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