support for zipped ISOs
[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 #if 1 //def __DEBUG_PRINT\r
29 #define logerror printf\r
30 #define errormsg(str1,def,fname) printf("%s: " #def ": " str1 "\n", fname);\r
31 #else\r
32 #define logerror(x...)\r
33 #define errormsg(x...)\r
34 #endif\r
35 \r
36 /* Print a error message */\r
37 //void errormsg(const char* extmsg, const char* usermsg, const char* zipname) {\r
38         /* Output to the user with no internal detail */\r
39 //      if (!gUnzipQuiet)\r
40 //              printf("Error in zipfile %s\n%s\n", zipname, usermsg);\r
41         /* Output to log file with all informations */\r
42 //      logerror("Error in zipfile %s: %s\n", zipname, extmsg);\r
43 //      printf("Error in zipfile %s: %s\n", zipname, extmsg);\r
44 //}\r
45 \r
46 /* -------------------------------------------------------------------------\r
47    Unzip support\r
48  ------------------------------------------------------------------------- */\r
49 \r
50 /* Use these to avoid structure padding and byte-ordering problems */\r
51 static UINT16 read_word (char *buf) {\r
52    unsigned char *ubuf = (unsigned char *) buf;\r
53 \r
54    return ((UINT16)ubuf[1] << 8) | (UINT16)ubuf[0];\r
55 }\r
56 \r
57 /* Use these to avoid structure padding and byte-ordering problems */\r
58 static UINT32 read_dword (char *buf) {\r
59    unsigned char *ubuf = (unsigned char *) buf;\r
60 \r
61    return ((UINT32)ubuf[3] << 24) | ((UINT32)ubuf[2] << 16) | ((UINT32)ubuf[1] << 8) | (UINT32)ubuf[0];\r
62 }\r
63 \r
64 /* Locate end-of-central-dir sig in buffer and return offset\r
65    out:\r
66         *offset offset of cent dir start in buffer\r
67    return:\r
68         ==0 not found\r
69         !=0 found, *offset valid\r
70 */\r
71 static int ecd_find_sig (char *buffer, int buflen, int *offset)\r
72 {\r
73         static char ecdsig[] = { 'P', 'K', 0x05, 0x06 };\r
74         int i;\r
75         for (i=buflen-22; i>=0; i--) {\r
76                 if (memcmp(buffer+i, ecdsig, 4) == 0) {\r
77                         *offset = i;\r
78                         return 1;\r
79                 }\r
80         }\r
81         return 0;\r
82 }\r
83 \r
84 /* Read ecd data in zip structure\r
85    in:\r
86      zip->fp, zip->length zip file\r
87    out:\r
88      zip->ecd, zip->ecd_length ecd data\r
89 */\r
90 static int ecd_read(ZIP* zip) {\r
91         char* buf;\r
92         int buf_length = 1024; /* initial buffer length */\r
93 \r
94         while (1) {\r
95                 int offset;\r
96 \r
97                 if (buf_length > zip->length)\r
98                         buf_length = zip->length;\r
99 \r
100                 if (fseek(zip->fp, zip->length - buf_length, SEEK_SET) != 0) {\r
101                         return -1;\r
102                 }\r
103 \r
104                 /* allocate buffer */\r
105                 buf = (char*)malloc( buf_length );\r
106                 if (!buf) {\r
107                         return -1;\r
108                 }\r
109 \r
110                 if (fread( buf, buf_length, 1, zip->fp ) != 1) {\r
111                         free(buf);\r
112                         return -1;\r
113                 }\r
114 \r
115                 if (ecd_find_sig(buf, buf_length, &offset)) {\r
116                         zip->ecd_length = buf_length - offset;\r
117 \r
118                         zip->ecd = (char*)malloc( zip->ecd_length );\r
119                         if (!zip->ecd) {\r
120                                 free(buf);\r
121                                 return -1;\r
122                         }\r
123 \r
124                         memcpy(zip->ecd, buf + offset, zip->ecd_length);\r
125 \r
126                         free(buf);\r
127                         return 0;\r
128                 }\r
129 \r
130                 free(buf);\r
131 \r
132                 if (buf_length < zip->length) {\r
133                         /* double buffer */\r
134                         buf_length = 2*buf_length;\r
135 \r
136                         logerror("Retry reading of zip ecd for %d bytes\n",buf_length);\r
137 \r
138                 } else {\r
139                         return -1;\r
140                 }\r
141         }\r
142 }\r
143 \r
144 /* offsets in end of central directory structure */\r
145 #define ZIPESIG         0x00\r
146 #define ZIPEDSK         0x04\r
147 #define ZIPECEN         0x06\r
148 #define ZIPENUM         0x08\r
149 #define ZIPECENN        0x0a\r
150 #define ZIPECSZ         0x0c\r
151 #define ZIPEOFST        0x10\r
152 #define ZIPECOML        0x14\r
153 #define ZIPECOM         0x16\r
154 \r
155 /* offsets in central directory entry structure */\r
156 #define ZIPCENSIG       0x0\r
157 #define ZIPCVER         0x4\r
158 #define ZIPCOS          0x5\r
159 #define ZIPCVXT         0x6\r
160 #define ZIPCEXOS        0x7\r
161 #define ZIPCFLG         0x8\r
162 #define ZIPCMTHD        0xa\r
163 #define ZIPCTIM         0xc\r
164 #define ZIPCDAT         0xe\r
165 #define ZIPCCRC         0x10\r
166 #define ZIPCSIZ         0x14\r
167 #define ZIPCUNC         0x18\r
168 #define ZIPCFNL         0x1c\r
169 #define ZIPCXTL         0x1e\r
170 #define ZIPCCML         0x20\r
171 #define ZIPDSK          0x22\r
172 #define ZIPINT          0x24\r
173 #define ZIPEXT          0x26\r
174 #define ZIPOFST         0x2a\r
175 #define ZIPCFN          0x2e\r
176 \r
177 /* offsets in local file header structure */\r
178 #define ZIPLOCSIG       0x00\r
179 #define ZIPVER          0x04\r
180 #define ZIPGENFLG       0x06\r
181 #define ZIPMTHD         0x08\r
182 #define ZIPTIME         0x0a\r
183 #define ZIPDATE         0x0c\r
184 #define ZIPCRC          0x0e\r
185 #define ZIPSIZE         0x12\r
186 #define ZIPUNCMP        0x16\r
187 #define ZIPFNLN         0x1a\r
188 #define ZIPXTRALN       0x1c\r
189 #define ZIPNAME         0x1e\r
190 \r
191 /* Opens a zip stream for reading\r
192    return:\r
193      !=0 success, zip stream\r
194      ==0 error\r
195 */\r
196 ZIP* openzip(const char* zipfile) {\r
197         /* allocate */\r
198         ZIP* zip = (ZIP*)malloc( sizeof(ZIP) );\r
199         if (!zip) {\r
200                 return 0;\r
201         }\r
202 \r
203         /* open */\r
204         zip->fp = fopen(zipfile, "rb");\r
205         if (!zip->fp) {\r
206                 errormsg ("Opening for reading", ERROR_FILESYSTEM, zipfile);\r
207                 free(zip);\r
208                 return 0;\r
209         }\r
210 \r
211         /* go to end */\r
212         if (fseek(zip->fp, 0L, SEEK_END) != 0) {\r
213                 errormsg ("Seeking to end", ERROR_FILESYSTEM, zipfile);\r
214                 fclose(zip->fp);\r
215                 free(zip);\r
216                 return 0;\r
217         }\r
218 \r
219         /* get length */\r
220         zip->length = ftell(zip->fp);\r
221         if (zip->length < 0) {\r
222                 errormsg ("Get file size", ERROR_FILESYSTEM, zipfile);\r
223                 fclose(zip->fp);\r
224                 free(zip);\r
225                 return 0;\r
226         }\r
227         if (zip->length == 0) {\r
228                 errormsg ("Empty file", ERROR_CORRUPT, zipfile);\r
229                 fclose(zip->fp);\r
230                 free(zip);\r
231                 return 0;\r
232         }\r
233 \r
234         /* read ecd data */\r
235         if (ecd_read(zip)!=0) {\r
236                 errormsg ("Reading ECD (end of central directory)", ERROR_CORRUPT, zipfile);\r
237                 fclose(zip->fp);\r
238                 free(zip);\r
239                 return 0;\r
240         }\r
241 \r
242         /* compile ecd info */\r
243         zip->end_of_cent_dir_sig = read_dword (zip->ecd+ZIPESIG);\r
244         zip->number_of_this_disk = read_word (zip->ecd+ZIPEDSK);\r
245         zip->number_of_disk_start_cent_dir = read_word (zip->ecd+ZIPECEN);\r
246         zip->total_entries_cent_dir_this_disk = read_word (zip->ecd+ZIPENUM);\r
247         zip->total_entries_cent_dir = read_word (zip->ecd+ZIPECENN);\r
248         zip->size_of_cent_dir = read_dword (zip->ecd+ZIPECSZ);\r
249         zip->offset_to_start_of_cent_dir = read_dword (zip->ecd+ZIPEOFST);\r
250         zip->zipfile_comment_length = read_word (zip->ecd+ZIPECOML);\r
251         zip->zipfile_comment = zip->ecd+ZIPECOM;\r
252 \r
253         /* verify that we can work with this zipfile (no disk spanning allowed) */\r
254         if ((zip->number_of_this_disk != zip->number_of_disk_start_cent_dir) ||\r
255                 (zip->total_entries_cent_dir_this_disk != zip->total_entries_cent_dir) ||\r
256                 (zip->total_entries_cent_dir < 1)) {\r
257                 errormsg("Cannot span disks", ERROR_UNSUPPORTED, zipfile);\r
258                 free(zip->ecd);\r
259                 fclose(zip->fp);\r
260                 free(zip);\r
261                 return 0;\r
262         }\r
263 \r
264         if (fseek(zip->fp, zip->offset_to_start_of_cent_dir, SEEK_SET)!=0) {\r
265                 errormsg ("Seeking to central directory", ERROR_CORRUPT, zipfile);\r
266                 free(zip->ecd);\r
267                 fclose(zip->fp);\r
268                 free(zip);\r
269                 return 0;\r
270         }\r
271 \r
272         /* read from start of central directory */\r
273         zip->cd = (char*)malloc( zip->size_of_cent_dir );\r
274         if (!zip->cd) {\r
275                 free(zip->ecd);\r
276                 fclose(zip->fp);\r
277                 free(zip);\r
278                 return 0;\r
279         }\r
280 \r
281         if (fread(zip->cd, zip->size_of_cent_dir, 1, zip->fp)!=1) {\r
282                 errormsg ("Reading central directory", ERROR_CORRUPT, zipfile);\r
283                 free(zip->cd);\r
284                 free(zip->ecd);\r
285                 fclose(zip->fp);\r
286                 free(zip);\r
287                 return 0;\r
288         }\r
289 \r
290         /* reset ent */\r
291         zip->ent.name = 0;\r
292 \r
293         /* rewind */\r
294         zip->cd_pos = 0;\r
295 \r
296         /* file name */\r
297         zip->zip = (char*)malloc(strlen(zipfile)+1);\r
298         if (!zip->zip) {\r
299                 free(zip->cd);\r
300                 free(zip->ecd);\r
301                 fclose(zip->fp);\r
302                 free(zip);\r
303                 return 0;\r
304         }\r
305         strcpy(zip->zip, zipfile);\r
306 \r
307         return zip;\r
308 }\r
309 \r
310 /* Reads the current entry from a zip stream\r
311    in:\r
312      zip opened zip\r
313    return:\r
314      !=0 success\r
315      ==0 error\r
316 */\r
317 struct zipent* readzip(ZIP* zip) {\r
318 \r
319         /* end of directory */\r
320         if (zip->cd_pos >= zip->size_of_cent_dir)\r
321                 return 0;\r
322 \r
323         /* compile zipent info */\r
324         zip->ent.cent_file_header_sig = read_dword (zip->cd+zip->cd_pos+ZIPCENSIG);\r
325         zip->ent.version_made_by = *(zip->cd+zip->cd_pos+ZIPCVER);\r
326         zip->ent.host_os = *(zip->cd+zip->cd_pos+ZIPCOS);\r
327         zip->ent.version_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCVXT);\r
328         zip->ent.os_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCEXOS);\r
329         zip->ent.general_purpose_bit_flag = read_word (zip->cd+zip->cd_pos+ZIPCFLG);\r
330         zip->ent.compression_method = read_word (zip->cd+zip->cd_pos+ZIPCMTHD);\r
331         zip->ent.last_mod_file_time = read_word (zip->cd+zip->cd_pos+ZIPCTIM);\r
332         zip->ent.last_mod_file_date = read_word (zip->cd+zip->cd_pos+ZIPCDAT);\r
333         zip->ent.crc32 = read_dword (zip->cd+zip->cd_pos+ZIPCCRC);\r
334         zip->ent.compressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCSIZ);\r
335         zip->ent.uncompressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCUNC);\r
336         zip->ent.filename_length = read_word (zip->cd+zip->cd_pos+ZIPCFNL);\r
337         zip->ent.extra_field_length = read_word (zip->cd+zip->cd_pos+ZIPCXTL);\r
338         zip->ent.file_comment_length = read_word (zip->cd+zip->cd_pos+ZIPCCML);\r
339         zip->ent.disk_number_start = read_word (zip->cd+zip->cd_pos+ZIPDSK);\r
340         zip->ent.internal_file_attrib = read_word (zip->cd+zip->cd_pos+ZIPINT);\r
341         zip->ent.external_file_attrib = read_dword (zip->cd+zip->cd_pos+ZIPEXT);\r
342         zip->ent.offset_lcl_hdr_frm_frst_disk = read_dword (zip->cd+zip->cd_pos+ZIPOFST);\r
343 \r
344     /* check to see if filename length is illegally long (past the size of this directory\r
345        entry) */\r
346     if (zip->cd_pos + ZIPCFN + zip->ent.filename_length > zip->size_of_cent_dir)\r
347     {\r
348         errormsg("Invalid filename length in directory", ERROR_CORRUPT,zip->zip);\r
349         return 0;\r
350     }\r
351 \r
352         /* copy filename */\r
353         free(zip->ent.name);\r
354         zip->ent.name = (char*)malloc(zip->ent.filename_length + 1);\r
355         memcpy(zip->ent.name, zip->cd+zip->cd_pos+ZIPCFN, zip->ent.filename_length);\r
356         zip->ent.name[zip->ent.filename_length] = 0;\r
357 \r
358         /* skip to next entry in central dir */\r
359         zip->cd_pos += ZIPCFN + zip->ent.filename_length + zip->ent.extra_field_length + zip->ent.file_comment_length;\r
360 \r
361         return &zip->ent;\r
362 }\r
363 \r
364 /* Closes a zip stream */\r
365 void closezip(ZIP* zip) {\r
366         /* release all */\r
367         free(zip->ent.name);\r
368         free(zip->cd);\r
369         free(zip->ecd);\r
370         /* only if not suspended */\r
371         if (zip->fp)\r
372                 fclose(zip->fp);\r
373         free(zip->zip);\r
374         free(zip);\r
375 }\r
376 \r
377 /* Suspend access to a zip file (release file handler)\r
378    in:\r
379       zip opened zip\r
380    note:\r
381      A suspended zip is automatically reopened at first call of\r
382      readuncompressd() or readcompressed() functions\r
383 */\r
384 void suspendzip(ZIP* zip) {\r
385         if (zip->fp) {\r
386                 fclose(zip->fp);\r
387                 zip->fp = 0;\r
388         }\r
389 }\r
390 \r
391 /* Revive a suspended zip file (reopen file handler)\r
392    in:\r
393      zip suspended zip\r
394    return:\r
395         zip success\r
396         ==0 error (zip must be closed with closezip)\r
397 */\r
398 static ZIP* revivezip(ZIP* zip) {\r
399         if (!zip->fp) {\r
400                 zip->fp = fopen(zip->zip, "rb");\r
401                 if (!zip->fp) {\r
402                         return 0;\r
403                 }\r
404         }\r
405         return zip;\r
406 \r
407 }\r
408 \r
409 /* Reset a zip stream to the first entry\r
410    in:\r
411      zip opened zip\r
412    note:\r
413      ZIP file must be opened and not suspended\r
414 */\r
415 void rewindzip(ZIP* zip) {\r
416         zip->cd_pos = 0;\r
417 }\r
418 \r
419 /* Seek zip->fp to compressed data\r
420    return:\r
421         ==0 success\r
422         <0 error\r
423 */\r
424 int seekcompresszip(ZIP* zip, struct zipent* ent) {\r
425         char buf[ZIPNAME];\r
426         long offset;\r
427 \r
428         if (!zip->fp) {\r
429                 if (!revivezip(zip))\r
430                         return -1;\r
431         }\r
432 \r
433         if (fseek(zip->fp, ent->offset_lcl_hdr_frm_frst_disk, SEEK_SET)!=0) {\r
434                 errormsg ("Seeking to header", ERROR_CORRUPT, zip->zip);\r
435                 return -1;\r
436         }\r
437 \r
438         if (fread(buf, ZIPNAME, 1, zip->fp)!=1) {\r
439                 errormsg ("Reading header", ERROR_CORRUPT, zip->zip);\r
440                 return -1;\r
441         }\r
442 \r
443         {\r
444                 UINT16 filename_length = read_word (buf+ZIPFNLN);\r
445                 UINT16 extra_field_length = read_word (buf+ZIPXTRALN);\r
446 \r
447                 /* calculate offset to data and fseek() there */\r
448                 offset = ent->offset_lcl_hdr_frm_frst_disk + ZIPNAME + filename_length + extra_field_length;\r
449 \r
450                 if (fseek(zip->fp, offset, SEEK_SET) != 0) {\r
451                         errormsg ("Seeking to compressed data", ERROR_CORRUPT, zip->zip);\r
452                         return -1;\r
453                 }\r
454 \r
455         }\r
456 \r
457         return 0;\r
458 }\r
459 \r
460 /* Inflate a file\r
461    in:\r
462    in_file stream to inflate\r
463    in_size size of the compressed data to read\r
464    out_size size of decompressed data\r
465    out:\r
466    out_data buffer for decompressed data\r
467    return:\r
468    ==0 ok\r
469 \r
470    990525 rewritten for use with zlib MLR\r
471 */\r
472 static int inflate_file(FILE* in_file, unsigned in_size, unsigned char* out_data, unsigned out_size)\r
473 {\r
474     int err;\r
475         unsigned char* in_buffer;\r
476     z_stream d_stream; /* decompression stream */\r
477 \r
478     d_stream.zalloc = 0;\r
479     d_stream.zfree = 0;\r
480     d_stream.opaque = 0;\r
481 \r
482         d_stream.next_in  = 0;\r
483         d_stream.avail_in = 0;\r
484     d_stream.next_out = out_data;\r
485     d_stream.avail_out = out_size;\r
486 \r
487     err = inflateInit2(&d_stream, -MAX_WBITS);\r
488         /* windowBits is passed < 0 to tell that there is no zlib header.\r
489          * Note that in this case inflate *requires* an extra "dummy" byte\r
490          * after the compressed stream in order to complete decompression and\r
491          * return Z_STREAM_END.\r
492          */\r
493     if (err != Z_OK)\r
494         {\r
495                 logerror("inflateInit error: %d\n", err);\r
496         return -1;\r
497         }\r
498 \r
499         in_buffer = (unsigned char*)malloc(INFLATE_INPUT_BUFFER_MAX+1);\r
500         if (!in_buffer)\r
501                 return -1;\r
502 \r
503     for (;;)\r
504         {\r
505                 if (in_size <= 0)\r
506                 {\r
507                         logerror("inflate error: compressed size too small\n");\r
508                         free (in_buffer);\r
509                         return -1;\r
510                 }\r
511                 d_stream.next_in  = in_buffer;\r
512                 d_stream.avail_in = fread (in_buffer, 1, MIN(in_size, INFLATE_INPUT_BUFFER_MAX), in_file);\r
513                 in_size -= d_stream.avail_in;\r
514                 if (in_size == 0)\r
515                         d_stream.avail_in++; /* add dummy byte at end of compressed data */\r
516 \r
517         err = inflate(&d_stream, Z_NO_FLUSH);\r
518         if (err == Z_STREAM_END)\r
519                         break;\r
520                 if (err != Z_OK)\r
521                 {\r
522                         logerror("inflate error: %d\n", err);\r
523                         free (in_buffer);\r
524                         return -1;\r
525                 }\r
526     }\r
527 \r
528     err = inflateEnd(&d_stream);\r
529         if (err != Z_OK)\r
530         {\r
531                 logerror("inflateEnd error: %d\n", err);\r
532                 free (in_buffer);\r
533                 return -1;\r
534         }\r
535 \r
536         free (in_buffer);\r
537 \r
538         if ((d_stream.avail_out > 0) || (in_size > 0))\r
539         {\r
540                 logerror("zip size mismatch. %i\n", in_size);\r
541                 return -1;\r
542         }\r
543 \r
544         return 0;\r
545 }\r
546 \r
547 /* Read compressed data\r
548    out:\r
549         data compressed data read\r
550    return:\r
551         ==0 success\r
552         <0 error\r
553 */\r
554 int readcompresszip(ZIP* zip, struct zipent* ent, char* data) {\r
555         int err = seekcompresszip(zip,ent);\r
556         if (err!=0)\r
557                 return err;\r
558 \r
559         if (fread(data, ent->compressed_size, 1, zip->fp)!=1) {\r
560                 errormsg ("Reading compressed data", ERROR_CORRUPT, zip->zip);\r
561                 return -1;\r
562         }\r
563 \r
564         return 0;\r
565 }\r
566 \r
567 /* Read UNcompressed data\r
568    out:\r
569         data UNcompressed data\r
570    return:\r
571         ==0 success\r
572         <0 error\r
573 */\r
574 int readuncompresszip(ZIP* zip, struct zipent* ent, char* data) {\r
575         if (ent->compression_method == 0x0000) {\r
576                 /* file is not compressed, simply stored */\r
577 \r
578                 /* check if size are equal */\r
579                 if (ent->compressed_size != ent->uncompressed_size) {\r
580                         errormsg("Wrong uncompressed size in store compression", ERROR_CORRUPT,zip->zip);\r
581                         return -3;\r
582                 }\r
583 \r
584                 return readcompresszip(zip,ent,data);\r
585         } else if (ent->compression_method == 0x0008) {\r
586                 /* file is compressed using "Deflate" method */\r
587                 if (ent->version_needed_to_extract > 0x14) {\r
588                         errormsg("Version too new", ERROR_UNSUPPORTED,zip->zip);\r
589                         return -2;\r
590                 }\r
591 \r
592                 if (ent->os_needed_to_extract != 0x00) {\r
593                         errormsg("OS not supported", ERROR_UNSUPPORTED,zip->zip);\r
594                         return -2;\r
595                 }\r
596 \r
597                 if (ent->disk_number_start != zip->number_of_this_disk) {\r
598                         errormsg("Cannot span disks", ERROR_UNSUPPORTED,zip->zip);\r
599                         return -2;\r
600                 }\r
601 \r
602                 /* read compressed data */\r
603                 if (seekcompresszip(zip,ent)!=0) {\r
604                         return -1;\r
605                 }\r
606 \r
607                 /* configure inflate */\r
608                 if (inflate_file( zip->fp, ent->compressed_size, (unsigned char*)data, ent->uncompressed_size))\r
609                 {\r
610                         errormsg("Inflating compressed data", ERROR_CORRUPT, zip->zip);\r
611                         return -3;\r
612                 }\r
613 \r
614                 return 0;\r
615         } else {\r
616                 errormsg("Compression method unsupported", ERROR_UNSUPPORTED, zip->zip);\r
617                 return -2;\r
618         }\r
619 }\r