Newsgroup: it.comp.lang.c
Titolo: Dati letti da file zip in una struct non corrispondono, perchè ?

Ciao,
spero di non essere OT nel qual caso chiedo scusa. Devo leggere la
struttura di un file zip. Tale file zip è cosi  ( ne riporto parte ):
[gt@Paradise Stuff2]$ hexdump -C zip_senza_con.zip |head
00000000  50 4b 03 04 14 00 00 00  08 00 57 8f e2 2e 71 65
|PK........W...qe|
00000010  e8 fc 4b 01 00 00 ec 01  00 00 15 00 15 00 53 65
|..K...........Se|
00000020  71 75 65 6e 63 65 46 72  61 6d 65 24 31 2e 63 6c
|quenceFrame$
1.cl
|
00000030  61 73 73 55 54 09 00 03  c6 7f 03 3f 38 c6 74 43
|assUT......?8.tC|
00000040  55 78 04 00 e8 03 64 00  6d 90 6d 4b 02 41 10 c7
|Ux....d.m.mK.A..|
00000050  ff eb a9 d7 5d 67 d6 55  f4 64 14 61 a0 46 59 af
|....]g.U.d.a.FY.|
00000060  8b a0 2e 83 40 7a 63 18  f4 ee cc 25 37 74 cf ee
|....@zc....%7t..|
00000070  56 a5 8f 15 f4 00 bd e8  03 f4 a1 a2 d9 45 0a a3
|V............E..|
00000080  85 dd 99 d9 f9 cd fc 67  f7 f3 eb fd 03 16 76 b1
|.......g......v.|
00000090  ee 22 83 39 07 69 f8 2e  e6 b1 60 63 d1 c6 32 43
|.".9.i....`c..2C
L'output delle quattro righe che ho buttato giù:
[gt@Paradise Stuff2]$ ./zip_detect
signature 4034b50
version 14
general flag 0
method 8
last file time 8f57
last filedate 2ee2
crc 14bfce8
compressed size 1ec0000
uncompressed size 150000
Dal crc in poi alcuni campi sono sballati. Il CRC è fce87165 come
risulta dall'output sotto:
[gt@Paradise Stuff2]$ unzip -vl zip_senza_con.zip |head
Archive:  zip_senza_con.zip
 Length   Method    Size  Ratio   Date   Time   CRC-32    Name
--------  ------  ------- -----   ----   ----   ------    ----
     492  Defl:N      331  33%  07-02-03 17:58  fce86571
SequenceFrame$1.class
  365845  Defl:N   352938   4%  04-27-05 05:03  6b1fd309
secure_webserver.pdf
--------          -------  ---                            -------
  366337           353269   4%                            2 files
Questo il programmino che ho usato:
#include <stdio.h>
#include <errno.h>
struct
{
    unsigned int sig;
    unsigned short int ver;
    unsigned short int flag;
    unsigned short int method;
    unsigned short int time;
    unsigned short int date;
    unsigned int crc;
    unsigned int comp_size;
    unsigned int uncomp_size;
    unsigned short int file_length;
    unsigned short int extra_length;
    unsigned short filename;
    unsigned short extra_field;
} my_struct;
FILE *fd;
int main (int argc,char *argv[])
{
    fd = fopen ("zip_senza_con.zip","r");
    if (fd == NULL)
    {
        printf ("%s\n",strerror(errno));
        return 0;
    }
    fread ( &my_struct, 1, sizeof(my_struct), fd );
    printf ("signature %x\n",my_struct.sig);
    printf ("version %x\n",my_struct.ver);
    printf ("general flag %x\n",my_struct.flag);
    printf ("method %x\n",my_struct.method);
    printf ("last file time %x\n",my_struct.time);
    printf ("last filedate %x\n",my_struct.date);
    printf ("crc %x\n",my_struct.crc);
    printf ("compressed size %x\n",my_struct.comp_size);
    printf ("uncompressed size %x\n",my_struct.uncomp_size);
}
Perchè i valori si sballano ?
Colossus

Quando leggi una struttura da un file, devi SEMPRE assicurarti
che il file sia aperto in modalità binaria. Ovvero, come secondo
parametro di fopen passa la stringa "rb". Se neanche in questo
modo dovesse funzionare, ricontrolla la specifica dell'header
dei file zip (
www.wotsit.org
) e fai attenzione alla dimensione delle
variabili.

 Perchè i valori si sballano ?
Non ho il tempo di mettermi a controllare byte per byte,
ma in questi casi di solito il problema e' questo:
Il compilatore, a meno che tu non lo forzi con delle
direttive di compilazione apposite (che quindi limitano
la portabilita' e che comunque su due piedi non mi ricordo)
puo' decidere, per migliorare le prestazioni,
di allineare i dati rispetto, ad esempio, di multipli di 4 bytes.
E potrebbe anche cambiare l'ordine dei campi, penso.
Nel tuo caso direi che nella struct hai 5 campi da 2 byte (short int),
e questo gli puo' anche stare bene, ma poi hai un campo
intero da 4 che verrebbe disallineato (a causa del numero dispari
di campi da 2 che lo precedono) e quindi lui potrebbe
aggiungere un campo da 2 byte vuoto e invisibile in modo
che i campi interi sucessivi siano allineati al boundary dei 4 bytes.
Oppure potrebbe cambiare l'ordine dei campi in modo
da mettere insieme tutti quelli da 2 bytes.
Quindi quando vai a leggere  alcuni bytes 2 di questi "spariscono"
perche' vengono memorizzati in quel campo invisibile di riempimento,
oppure potrebbero andare a trovarsi nella campo sbagliato
o entrambe le cose.
Ovviamente puoi risolvere leggendo tu a manina i vari
campi uno alla volta in apposite variabili, invece di buttarli tutti in 
un record.
ciao,
g.

 che il file sia aperto in modalità binaria.
Non e' necessariamente vero.
Se lui usa linux, come sembra di capire, non c'e' distinzione tra
file binari e file text (distinzione che invece c'e' su Windows ed
e' causa effettivamente di un sacco di messaggi su questo gruppo...).
ciao,
g.

 e' causa effettivamente di un sacco di messaggi su questo gruppo...).
Infatti la man page di fopen dice di usare solo r per aprire un file.
Colossus

 ciao,
Oltre a questo non c'è altra soluzione ?
Grazie mille sei molto gentile e competente.
--
Colossus
Xarchiver, a GTK2 only archive manager -
http://xarchiver.sourceforge.net
Cpsed, a Linux OpenGL 3D scene editor - 
http://cpsed.sourceforge.net
Mizio, a QT proxy hunter scanner tool - 
http://mizio.sourceforge.net

 parametro di fopen passa la stringa "rb".
Ti ringrazio della risposta ma io programmo solo su Linux, dove non
c'è distinzione tra r e rb come su Windows.


 parametro di fopen passa la stringa "rb".
Vale solo su quei sistemi (tipicamente DOS/Windows) in cui c'è 
distinzione tra file binari e non.  Su tutti gli *nix questa 
distinzione (intelligentemente) non esiste.

 Oltre a questo non c'è altra soluzione ?
mi sembra esistano delle opzioni di compilazione per forzare
l'allineamento "come lo vuoi tu".
Devi vedere il man gcc e cercare parole che contengano,
per esempio le parole align (quindi aligned, alignement, etc.)
e structs e  packed e padded che sono direi le parole chiave che
ti interessano.
Poi nel manuale del gcc in linea (non il man) ma magari
info gcc
dovresti trovare anche quelle cose che invece che sulla
linea di comando vanno ficcate nel file, tipo "pragma" o attributi
vari, con le quali dovresti poter
forzare l'allineamento come ti pare ed evitare
padding.
puoi anche cercare con google....
Io in ogni caso, visto il numero irrisorio di campi da
leggere, farei a mano.
Magari ti definisci alcune funzioni, una
per i short e una per gli int, alle quali passi lo stream
e che ti leggono il giusto numero di byte.
E dopo devi solo fare una cosa tipo:
my_struct.sig = LeggiI(fd);
my_struct.ver = LeggiS(fd);
etc.etc.
ciao,
g.

 my_struct.ver = LeggiS(fd);
ottima idea, grazie mille.
