11 #include "zlib/zlib.h"
\r
14 /* public globals */
\r
15 //int gUnzipQuiet = 0; /* flag controls error messages */
\r
17 #define ERROR_CORRUPT "The zipfile seems to be corrupt, please check it"
\r
18 #define ERROR_FILESYSTEM "Your filesystem seems to be corrupt, please check it"
\r
19 #define ERROR_UNSUPPORTED "The format of this zipfile is not supported, please recompress it"
\r
21 #define INFLATE_INPUT_BUFFER_MAX 16384
\r
23 #define MIN(x,y) ((x)<(y)?(x):(y))
\r
28 #ifdef __DEBUG_PRINT
\r
29 void dprintf(char *format, ...);
\r
30 #define logerror dprintf
\r
31 void errormsg(const char* extmsg, const char* usermsg, const char* zipname)
\r
33 dprintf("Error in zipfile %s: %s", zipname, extmsg);
\r
36 #define logerror(x...)
\r
37 #define errormsg(x...)
\r
40 /* Print a error message */
\r
41 //void errormsg(const char* extmsg, const char* usermsg, const char* zipname) {
\r
42 /* Output to the user with no internal detail */
\r
43 // if (!gUnzipQuiet)
\r
44 // printf("Error in zipfile %s\n%s\n", zipname, usermsg);
\r
45 /* Output to log file with all informations */
\r
46 // logerror("Error in zipfile %s: %s\n", zipname, extmsg);
\r
47 // printf("Error in zipfile %s: %s\n", zipname, extmsg);
\r
50 /* -------------------------------------------------------------------------
\r
52 ------------------------------------------------------------------------- */
\r
54 /* Use these to avoid structure padding and byte-ordering problems */
\r
55 static UINT16 read_word (char *buf) {
\r
56 unsigned char *ubuf = (unsigned char *) buf;
\r
58 return ((UINT16)ubuf[1] << 8) | (UINT16)ubuf[0];
\r
61 /* Use these to avoid structure padding and byte-ordering problems */
\r
62 static UINT32 read_dword (char *buf) {
\r
63 unsigned char *ubuf = (unsigned char *) buf;
\r
65 return ((UINT32)ubuf[3] << 24) | ((UINT32)ubuf[2] << 16) | ((UINT32)ubuf[1] << 8) | (UINT32)ubuf[0];
\r
68 /* Locate end-of-central-dir sig in buffer and return offset
\r
70 *offset offset of cent dir start in buffer
\r
73 !=0 found, *offset valid
\r
75 static int ecd_find_sig (char *buffer, int buflen, int *offset)
\r
77 static char ecdsig[] = { 'P', 'K', 0x05, 0x06 };
\r
79 for (i=buflen-22; i>=0; i--) {
\r
80 if (memcmp(buffer+i, ecdsig, 4) == 0) {
\r
88 /* Read ecd data in zip structure
\r
90 zip->fp, zip->length zip file
\r
92 zip->ecd, zip->ecd_length ecd data
\r
94 static int ecd_read(ZIP* zip) {
\r
96 int buf_length = 1024; /* initial buffer length */
\r
101 if (buf_length > zip->length)
\r
102 buf_length = zip->length;
\r
104 if (fseek(zip->fp, zip->length - buf_length, SEEK_SET) != 0) {
\r
108 /* allocate buffer */
\r
109 buf = (char*)malloc( buf_length );
\r
114 if (fread( buf, buf_length, 1, zip->fp ) != 1) {
\r
119 if (ecd_find_sig(buf, buf_length, &offset)) {
\r
120 zip->ecd_length = buf_length - offset;
\r
122 zip->ecd = (char*)malloc( zip->ecd_length );
\r
128 memcpy(zip->ecd, buf + offset, zip->ecd_length);
\r
136 if (buf_length < zip->length) {
\r
137 /* double buffer */
\r
138 buf_length = 2*buf_length;
\r
140 logerror("Retry reading of zip ecd for %d bytes\n",buf_length);
\r
148 /* offsets in end of central directory structure */
\r
149 #define ZIPESIG 0x00
\r
150 #define ZIPEDSK 0x04
\r
151 #define ZIPECEN 0x06
\r
152 #define ZIPENUM 0x08
\r
153 #define ZIPECENN 0x0a
\r
154 #define ZIPECSZ 0x0c
\r
155 #define ZIPEOFST 0x10
\r
156 #define ZIPECOML 0x14
\r
157 #define ZIPECOM 0x16
\r
159 /* offsets in central directory entry structure */
\r
160 #define ZIPCENSIG 0x0
\r
161 #define ZIPCVER 0x4
\r
163 #define ZIPCVXT 0x6
\r
164 #define ZIPCEXOS 0x7
\r
165 #define ZIPCFLG 0x8
\r
166 #define ZIPCMTHD 0xa
\r
167 #define ZIPCTIM 0xc
\r
168 #define ZIPCDAT 0xe
\r
169 #define ZIPCCRC 0x10
\r
170 #define ZIPCSIZ 0x14
\r
171 #define ZIPCUNC 0x18
\r
172 #define ZIPCFNL 0x1c
\r
173 #define ZIPCXTL 0x1e
\r
174 #define ZIPCCML 0x20
\r
175 #define ZIPDSK 0x22
\r
176 #define ZIPINT 0x24
\r
177 #define ZIPEXT 0x26
\r
178 #define ZIPOFST 0x2a
\r
179 #define ZIPCFN 0x2e
\r
181 /* offsets in local file header structure */
\r
182 #define ZIPLOCSIG 0x00
\r
183 #define ZIPVER 0x04
\r
184 #define ZIPGENFLG 0x06
\r
185 #define ZIPMTHD 0x08
\r
186 #define ZIPTIME 0x0a
\r
187 #define ZIPDATE 0x0c
\r
188 #define ZIPCRC 0x0e
\r
189 #define ZIPSIZE 0x12
\r
190 #define ZIPUNCMP 0x16
\r
191 #define ZIPFNLN 0x1a
\r
192 #define ZIPXTRALN 0x1c
\r
193 #define ZIPNAME 0x1e
\r
195 /* Opens a zip stream for reading
\r
197 !=0 success, zip stream
\r
200 ZIP* openzip(const char* zipfile) {
\r
202 ZIP* zip = (ZIP*)malloc( sizeof(ZIP) );
\r
208 zip->fp = fopen(zipfile, "rb");
\r
210 errormsg ("Opening for reading", ERROR_FILESYSTEM, zipfile);
\r
216 if (fseek(zip->fp, 0L, SEEK_END) != 0) {
\r
217 errormsg ("Seeking to end", ERROR_FILESYSTEM, zipfile);
\r
224 zip->length = ftell(zip->fp);
\r
225 if (zip->length < 0) {
\r
226 errormsg ("Get file size", ERROR_FILESYSTEM, zipfile);
\r
231 if (zip->length == 0) {
\r
232 errormsg ("Empty file", ERROR_CORRUPT, zipfile);
\r
238 /* read ecd data */
\r
239 if (ecd_read(zip)!=0) {
\r
240 errormsg ("Reading ECD (end of central directory)", ERROR_CORRUPT, zipfile);
\r
246 /* compile ecd info */
\r
247 zip->end_of_cent_dir_sig = read_dword (zip->ecd+ZIPESIG);
\r
248 zip->number_of_this_disk = read_word (zip->ecd+ZIPEDSK);
\r
249 zip->number_of_disk_start_cent_dir = read_word (zip->ecd+ZIPECEN);
\r
250 zip->total_entries_cent_dir_this_disk = read_word (zip->ecd+ZIPENUM);
\r
251 zip->total_entries_cent_dir = read_word (zip->ecd+ZIPECENN);
\r
252 zip->size_of_cent_dir = read_dword (zip->ecd+ZIPECSZ);
\r
253 zip->offset_to_start_of_cent_dir = read_dword (zip->ecd+ZIPEOFST);
\r
254 zip->zipfile_comment_length = read_word (zip->ecd+ZIPECOML);
\r
255 zip->zipfile_comment = zip->ecd+ZIPECOM;
\r
257 /* verify that we can work with this zipfile (no disk spanning allowed) */
\r
258 if ((zip->number_of_this_disk != zip->number_of_disk_start_cent_dir) ||
\r
259 (zip->total_entries_cent_dir_this_disk != zip->total_entries_cent_dir) ||
\r
260 (zip->total_entries_cent_dir < 1)) {
\r
261 errormsg("Cannot span disks", ERROR_UNSUPPORTED, zipfile);
\r
268 if (fseek(zip->fp, zip->offset_to_start_of_cent_dir, SEEK_SET)!=0) {
\r
269 errormsg ("Seeking to central directory", ERROR_CORRUPT, zipfile);
\r
276 /* read from start of central directory */
\r
277 zip->cd = (char*)malloc( zip->size_of_cent_dir );
\r
285 if (fread(zip->cd, zip->size_of_cent_dir, 1, zip->fp)!=1) {
\r
286 errormsg ("Reading central directory", ERROR_CORRUPT, zipfile);
\r
301 zip->zip = (char*)malloc(strlen(zipfile)+1);
\r
309 strcpy(zip->zip, zipfile);
\r
314 /* Reads the current entry from a zip stream
\r
321 struct zipent* readzip(ZIP* zip) {
\r
323 /* end of directory */
\r
324 if (zip->cd_pos >= zip->size_of_cent_dir)
\r
327 /* compile zipent info */
\r
328 zip->ent.cent_file_header_sig = read_dword (zip->cd+zip->cd_pos+ZIPCENSIG);
\r
329 zip->ent.version_made_by = *(zip->cd+zip->cd_pos+ZIPCVER);
\r
330 zip->ent.host_os = *(zip->cd+zip->cd_pos+ZIPCOS);
\r
331 zip->ent.version_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCVXT);
\r
332 zip->ent.os_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCEXOS);
\r
333 zip->ent.general_purpose_bit_flag = read_word (zip->cd+zip->cd_pos+ZIPCFLG);
\r
334 zip->ent.compression_method = read_word (zip->cd+zip->cd_pos+ZIPCMTHD);
\r
335 zip->ent.last_mod_file_time = read_word (zip->cd+zip->cd_pos+ZIPCTIM);
\r
336 zip->ent.last_mod_file_date = read_word (zip->cd+zip->cd_pos+ZIPCDAT);
\r
337 zip->ent.crc32 = read_dword (zip->cd+zip->cd_pos+ZIPCCRC);
\r
338 zip->ent.compressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCSIZ);
\r
339 zip->ent.uncompressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCUNC);
\r
340 zip->ent.filename_length = read_word (zip->cd+zip->cd_pos+ZIPCFNL);
\r
341 zip->ent.extra_field_length = read_word (zip->cd+zip->cd_pos+ZIPCXTL);
\r
342 zip->ent.file_comment_length = read_word (zip->cd+zip->cd_pos+ZIPCCML);
\r
343 zip->ent.disk_number_start = read_word (zip->cd+zip->cd_pos+ZIPDSK);
\r
344 zip->ent.internal_file_attrib = read_word (zip->cd+zip->cd_pos+ZIPINT);
\r
345 zip->ent.external_file_attrib = read_dword (zip->cd+zip->cd_pos+ZIPEXT);
\r
346 zip->ent.offset_lcl_hdr_frm_frst_disk = read_dword (zip->cd+zip->cd_pos+ZIPOFST);
\r
348 /* check to see if filename length is illegally long (past the size of this directory
\r
350 if (zip->cd_pos + ZIPCFN + zip->ent.filename_length > zip->size_of_cent_dir)
\r
352 errormsg("Invalid filename length in directory", ERROR_CORRUPT,zip->zip);
\r
356 /* copy filename */
\r
357 free(zip->ent.name);
\r
358 zip->ent.name = (char*)malloc(zip->ent.filename_length + 1);
\r
359 memcpy(zip->ent.name, zip->cd+zip->cd_pos+ZIPCFN, zip->ent.filename_length);
\r
360 zip->ent.name[zip->ent.filename_length] = 0;
\r
362 /* skip to next entry in central dir */
\r
363 zip->cd_pos += ZIPCFN + zip->ent.filename_length + zip->ent.extra_field_length + zip->ent.file_comment_length;
\r
368 /* Closes a zip stream */
\r
369 void closezip(ZIP* zip) {
\r
371 free(zip->ent.name);
\r
374 /* only if not suspended */
\r
381 /* Suspend access to a zip file (release file handler)
\r
385 A suspended zip is automatically reopened at first call of
\r
386 readuncompressd() or readcompressed() functions
\r
388 void suspendzip(ZIP* zip) {
\r
395 /* Revive a suspended zip file (reopen file handler)
\r
400 ==0 error (zip must be closed with closezip)
\r
402 static ZIP* revivezip(ZIP* zip) {
\r
404 zip->fp = fopen(zip->zip, "rb");
\r
413 /* Reset a zip stream to the first entry
\r
417 ZIP file must be opened and not suspended
\r
419 void rewindzip(ZIP* zip) {
\r
423 /* Seek zip->fp to compressed data
\r
428 int seekcompresszip(ZIP* zip, struct zipent* ent) {
\r
433 if (!revivezip(zip))
\r
437 if (fseek(zip->fp, ent->offset_lcl_hdr_frm_frst_disk, SEEK_SET)!=0) {
\r
438 errormsg ("Seeking to header", ERROR_CORRUPT, zip->zip);
\r
442 if (fread(buf, ZIPNAME, 1, zip->fp)!=1) {
\r
443 errormsg ("Reading header", ERROR_CORRUPT, zip->zip);
\r
448 UINT16 filename_length = read_word (buf+ZIPFNLN);
\r
449 UINT16 extra_field_length = read_word (buf+ZIPXTRALN);
\r
451 /* calculate offset to data and fseek() there */
\r
452 offset = ent->offset_lcl_hdr_frm_frst_disk + ZIPNAME + filename_length + extra_field_length;
\r
454 if (fseek(zip->fp, offset, SEEK_SET) != 0) {
\r
455 errormsg ("Seeking to compressed data", ERROR_CORRUPT, zip->zip);
\r
466 in_file stream to inflate
\r
467 in_size size of the compressed data to read
\r
468 out_size size of decompressed data
\r
470 out_data buffer for decompressed data
\r
474 990525 rewritten for use with zlib MLR
\r
476 static int inflate_file(FILE* in_file, unsigned in_size, unsigned char* out_data, unsigned out_size)
\r
479 unsigned char* in_buffer;
\r
480 z_stream d_stream; /* decompression stream */
\r
482 d_stream.zalloc = 0;
\r
483 d_stream.zfree = 0;
\r
484 d_stream.opaque = 0;
\r
486 d_stream.next_in = 0;
\r
487 d_stream.avail_in = 0;
\r
488 d_stream.next_out = out_data;
\r
489 d_stream.avail_out = out_size;
\r
491 err = inflateInit2(&d_stream, -MAX_WBITS);
\r
492 /* windowBits is passed < 0 to tell that there is no zlib header.
\r
493 * Note that in this case inflate *requires* an extra "dummy" byte
\r
494 * after the compressed stream in order to complete decompression and
\r
495 * return Z_STREAM_END.
\r
499 logerror("inflateInit error: %d\n", err);
\r
503 in_buffer = (unsigned char*)malloc(INFLATE_INPUT_BUFFER_MAX+1);
\r
511 logerror("inflate error: compressed size too small\n");
\r
515 d_stream.next_in = in_buffer;
\r
516 d_stream.avail_in = fread (in_buffer, 1, MIN(in_size, INFLATE_INPUT_BUFFER_MAX), in_file);
\r
517 in_size -= d_stream.avail_in;
\r
519 d_stream.avail_in++; /* add dummy byte at end of compressed data */
\r
521 err = inflate(&d_stream, Z_NO_FLUSH);
\r
522 if (err == Z_STREAM_END)
\r
526 logerror("inflate error: %d\n", err);
\r
532 err = inflateEnd(&d_stream);
\r
535 logerror("inflateEnd error: %d\n", err);
\r
542 if ((d_stream.avail_out > 0) || (in_size > 0))
\r
544 logerror("zip size mismatch. %i\n", in_size);
\r
551 /* Read compressed data
\r
553 data compressed data read
\r
558 int readcompresszip(ZIP* zip, struct zipent* ent, char* data) {
\r
559 int err = seekcompresszip(zip,ent);
\r
563 if (fread(data, ent->compressed_size, 1, zip->fp)!=1) {
\r
564 errormsg ("Reading compressed data", ERROR_CORRUPT, zip->zip);
\r
571 /* Read UNcompressed data
\r
573 data UNcompressed data
\r
578 int readuncompresszip(ZIP* zip, struct zipent* ent, char* data) {
\r
579 if (ent->compression_method == 0x0000) {
\r
580 /* file is not compressed, simply stored */
\r
582 /* check if size are equal */
\r
583 if (ent->compressed_size != ent->uncompressed_size) {
\r
584 errormsg("Wrong uncompressed size in store compression", ERROR_CORRUPT,zip->zip);
\r
588 return readcompresszip(zip,ent,data);
\r
589 } else if (ent->compression_method == 0x0008) {
\r
590 /* file is compressed using "Deflate" method */
\r
591 if (ent->version_needed_to_extract > 0x14) {
\r
592 errormsg("Version too new", ERROR_UNSUPPORTED,zip->zip);
\r
596 if (ent->os_needed_to_extract != 0x00) {
\r
597 errormsg("OS not supported", ERROR_UNSUPPORTED,zip->zip);
\r
601 if (ent->disk_number_start != zip->number_of_this_disk) {
\r
602 errormsg("Cannot span disks", ERROR_UNSUPPORTED,zip->zip);
\r
606 /* read compressed data */
\r
607 if (seekcompresszip(zip,ent)!=0) {
\r
611 /* configure inflate */
\r
612 if (inflate_file( zip->fp, ent->compressed_size, (unsigned char*)data, ent->uncompressed_size))
\r
614 errormsg("Inflating compressed data", ERROR_CORRUPT, zip->zip);
\r
620 errormsg("Compression method unsupported", ERROR_UNSUPPORTED, zip->zip);
\r