]> Shamusworld >> Repos - virtualjaguar/blob - src/unzip.c
Moved Jaguar core to library, fixes for Mac OSX compilation.
[virtualjaguar] / src / unzip.c
1 //
2 // ZIP file support (mostly ripped from MAME--thx MAME team!)
3 // Mostly this is here to simplify interfacing to zlib...
4 //
5 // Added by James L. Hammons
6 // (C) 2010 Underground Software
7 //
8 // JLH = James L. Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -------------------------------------------------------------
12 // JLH  01/16/2010  Created this log ;-)
13 // JLH  02/28/2010  Removed unnecessary cruft
14 //
15
16 #include "unzip.h"
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <assert.h>
22 #include <zlib.h>
23 #include "log.h"
24
25 /* public globals */
26 int     gUnzipQuiet = 0;                /* flag controls error messages */
27
28
29 #define ERROR_CORRUPT     "The zipfile seems to be corrupt, please check it"
30 #define ERROR_FILESYSTEM  "Your filesystem seems to be corrupt, please check it"
31 #define ERROR_UNSUPPORTED "The format of this zipfile is not supported, please recompress it"
32
33 #define INFLATE_INPUT_BUFFER_MAX 16384
34 #ifndef MIN
35 #define MIN(x,y) ((x)<(y)?(x):(y))
36 #endif
37
38 /* Print a error message */
39 void errormsg(const char * extmsg, const char * usermsg, const char * zipname)
40 {
41         /* Output to the user with no internal detail */
42         if (!gUnzipQuiet)
43                 printf("Error in zipfile %s\n%s\n", zipname, usermsg);
44         /* Output to log file with all informations */
45 //      WriteLog("Error in zipfile %s: %s\n", zipname, extmsg);
46 }
47
48 /* -------------------------------------------------------------------------
49    Unzip support
50  ------------------------------------------------------------------------- */
51
52 /* Use these to avoid structure padding and byte-ordering problems */
53 static uint16_t read_word(char * buf)
54 {
55    unsigned char * ubuf = (unsigned char *)buf;
56
57    return ((uint16_t)ubuf[1] << 8) | (uint16_t)ubuf[0];
58 }
59
60 /* Use these to avoid structure padding and byte-ordering problems */
61 static uint32_t read_dword(char * buf)
62 {
63    unsigned char * ubuf = (unsigned char *)buf;
64
65    return ((uint32_t)ubuf[3] << 24) | ((uint32_t)ubuf[2] << 16) | ((uint32_t)ubuf[1] << 8) | (uint32_t)ubuf[0];
66 }
67
68 /* Locate end-of-central-dir sig in buffer and return offset
69    out:
70         *offset offset of cent dir start in buffer
71    return:
72         ==0 not found
73         !=0 found, *offset valid
74 */
75 static int ecd_find_sig(char * buffer, int buflen, int * offset)
76 {
77         static char ecdsig[] = { 'P', 'K', 0x05, 0x06 };
78         int i;
79
80         for(i=buflen-22; i>=0; i--)
81         {
82                 if (memcmp(buffer+i, ecdsig, 4) == 0)
83                 {
84                         *offset = i;
85                         return 1;
86                 }
87         }
88
89         return 0;
90 }
91
92 /* Read ecd data in zip structure
93    in:
94      zip->fp, zip->length zip file
95    out:
96      zip->ecd, zip->ecd_length ecd data
97 */
98 static int ecd_read(ZIP * zip)
99 {
100         char * buf;
101         int buf_length = 1024; /* initial buffer length */
102
103         while (1)
104         {
105                 int offset;
106
107                 if (buf_length > zip->length)
108                         buf_length = zip->length;
109
110                 if (fseek(zip->fp, zip->length - buf_length, SEEK_SET) != 0)
111                 {
112                         return -1;
113                 }
114
115                 /* allocate buffer */
116                 buf = (char *)malloc(buf_length);
117
118                 if (!buf)
119                 {
120                         return -1;
121                 }
122
123                 if (fread(buf, 1, buf_length, zip->fp) != (unsigned int)buf_length)
124                 {
125                         free(buf);
126                         return -1;
127                 }
128
129                 if (ecd_find_sig(buf, buf_length, &offset))
130                 {
131                         zip->ecd_length = buf_length - offset;
132
133                         zip->ecd = (char *)malloc(zip->ecd_length);
134
135                         if (!zip->ecd)
136                         {
137                                 free(buf);
138                                 return -1;
139                         }
140
141                         memcpy(zip->ecd, buf + offset, zip->ecd_length);
142                         free(buf);
143                         return 0;
144                 }
145
146                 free(buf);
147
148                 if (buf_length < zip->length)
149                 {
150                         /* double buffer */
151                         buf_length = 2 * buf_length;
152                         WriteLog("Retry reading of zip ecd for %d bytes\n",buf_length);
153
154                 }
155                 else
156                         return -1;
157         }
158 }
159
160 /* offsets in end of central directory structure */
161 #define ZIPESIG         0x00
162 #define ZIPEDSK         0x04
163 #define ZIPECEN         0x06
164 #define ZIPENUM         0x08
165 #define ZIPECENN        0x0a
166 #define ZIPECSZ         0x0c
167 #define ZIPEOFST        0x10
168 #define ZIPECOML        0x14
169 #define ZIPECOM         0x16
170
171 /* offsets in central directory entry structure */
172 #define ZIPCENSIG       0x0
173 #define ZIPCVER         0x4
174 #define ZIPCOS          0x5
175 #define ZIPCVXT         0x6
176 #define ZIPCEXOS        0x7
177 #define ZIPCFLG         0x8
178 #define ZIPCMTHD        0xa
179 #define ZIPCTIM         0xc
180 #define ZIPCDAT         0xe
181 #define ZIPCCRC         0x10
182 #define ZIPCSIZ         0x14
183 #define ZIPCUNC         0x18
184 #define ZIPCFNL         0x1c
185 #define ZIPCXTL         0x1e
186 #define ZIPCCML         0x20
187 #define ZIPDSK          0x22
188 #define ZIPINT          0x24
189 #define ZIPEXT          0x26
190 #define ZIPOFST         0x2a
191 #define ZIPCFN          0x2e
192
193 /* offsets in local file header structure */
194 #define ZIPLOCSIG       0x00
195 #define ZIPVER          0x04
196 #define ZIPGENFLG       0x06
197 #define ZIPMTHD         0x08
198 #define ZIPTIME         0x0a
199 #define ZIPDATE         0x0c
200 #define ZIPCRC          0x0e
201 #define ZIPSIZE         0x12
202 #define ZIPUNCMP        0x16
203 #define ZIPFNLN         0x1a
204 #define ZIPXTRALN       0x1c
205 #define ZIPNAME         0x1e
206
207 //
208 // Opens a zip stream for reading
209 //  return:
210 //     !=0 success, zip stream
211 //     ==0 error
212 //
213 ZIP * openzip(int pathtype, int pathindex, const char * zipfile)
214 {
215         /* allocate */
216         ZIP * zip = (ZIP *)malloc(sizeof(ZIP));
217         if (!zip)
218                 return 0;
219
220         /* open */
221         zip->fp = fopen(zipfile, "rb");
222         if (!zip->fp)
223         {
224                 errormsg("Opening for reading", ERROR_FILESYSTEM, zipfile);
225                 free(zip);
226                 return 0;
227         }
228
229         /* go to end */
230         if (fseek(zip->fp, 0L, SEEK_END) != 0)
231         {
232                 errormsg ("Seeking to end", ERROR_FILESYSTEM, zipfile);
233                 fclose(zip->fp);
234                 free(zip);
235                 return 0;
236         }
237
238         /* get length */
239         zip->length = ftell(zip->fp);
240         if (zip->length < 0)
241         {
242                 errormsg("Get file size", ERROR_FILESYSTEM, zipfile);
243                 fclose(zip->fp);
244                 free(zip);
245                 return 0;
246         }
247         if (zip->length == 0)
248         {
249                 errormsg ("Empty file", ERROR_CORRUPT, zipfile);
250                 fclose(zip->fp);
251                 free(zip);
252                 return 0;
253         }
254
255         /* read ecd data */
256         if (ecd_read(zip) != 0)
257         {
258                 errormsg("Reading ECD (end of central directory)", ERROR_CORRUPT, zipfile);
259                 fclose(zip->fp);
260                 free(zip);
261                 return 0;
262         }
263
264         /* compile ecd info */
265         zip->end_of_cent_dir_sig = read_dword (zip->ecd+ZIPESIG);
266         zip->number_of_this_disk = read_word (zip->ecd+ZIPEDSK);
267         zip->number_of_disk_start_cent_dir = read_word (zip->ecd+ZIPECEN);
268         zip->total_entries_cent_dir_this_disk = read_word (zip->ecd+ZIPENUM);
269         zip->total_entries_cent_dir = read_word (zip->ecd+ZIPECENN);
270         zip->size_of_cent_dir = read_dword (zip->ecd+ZIPECSZ);
271         zip->offset_to_start_of_cent_dir = read_dword (zip->ecd+ZIPEOFST);
272         zip->zipfile_comment_length = read_word (zip->ecd+ZIPECOML);
273         zip->zipfile_comment = zip->ecd+ZIPECOM;
274
275         /* verify that we can work with this zipfile (no disk spanning allowed) */
276         if ((zip->number_of_this_disk != zip->number_of_disk_start_cent_dir)
277                 || (zip->total_entries_cent_dir_this_disk != zip->total_entries_cent_dir)
278                 || (zip->total_entries_cent_dir < 1))
279         {
280                 errormsg("Cannot span disks", ERROR_UNSUPPORTED, zipfile);
281                 free(zip->ecd);
282                 fclose(zip->fp);
283                 free(zip);
284                 return 0;
285         }
286
287         if (fseek(zip->fp, zip->offset_to_start_of_cent_dir, SEEK_SET) != 0)
288         {
289                 errormsg("Seeking to central directory", ERROR_CORRUPT, zipfile);
290                 free(zip->ecd);
291                 fclose(zip->fp);
292                 free(zip);
293                 return 0;
294         }
295
296         /* read from start of central directory */
297         zip->cd = (char *)malloc(zip->size_of_cent_dir);
298         if (!zip->cd)
299         {
300                 free(zip->ecd);
301                 fclose(zip->fp);
302                 free(zip);
303                 return 0;
304         }
305
306         if (fread(zip->cd, 1, zip->size_of_cent_dir, zip->fp) != zip->size_of_cent_dir)
307         {
308                 errormsg("Reading central directory", ERROR_CORRUPT, zipfile);
309                 free(zip->cd);
310                 free(zip->ecd);
311                 fclose(zip->fp);
312                 free(zip);
313                 return 0;
314         }
315
316         /* reset ent */
317         zip->ent.name = 0;
318
319         /* rewind */
320         zip->cd_pos = 0;
321
322         /* file name */
323         zip->zip = (char*)malloc(strlen(zipfile)+1);
324         if (!zip->zip)
325         {
326                 free(zip->cd);
327                 free(zip->ecd);
328                 fclose(zip->fp);
329                 free(zip);
330                 return 0;
331         }
332         strcpy(zip->zip, zipfile);
333         zip->pathtype = pathtype;
334         zip->pathindex = pathindex;
335
336         return zip;
337 }
338
339 /* Reads the current entry from a zip stream
340    in:
341      zip opened zip
342    return:
343      !=0 success
344      ==0 error
345 */
346 struct zipent * readzip(ZIP * zip)
347 {
348
349         /* end of directory */
350         if (zip->cd_pos >= zip->size_of_cent_dir)
351                 return 0;
352
353         /* compile zipent info */
354         zip->ent.cent_file_header_sig = read_dword (zip->cd+zip->cd_pos+ZIPCENSIG);
355         zip->ent.version_made_by = *(zip->cd+zip->cd_pos+ZIPCVER);
356         zip->ent.host_os = *(zip->cd+zip->cd_pos+ZIPCOS);
357         zip->ent.version_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCVXT);
358         zip->ent.os_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCEXOS);
359         zip->ent.general_purpose_bit_flag = read_word (zip->cd+zip->cd_pos+ZIPCFLG);
360         zip->ent.compression_method = read_word (zip->cd+zip->cd_pos+ZIPCMTHD);
361         zip->ent.last_mod_file_time = read_word (zip->cd+zip->cd_pos+ZIPCTIM);
362         zip->ent.last_mod_file_date = read_word (zip->cd+zip->cd_pos+ZIPCDAT);
363         zip->ent.crc32 = read_dword (zip->cd+zip->cd_pos+ZIPCCRC);
364         zip->ent.compressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCSIZ);
365         zip->ent.uncompressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCUNC);
366         zip->ent.filename_length = read_word (zip->cd+zip->cd_pos+ZIPCFNL);
367         zip->ent.extra_field_length = read_word (zip->cd+zip->cd_pos+ZIPCXTL);
368         zip->ent.file_comment_length = read_word (zip->cd+zip->cd_pos+ZIPCCML);
369         zip->ent.disk_number_start = read_word (zip->cd+zip->cd_pos+ZIPDSK);
370         zip->ent.internal_file_attrib = read_word (zip->cd+zip->cd_pos+ZIPINT);
371         zip->ent.external_file_attrib = read_dword (zip->cd+zip->cd_pos+ZIPEXT);
372         zip->ent.offset_lcl_hdr_frm_frst_disk = read_dword (zip->cd+zip->cd_pos+ZIPOFST);
373
374     /* check to see if filename length is illegally long (past the size of this directory
375        entry) */
376     if (zip->cd_pos + ZIPCFN + zip->ent.filename_length > zip->size_of_cent_dir)
377     {
378         errormsg("Invalid filename length in directory", ERROR_CORRUPT,zip->zip);
379         return 0;
380     }
381
382         /* copy filename */
383         free(zip->ent.name);
384         zip->ent.name = (char*)malloc(zip->ent.filename_length + 1);
385         memcpy(zip->ent.name, zip->cd+zip->cd_pos+ZIPCFN, zip->ent.filename_length);
386         zip->ent.name[zip->ent.filename_length] = 0;
387
388         /* skip to next entry in central dir */
389         zip->cd_pos += ZIPCFN + zip->ent.filename_length + zip->ent.extra_field_length + zip->ent.file_comment_length;
390
391         return &zip->ent;
392 }
393
394 /* Closes a zip stream */
395 void closezip(ZIP * zip)
396 {
397         /* release all */
398         free(zip->ent.name);
399         free(zip->cd);
400         free(zip->ecd);
401
402         /* only if not suspended */
403         if (zip->fp)
404                 fclose(zip->fp);
405
406         free(zip->zip);
407         free(zip);
408 }
409
410 /* Suspend access to a zip file (release file handler)
411    in:
412       zip opened zip
413    note:
414      A suspended zip is automatically reopened at first call of
415      readuncompressd() or readcompressed() functions
416 */
417 void suspendzip(ZIP * zip)
418 {
419         if (zip->fp)
420         {
421                 fclose(zip->fp);
422                 zip->fp = 0;
423         }
424 }
425
426 /* Revive a suspended zip file (reopen file handler)
427    in:
428      zip suspended zip
429    return:
430         zip success
431         ==0 error (zip must be closed with closezip)
432 */
433 static ZIP * revivezip(ZIP * zip)
434 {
435         if (!zip->fp)
436         {
437                 zip->fp = fopen(zip->zip, "rb");
438                 if (!zip->fp)
439                         return 0;
440         }
441
442         return zip;
443 }
444
445 /* Reset a zip stream to the first entry
446    in:
447      zip opened zip
448    note:
449      ZIP file must be opened and not suspended
450 */
451 void rewindzip(ZIP * zip)
452 {
453         zip->cd_pos = 0;
454 }
455
456 //
457 // Seek zip->fp to compressed data
458 //  return:
459 //      ==0 success
460 //      <0 error
461 //
462 int seekcompresszip(ZIP * zip, struct zipent * ent)
463 {
464         char buf[ZIPNAME];
465         long offset;
466
467         if (!zip->fp)
468         {
469                 if (!revivezip(zip))
470                         return -1;
471         }
472
473         if (fseek(zip->fp, ent->offset_lcl_hdr_frm_frst_disk, SEEK_SET) != 0)
474         {
475                 errormsg("Seeking to header", ERROR_CORRUPT, zip->zip);
476                 return -1;
477         }
478
479         if (fread(buf, 1, ZIPNAME, zip->fp) != ZIPNAME)
480         {
481                 errormsg("Reading header", ERROR_CORRUPT, zip->zip);
482                 return -1;
483         }
484
485         {
486                 uint16_t filename_length = read_word(buf+ZIPFNLN);
487                 uint16_t extra_field_length = read_word(buf+ZIPXTRALN);
488
489                 // calculate offset to data and fseek() there
490                 offset = ent->offset_lcl_hdr_frm_frst_disk + ZIPNAME + filename_length + extra_field_length;
491
492                 if (fseek(zip->fp, offset, SEEK_SET) != 0)
493                 {
494                         errormsg("Seeking to compressed data", ERROR_CORRUPT, zip->zip);
495                         return -1;
496                 }
497
498         }
499
500         return 0;
501 }
502
503 //
504 // Inflate a file
505 // in:
506 //   in_file stream to inflate
507 //   in_size size of the compressed data to read
508 // out:
509 //   out_size size of decompressed data
510 //   out_data buffer for decompressed data
511 // return:
512 //   ==0 ok
513 //
514 // 990525 rewritten for use with zlib MLR
515 //
516 static int inflate_file(FILE * in_file, unsigned in_size, unsigned char * out_data, unsigned out_size)
517 {
518     int err;
519         unsigned char * in_buffer;
520     z_stream d_stream;                  // decompression stream
521
522     d_stream.zalloc = 0;
523     d_stream.zfree = 0;
524     d_stream.opaque = 0;
525
526         d_stream.next_in  = 0;
527         d_stream.avail_in = 0;
528     d_stream.next_out = out_data;
529     d_stream.avail_out = out_size;
530
531     err = inflateInit2(&d_stream, -MAX_WBITS);
532         /* windowBits is passed < 0 to tell that there is no zlib header.
533          * Note that in this case inflate *requires* an extra "dummy" byte
534          * after the compressed stream in order to complete decompression and
535          * return Z_STREAM_END.
536          */
537     if (err != Z_OK)
538         {
539                 WriteLog("inflateInit error: %d\n", err);
540         return -1;
541         }
542
543         in_buffer = (unsigned char*)malloc(INFLATE_INPUT_BUFFER_MAX+1);
544         if (!in_buffer)
545                 return -1;
546
547     for (;;)
548         {
549                 if (in_size <= 0)
550                 {
551                         WriteLog("inflate error: compressed size too small\n");
552                         free (in_buffer);
553                         return -1;
554                 }
555                 d_stream.next_in  = in_buffer;
556                 d_stream.avail_in = fread(in_buffer, 1, MIN(in_size, INFLATE_INPUT_BUFFER_MAX), in_file);
557                 in_size -= d_stream.avail_in;
558                 if (in_size == 0)
559                         d_stream.avail_in++; /* add dummy byte at end of compressed data */
560
561         err = inflate(&d_stream, Z_NO_FLUSH);
562         if (err == Z_STREAM_END)
563                         break;
564                 if (err != Z_OK)
565                 {
566                         WriteLog("inflate error: %d\n", err);
567                         free (in_buffer);
568                         return -1;
569                 }
570     }
571
572     err = inflateEnd(&d_stream);
573         if (err != Z_OK)
574         {
575                 WriteLog("inflateEnd error: %d\n", err);
576                 free (in_buffer);
577                 return -1;
578         }
579
580         free (in_buffer);
581
582         if ((d_stream.avail_out > 0) || (in_size > 0))
583         {
584                 WriteLog("zip size mismatch. %i\n", in_size);
585                 return -1;
586         }
587
588         return 0;
589 }
590
591 //
592 // Read compressed data
593 //   out:
594 //      data compressed data read
595 //   return:
596 //      ==0 success
597 // <0 error
598 //
599 int readcompresszip(ZIP * zip, struct zipent * ent, char * data)
600 {
601         int err = seekcompresszip(zip, ent);
602         if (err != 0)
603                 return err;
604
605         if (fread(data, 1, ent->compressed_size, zip->fp) != ent->compressed_size)
606         {
607                 errormsg("Reading compressed data", ERROR_CORRUPT, zip->zip);
608                 return -1;
609         }
610
611         return 0;
612 }
613
614 //
615 // Read UNcompressed data
616 //   out:
617 //      data UNcompressed data
618 //   return:
619 //      ==0 success
620 //      <0 error
621 //
622 int readuncompresszip(ZIP * zip, struct zipent * ent, char * data)
623 {
624         if (ent->compression_method == 0x0000)
625         {
626                 /* file is not compressed, simply stored */
627
628                 /* check if size are equal */
629                 if (ent->compressed_size != ent->uncompressed_size)
630                 {
631                         errormsg("Wrong uncompressed size in store compression", ERROR_CORRUPT,zip->zip);
632                         return -3;
633                 }
634
635                 return readcompresszip(zip, ent, data);
636         }
637         else if (ent->compression_method == 0x0008)
638         {
639                 /* file is compressed using "Deflate" method */
640                 if (ent->version_needed_to_extract > 0x14)
641                 {
642                         errormsg("Version too new", ERROR_UNSUPPORTED, zip->zip);
643                         return -2;
644                 }
645
646                 if (ent->os_needed_to_extract != 0x00)
647                 {
648                         errormsg("OS not supported", ERROR_UNSUPPORTED, zip->zip);
649                         return -2;
650                 }
651
652                 if (ent->disk_number_start != zip->number_of_this_disk)
653                 {
654                         errormsg("Cannot span disks", ERROR_UNSUPPORTED, zip->zip);
655                         return -2;
656                 }
657
658                 /* read compressed data */
659                 if (seekcompresszip(zip, ent) != 0)
660                 {
661                         return -1;
662                 }
663
664                 /* configure inflate */
665                 if (inflate_file(zip->fp, ent->compressed_size, (unsigned char *)data, ent->uncompressed_size))
666                 {
667                         errormsg("Inflating compressed data", ERROR_CORRUPT, zip->zip);
668                         return -3;
669                 }
670
671                 return 0;
672         }
673         else
674         {
675                 errormsg("Compression method unsupported", ERROR_UNSUPPORTED, zip->zip);
676                 return -2;
677         }
678 }
679
680 /* -------------------------------------------------------------------------
681    Backward MAME compatibility
682  ------------------------------------------------------------------------- */
683
684 //
685 // Compare two filenames
686 // NOTE: Don't check directory in zip and ignore case
687 //
688 static int equal_filename(const char * zipfile, const char * file)
689 {
690 //      const char * s1 = file;
691         // start comparison after last / also...!
692         const char * s1 = strrchr(file, '/');
693         if (s1)
694                 s1++;
695         else
696                 s1 = file;
697         // start comparison after last /
698         const char * s2 = strrchr(zipfile, '/');
699         if (s2)
700                 s2++;
701         else
702                 s2 = zipfile;
703 //WriteLog("--> Comparing filenames: [%s] <-> [%s]\n", s1, s2);
704
705         // This assumes that s1 is longer than s2... Might not be! !!! FIX !!!
706         while (*s1 && toupper(*s1) == toupper(*s2))
707         {
708                 s1++;
709                 s2++;
710         }
711
712         return !*s1 && !*s2;
713 }
714
715 //
716 // Pass the path to the zipfile and the name of the file within the zipfile.
717 // buf is set to point to the uncompressed image of that zipped file (preallocated by user!).
718 // length will be set to the length of the uncompressed data.
719 //
720 int load_zipped_file(int pathtype, int pathindex, const char * zipfile, const char * filename, unsigned char ** buf, uint32_t * length)
721 {
722         ZIP * zip = openzip(pathtype, pathindex, zipfile);
723
724         if (!zip)
725                 return -1;
726
727         while (readzip(zip))
728         {
729                 /* NS981003: support for "load by CRC" */
730                 char crc[9];
731
732                 struct zipent * ent = &(zip->ent);
733                 sprintf(crc, "%08x", (unsigned int)ent->crc32);
734
735                 if (filename == NULL || equal_filename(ent->name, filename)
736                         || (ent->crc32 && !strcmp(crc, filename)))
737                 {
738                         *length = ent->uncompressed_size;
739
740                         if (readuncompresszip(zip, ent, (char *)*buf) != 0)
741                         {
742                                 closezip(zip);
743                                 return -1;
744                         }
745
746                         suspendzip(zip);
747                         return 0;
748                 }
749         }
750
751         suspendzip(zip);
752         return -1;
753 }