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