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