[C con Clase] Duda con función que retorna un puntero a una estructura que no está funciona

Personal santiago230792 en gmail.com
Lun Dic 18 09:06:52 CET 2017


Estimados docentes de C con Clase:

Estuve un tiempo sin seguir con las prácticas del curso de C++ y
recientemente regresé luego de hacerme un tiempo. Para hacer algo más
real, decidí comenzar un proyecto más "real" y práctico, para lo cual
elegí crear una pequeña biblioteca para leer un formato de archivo que
no sé si tiene una implementación de código abierto como tal, de forma
que se pudiera reutilizar de forma libre
(y con licencia libre) para que otras aplicaciones pudieran importar
datos de este formato, etc.  Mi idea era la de crear una biblioteca
independiente de la plataforma y dentro de lo posible, sin dependencias
adicionales, solo requiriendo al menos una versión reciente de las
bibliotecas de C, y al mismo tiempo seguir aprendiendo en el camino.
Aclaro que estoy programándola en C para que sea útil tanto en C como en
C++.

El formato de archivo es el de CARDFILE, una aplicación del antiguo
Windows 3.11. El formato de archivo no ha sido del todo bien
documentado, pero algunas especificaciones están en:
*
https://support.microsoft.com/en-us/help/99340/windows-3-1-card-file-format
* http://donaldkenney.x10.mx/CARDFILE.HTM#MGC
*
https://groups.google.com/forum/#!searchin/comp.windows.ms/cardfile;context-place=forum/comp.windows.ms
* https://en.wikipedia.org/wiki/Cardfile

Este formato es un archivo binario de extensión CRD con tres versiones,
que se las puede identificar por sus números mágicos: MGC, RRG y DKO. El
primero fue el formato inicial, el segundo añadió soporte para objetos
OLE (que se pueden manipular mediante el API de Windows) y el tercero
habría añadido soporte para Unicode 16 bits.

De forma gráfica, se trata de un archivo que contiene tarjetas o cards,
en las que se puede guardar información personal al estilo de un
fichero,  conteniendo varias tarjetas con texto, mapas de bits, objetos
OLE cada una.

Un archivo CRD se caracteriza por contener tres bloques: (1) un
encabezado o header, (2) un índice o index, y (3) los datos de las
tarjetas señaladas en el índice.
-------
(1) El encabezado se caracteriza por contener dos o tres sub-bloques
dependiendo de la implementación, con al menos un "número mágico" y un
"número de cartas".

(a) El del formato MGC es así:
[número mágico (3 bytes)="MGC"] [número de tarjetas (2 bytes, little
endian)] = 5 bytes

(b) Los formatos RRG y DKO serían así:
[número mágico (3 bytes)="RRG" o "DKO"] [último id de objeto (4 bytes,
little endian)][número de tarjetas (2 bytes, en little endian)] = 9 bytes

Al "ultimo id de objeto" no le veo demasiada utilidad por el momento. El
numero de
tarjetas sí es un dato importante para acceder al resto del archivo.
-----
(2) El índice comienza una vez termina el encabezado, la distribución de
bytes es común a todos los formatos de CRD, y puede repetirse la misma
estructura tantas veces como tarjetas haya en el archivo:

(a) [reservado (6 bytes)= 0x000000]
(b) [posición en el archivo de los datos asociados a esta entrada de
índice (4 bytes)]
(c) [flag inicial (1 byte) = 0x00]
(d) [título del índice de la tarjeta (40 bytes) = cadena de texto]
(e) [flag final  (1 byte) = 0x00]

Por ejemplo, si hay dos tarjetas, tendríamos:
[[ENCABEZADO:...]]
[[ÍNDICE:
 [reserv.] [pos. datos 1=0x39] [flag] [titulo indice 1] [flag final]
 [reserv.] [pos. datos 2=0xnn] [flag] [titulo indice 2] [flag final]
]]
[[DATOS:
  0x39->...
  0xnn->...
]]

-----
(3) La sección de datos es más compleja y su implementación depende de la
versión de archivo CRD. La más simple es la de los MGC, con la cual
estaba empezando a trabajar.

Más o menos se compone así para los MGC:

(a) [Tamaño de objeto bmp en little endian] 0x0000 (no hay objeto) u otro
valor si hay uno, del peso indicado, en little endian
(b) [OPCIONAL-objeto:
         (b.1) [ancho=2 bytes]
         (b.2) [alto=2 bytes]
         (b.3) [x=2 bytes]
         (b.4) [y=2 bytes]
         (b.5) [datos (tamaño en bytes indicado en "(a)" )]
(c) [Tamaño de texto=2 bytes little endian]
(d) [Texto=440 bytes]

En los RRG es así
(a) [Flag de objeto bmp en little endian] 0x0000 (no hay objeto) o
0x0001 (hay un objeto) en little endian
(b) [OPCIONAL-Muchos flags del objeto OLE que no enumeraré aquí...]
(c) [Tamaño de texto]
(d) [Texto=440 bytes]
---------------------

En cuanto a la implementación, recién estaba empezando, y estaba
haciendo una función que retornaba un puntero a una estructura del
índice para poder obtener los datos del índice, es decir, el título del
índice y la ubicación de los datos dentro del archivo:

PINDEX LoadCardNumberInfo (FILE *fileptr, int card_number);

PINDEX es un puntero a la estructura que hace referencia a la sección
índice del archivo.

Pero por alguna razón la función no está trabajando como debería y me da
un error al ejecutar. He intentado detectar con el depurador cómo
modificar este comportamiento, pero no tuve éxito.

La función trabaja de esta forma:

1. Externamente se abre el archivo. Dentro de la función se declara una
instancia del puntero a la estructura del índice.
2. Consulta la versión de archivo CRD para determinar cuánto debe
moverse el "cursor" con fseek, o retorna un puntero nulo en caso de ser
un tipo de archivo desconocido. Esto se debe a que como ya expliqué más
arriba, el índice comienza en posiciones distintas si se trata de un
MGC, o en otro caso, de los RRG y DKO.
3. Reserva memoria dinámica en caso de que (2) no haya tenido error.
4. Se mueve a la posición indicada en (2).
5. Abre un bucle for para recorrer secuencialmente la sección de índices:
    a. Evita el campo de 6 bytes reservados, que no nos es útil, hasta
el comienzo del campo de <posición datos>.
    b. Lee <posición datos> y lo convierte a big endian para poder
trabajar con él. Si no lo hice mal, este dato se guarda dentro de la
instancia de la estructura. No sé si en realidad debería guardar el dato
en una variable temporal.
    c. Evita el flag de comienzo del texto de la entrada de índice.
    d. Lee el texto del índice. De nuevo, no sé si no lo hice mal, este
dato se guarda dentro de la instancia de la estructura. No sé si en
realidad debería guardar el dato en una variable temporal.
    e. Evita el flag de cierre del texto de la entrada del índice, y se
repite el bucle hasta llegado el número de índice indicado.
6. Se mueve el cursor al principio del archivo y libera memoria (si
corresponde).
7. Retorna un puntero a la estructura con los datos recogidos, para
trabajar de forma externa a la función.

¿Podría Ud. ver el código y  ver en qué falla mi implementación, que
luego de haberlo analizado no logro encontrar una respuesta?

Adjunto en caso de ser necesario el código fuente actual y unos archivos
de ejemplo para probar en la línea de comandos con una implementación de
un programa de ejemplo que utiliza la biblioteca como base. Para leer
los datos binarios de los archivos CRD utilicé el editor hexadecimal
FRHED, aunque supongo que cualquier otro similar será igualmente útil.

Muchas gracias.
Saludos
------------ próxima parte ------------
A non-text attachment was scrubbed...
Name: libcardfile.zip
Type: application/x-zip-compressed
Size: 20853 bytes
Desc: no disponible
URL: <http://listas.conclase.net/pipermail/cconclase_listas.conclase.net/attachments/20171218/7d983164/attachment.bin>


Más información sobre la lista de distribución Cconclase