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