initial import
[picodrive.git] / unzip / unzip.c
1 #include "unzip.h"\r
2 \r
3 #include <stdlib.h>\r
4 #include <string.h>\r
5 #include <ctype.h>\r
6 #include <assert.h>\r
7 \r
8 #ifdef __SYMBIAN32__\r
9 #include <ezlib.h>\r
10 #else\r
11 #include "zlib/zlib.h"\r
12 #endif\r
13 \r
14 /* public globals */\r
15 //int   gUnzipQuiet = 0;                /* flag controls error messages */\r
16 \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
20 \r
21 #define INFLATE_INPUT_BUFFER_MAX 16384\r
22 #ifndef MIN\r
23 #define MIN(x,y) ((x)<(y)?(x):(y))\r
24 #endif\r
25 \r
26 \r
27 // notaz\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
32 {\r
33         dprintf("Error in zipfile %s: %s", zipname, extmsg);\r
34 }\r
35 #else\r
36 #define logerror(x...)\r
37 #define errormsg(x...)\r
38 #endif\r
39 \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
48 //}\r
49 \r
50 /* -------------------------------------------------------------------------\r
51    Unzip support\r
52  ------------------------------------------------------------------------- */\r
53 \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
57 \r
58    return ((UINT16)ubuf[1] << 8) | (UINT16)ubuf[0];\r
59 }\r
60 \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
64 \r
65    return ((UINT32)ubuf[3] << 24) | ((UINT32)ubuf[2] << 16) | ((UINT32)ubuf[1] << 8) | (UINT32)ubuf[0];\r
66 }\r
67 \r
68 /* Locate end-of-central-dir sig in buffer and return offset\r
69    out:\r
70         *offset offset of cent dir start in buffer\r
71    return:\r
72         ==0 not found\r
73         !=0 found, *offset valid\r
74 */\r
75 static int ecd_find_sig (char *buffer, int buflen, int *offset)\r
76 {\r
77         static char ecdsig[] = { 'P', 'K', 0x05, 0x06 };\r
78         int i;\r
79         for (i=buflen-22; i>=0; i--) {\r
80                 if (memcmp(buffer+i, ecdsig, 4) == 0) {\r
81                         *offset = i;\r
82                         return 1;\r
83                 }\r
84         }\r
85         return 0;\r
86 }\r
87 \r
88 /* Read ecd data in zip structure\r
89    in:\r
90      zip->fp, zip->length zip file\r
91    out:\r
92      zip->ecd, zip->ecd_length ecd data\r
93 */\r
94 static int ecd_read(ZIP* zip) {\r
95         char* buf;\r
96         int buf_length = 1024; /* initial buffer length */\r
97 \r
98         while (1) {\r
99                 int offset;\r
100 \r
101                 if (buf_length > zip->length)\r
102                         buf_length = zip->length;\r
103 \r
104                 if (fseek(zip->fp, zip->length - buf_length, SEEK_SET) != 0) {\r
105                         return -1;\r
106                 }\r
107 \r
108                 /* allocate buffer */\r
109                 buf = (char*)malloc( buf_length );\r
110                 if (!buf) {\r
111                         return -1;\r
112                 }\r
113 \r
114                 if (fread( buf, buf_length, 1, zip->fp ) != 1) {\r
115                         free(buf);\r
116                         return -1;\r
117                 }\r
118 \r
119                 if (ecd_find_sig(buf, buf_length, &offset)) {\r
120                         zip->ecd_length = buf_length - offset;\r
121 \r
122                         zip->ecd = (char*)malloc( zip->ecd_length );\r
123                         if (!zip->ecd) {\r
124                                 free(buf);\r
125                                 return -1;\r
126                         }\r
127 \r
128                         memcpy(zip->ecd, buf + offset, zip->ecd_length);\r
129 \r
130                         free(buf);\r
131                         return 0;\r
132                 }\r
133 \r
134                 free(buf);\r
135 \r
136                 if (buf_length < zip->length) {\r
137                         /* double buffer */\r
138                         buf_length = 2*buf_length;\r
139 \r
140                         logerror("Retry reading of zip ecd for %d bytes\n",buf_length);\r
141 \r
142                 } else {\r
143                         return -1;\r
144                 }\r
145         }\r
146 }\r
147 \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
158 \r
159 /* offsets in central directory entry structure */\r
160 #define ZIPCENSIG       0x0\r
161 #define ZIPCVER         0x4\r
162 #define ZIPCOS          0x5\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
180 \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
194 \r
195 /* Opens a zip stream for reading\r
196    return:\r
197      !=0 success, zip stream\r
198      ==0 error\r
199 */\r
200 ZIP* openzip(const char* zipfile) {\r
201         /* allocate */\r
202         ZIP* zip = (ZIP*)malloc( sizeof(ZIP) );\r
203         if (!zip) {\r
204                 return 0;\r
205         }\r
206 \r
207         /* open */\r
208         zip->fp = fopen(zipfile, "rb");\r
209         if (!zip->fp) {\r
210                 errormsg ("Opening for reading", ERROR_FILESYSTEM, zipfile);\r
211                 free(zip);\r
212                 return 0;\r
213         }\r
214 \r
215         /* go to end */\r
216         if (fseek(zip->fp, 0L, SEEK_END) != 0) {\r
217                 errormsg ("Seeking to end", ERROR_FILESYSTEM, zipfile);\r
218                 fclose(zip->fp);\r
219                 free(zip);\r
220                 return 0;\r
221         }\r
222 \r
223         /* get length */\r
224         zip->length = ftell(zip->fp);\r
225         if (zip->length < 0) {\r
226                 errormsg ("Get file size", ERROR_FILESYSTEM, zipfile);\r
227                 fclose(zip->fp);\r
228                 free(zip);\r
229                 return 0;\r
230         }\r
231         if (zip->length == 0) {\r
232                 errormsg ("Empty file", ERROR_CORRUPT, zipfile);\r
233                 fclose(zip->fp);\r
234                 free(zip);\r
235                 return 0;\r
236         }\r
237 \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
241                 fclose(zip->fp);\r
242                 free(zip);\r
243                 return 0;\r
244         }\r
245 \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
256 \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
262                 free(zip->ecd);\r
263                 fclose(zip->fp);\r
264                 free(zip);\r
265                 return 0;\r
266         }\r
267 \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
270                 free(zip->ecd);\r
271                 fclose(zip->fp);\r
272                 free(zip);\r
273                 return 0;\r
274         }\r
275 \r
276         /* read from start of central directory */\r
277         zip->cd = (char*)malloc( zip->size_of_cent_dir );\r
278         if (!zip->cd) {\r
279                 free(zip->ecd);\r
280                 fclose(zip->fp);\r
281                 free(zip);\r
282                 return 0;\r
283         }\r
284 \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
287                 free(zip->cd);\r
288                 free(zip->ecd);\r
289                 fclose(zip->fp);\r
290                 free(zip);\r
291                 return 0;\r
292         }\r
293 \r
294         /* reset ent */\r
295         zip->ent.name = 0;\r
296 \r
297         /* rewind */\r
298         zip->cd_pos = 0;\r
299 \r
300         /* file name */\r
301         zip->zip = (char*)malloc(strlen(zipfile)+1);\r
302         if (!zip->zip) {\r
303                 free(zip->cd);\r
304                 free(zip->ecd);\r
305                 fclose(zip->fp);\r
306                 free(zip);\r
307                 return 0;\r
308         }\r
309         strcpy(zip->zip, zipfile);\r
310 \r
311         return zip;\r
312 }\r
313 \r
314 /* Reads the current entry from a zip stream\r
315    in:\r
316      zip opened zip\r
317    return:\r
318      !=0 success\r
319      ==0 error\r
320 */\r
321 struct zipent* readzip(ZIP* zip) {\r
322 \r
323         /* end of directory */\r
324         if (zip->cd_pos >= zip->size_of_cent_dir)\r
325                 return 0;\r
326 \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
347 \r
348     /* check to see if filename length is illegally long (past the size of this directory\r
349        entry) */\r
350     if (zip->cd_pos + ZIPCFN + zip->ent.filename_length > zip->size_of_cent_dir)\r
351     {\r
352         errormsg("Invalid filename length in directory", ERROR_CORRUPT,zip->zip);\r
353         return 0;\r
354     }\r
355 \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
361 \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
364 \r
365         return &zip->ent;\r
366 }\r
367 \r
368 /* Closes a zip stream */\r
369 void closezip(ZIP* zip) {\r
370         /* release all */\r
371         free(zip->ent.name);\r
372         free(zip->cd);\r
373         free(zip->ecd);\r
374         /* only if not suspended */\r
375         if (zip->fp)\r
376                 fclose(zip->fp);\r
377         free(zip->zip);\r
378         free(zip);\r
379 }\r
380 \r
381 /* Suspend access to a zip file (release file handler)\r
382    in:\r
383       zip opened zip\r
384    note:\r
385      A suspended zip is automatically reopened at first call of\r
386      readuncompressd() or readcompressed() functions\r
387 */\r
388 void suspendzip(ZIP* zip) {\r
389         if (zip->fp) {\r
390                 fclose(zip->fp);\r
391                 zip->fp = 0;\r
392         }\r
393 }\r
394 \r
395 /* Revive a suspended zip file (reopen file handler)\r
396    in:\r
397      zip suspended zip\r
398    return:\r
399         zip success\r
400         ==0 error (zip must be closed with closezip)\r
401 */\r
402 static ZIP* revivezip(ZIP* zip) {\r
403         if (!zip->fp) {\r
404                 zip->fp = fopen(zip->zip, "rb");\r
405                 if (!zip->fp) {\r
406                         return 0;\r
407                 }\r
408         }\r
409         return zip;\r
410 \r
411 }\r
412 \r
413 /* Reset a zip stream to the first entry\r
414    in:\r
415      zip opened zip\r
416    note:\r
417      ZIP file must be opened and not suspended\r
418 */\r
419 void rewindzip(ZIP* zip) {\r
420         zip->cd_pos = 0;\r
421 }\r
422 \r
423 /* Seek zip->fp to compressed data\r
424    return:\r
425         ==0 success\r
426         <0 error\r
427 */\r
428 int seekcompresszip(ZIP* zip, struct zipent* ent) {\r
429         char buf[ZIPNAME];\r
430         long offset;\r
431 \r
432         if (!zip->fp) {\r
433                 if (!revivezip(zip))\r
434                         return -1;\r
435         }\r
436 \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
439                 return -1;\r
440         }\r
441 \r
442         if (fread(buf, ZIPNAME, 1, zip->fp)!=1) {\r
443                 errormsg ("Reading header", ERROR_CORRUPT, zip->zip);\r
444                 return -1;\r
445         }\r
446 \r
447         {\r
448                 UINT16 filename_length = read_word (buf+ZIPFNLN);\r
449                 UINT16 extra_field_length = read_word (buf+ZIPXTRALN);\r
450 \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
453 \r
454                 if (fseek(zip->fp, offset, SEEK_SET) != 0) {\r
455                         errormsg ("Seeking to compressed data", ERROR_CORRUPT, zip->zip);\r
456                         return -1;\r
457                 }\r
458 \r
459         }\r
460 \r
461         return 0;\r
462 }\r
463 \r
464 /* Inflate a file\r
465    in:\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
469    out:\r
470    out_data buffer for decompressed data\r
471    return:\r
472    ==0 ok\r
473 \r
474    990525 rewritten for use with zlib MLR\r
475 */\r
476 static int inflate_file(FILE* in_file, unsigned in_size, unsigned char* out_data, unsigned out_size)\r
477 {\r
478     int err;\r
479         unsigned char* in_buffer;\r
480     z_stream d_stream; /* decompression stream */\r
481 \r
482     d_stream.zalloc = 0;\r
483     d_stream.zfree = 0;\r
484     d_stream.opaque = 0;\r
485 \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
490 \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
496          */\r
497     if (err != Z_OK)\r
498         {\r
499                 logerror("inflateInit error: %d\n", err);\r
500         return -1;\r
501         }\r
502 \r
503         in_buffer = (unsigned char*)malloc(INFLATE_INPUT_BUFFER_MAX+1);\r
504         if (!in_buffer)\r
505                 return -1;\r
506 \r
507     for (;;)\r
508         {\r
509                 if (in_size <= 0)\r
510                 {\r
511                         logerror("inflate error: compressed size too small\n");\r
512                         free (in_buffer);\r
513                         return -1;\r
514                 }\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
518                 if (in_size == 0)\r
519                         d_stream.avail_in++; /* add dummy byte at end of compressed data */\r
520 \r
521         err = inflate(&d_stream, Z_NO_FLUSH);\r
522         if (err == Z_STREAM_END)\r
523                         break;\r
524                 if (err != Z_OK)\r
525                 {\r
526                         logerror("inflate error: %d\n", err);\r
527                         free (in_buffer);\r
528                         return -1;\r
529                 }\r
530     }\r
531 \r
532     err = inflateEnd(&d_stream);\r
533         if (err != Z_OK)\r
534         {\r
535                 logerror("inflateEnd error: %d\n", err);\r
536                 free (in_buffer);\r
537                 return -1;\r
538         }\r
539 \r
540         free (in_buffer);\r
541 \r
542         if ((d_stream.avail_out > 0) || (in_size > 0))\r
543         {\r
544                 logerror("zip size mismatch. %i\n", in_size);\r
545                 return -1;\r
546         }\r
547 \r
548         return 0;\r
549 }\r
550 \r
551 /* Read compressed data\r
552    out:\r
553         data compressed data read\r
554    return:\r
555         ==0 success\r
556         <0 error\r
557 */\r
558 int readcompresszip(ZIP* zip, struct zipent* ent, char* data) {\r
559         int err = seekcompresszip(zip,ent);\r
560         if (err!=0)\r
561                 return err;\r
562 \r
563         if (fread(data, ent->compressed_size, 1, zip->fp)!=1) {\r
564                 errormsg ("Reading compressed data", ERROR_CORRUPT, zip->zip);\r
565                 return -1;\r
566         }\r
567 \r
568         return 0;\r
569 }\r
570 \r
571 /* Read UNcompressed data\r
572    out:\r
573         data UNcompressed data\r
574    return:\r
575         ==0 success\r
576         <0 error\r
577 */\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
581 \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
585                         return -3;\r
586                 }\r
587 \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
593                         return -2;\r
594                 }\r
595 \r
596                 if (ent->os_needed_to_extract != 0x00) {\r
597                         errormsg("OS not supported", ERROR_UNSUPPORTED,zip->zip);\r
598                         return -2;\r
599                 }\r
600 \r
601                 if (ent->disk_number_start != zip->number_of_this_disk) {\r
602                         errormsg("Cannot span disks", ERROR_UNSUPPORTED,zip->zip);\r
603                         return -2;\r
604                 }\r
605 \r
606                 /* read compressed data */\r
607                 if (seekcompresszip(zip,ent)!=0) {\r
608                         return -1;\r
609                 }\r
610 \r
611                 /* configure inflate */\r
612                 if (inflate_file( zip->fp, ent->compressed_size, (unsigned char*)data, ent->uncompressed_size))\r
613                 {\r
614                         errormsg("Inflating compressed data", ERROR_CORRUPT, zip->zip);\r
615                         return -3;\r
616                 }\r
617 \r
618                 return 0;\r
619         } else {\r
620                 errormsg("Compression method unsupported", ERROR_UNSUPPORTED, zip->zip);\r
621                 return -2;\r
622         }\r
623 }\r