1 #include "unzip.h"
2 #include "driver.h"
3 
4 #include <stdlib.h>
5 #include <string.h>
6 #include <ctype.h>
7 #include <assert.h>
8 #include <compat/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 		log_cb(RETRO_LOG_ERROR, LOGPRE "Error in zipfile %s\n%s\n", zipname, usermsg);
28 	/* Output to log file with all informations */
29 	log_cb(RETRO_LOG_ERROR, LOGPRE "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, 1, buf_length, zip->fp ) != buf_length) {
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 			log_cb(RETRO_LOG_ERROR, LOGPRE "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(int pathtype,int pathindex,const char * zipfile)182 ZIP* openzip(int pathtype, int pathindex, 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 = osd_fopen(pathtype, pathindex, 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, 1, zip->size_of_cent_dir, zip->fp)!=zip->size_of_cent_dir) {
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 	zip->pathtype = pathtype;
293 	zip->pathindex = pathindex;
294 
295 	return zip;
296 }
297 
298 /* Reads the current entry from a zip stream
299    in:
300      zip opened zip
301    return:
302      !=0 success
303      ==0 error
304 */
readzip(ZIP * zip)305 struct zipent* readzip(ZIP* zip) {
306 
307 	/* end of directory */
308 	if (zip->cd_pos >= zip->size_of_cent_dir)
309 		return 0;
310 
311 	/* compile zipent info */
312 	zip->ent.cent_file_header_sig = read_dword (zip->cd+zip->cd_pos+ZIPCENSIG);
313 	zip->ent.version_made_by = *(zip->cd+zip->cd_pos+ZIPCVER);
314 	zip->ent.host_os = *(zip->cd+zip->cd_pos+ZIPCOS);
315 	zip->ent.version_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCVXT);
316 	zip->ent.os_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCEXOS);
317 	zip->ent.general_purpose_bit_flag = read_word (zip->cd+zip->cd_pos+ZIPCFLG);
318 	zip->ent.compression_method = read_word (zip->cd+zip->cd_pos+ZIPCMTHD);
319 	zip->ent.last_mod_file_time = read_word (zip->cd+zip->cd_pos+ZIPCTIM);
320 	zip->ent.last_mod_file_date = read_word (zip->cd+zip->cd_pos+ZIPCDAT);
321 	zip->ent.crc32 = read_dword (zip->cd+zip->cd_pos+ZIPCCRC);
322 	zip->ent.compressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCSIZ);
323 	zip->ent.uncompressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCUNC);
324 	zip->ent.filename_length = read_word (zip->cd+zip->cd_pos+ZIPCFNL);
325 	zip->ent.extra_field_length = read_word (zip->cd+zip->cd_pos+ZIPCXTL);
326 	zip->ent.file_comment_length = read_word (zip->cd+zip->cd_pos+ZIPCCML);
327 	zip->ent.disk_number_start = read_word (zip->cd+zip->cd_pos+ZIPDSK);
328 	zip->ent.internal_file_attrib = read_word (zip->cd+zip->cd_pos+ZIPINT);
329 	zip->ent.external_file_attrib = read_dword (zip->cd+zip->cd_pos+ZIPEXT);
330 	zip->ent.offset_lcl_hdr_frm_frst_disk = read_dword (zip->cd+zip->cd_pos+ZIPOFST);
331 
332     /* check to see if filename length is illegally long (past the size of this directory
333        entry) */
334     if (zip->cd_pos + ZIPCFN + zip->ent.filename_length > zip->size_of_cent_dir)
335     {
336         errormsg("Invalid filename length in directory", ERROR_CORRUPT,zip->zip);
337         return 0;
338     }
339 
340 	/* copy filename */
341 	free(zip->ent.name);
342 	zip->ent.name = (char*)malloc(zip->ent.filename_length + 1);
343 	memcpy(zip->ent.name, zip->cd+zip->cd_pos+ZIPCFN, zip->ent.filename_length);
344 	zip->ent.name[zip->ent.filename_length] = 0;
345 
346 	/* skip to next entry in central dir */
347 	zip->cd_pos += ZIPCFN + zip->ent.filename_length + zip->ent.extra_field_length + zip->ent.file_comment_length;
348 
349 	return &zip->ent;
350 }
351 
352 /* Closes a zip stream */
closezip(ZIP * zip)353 void closezip(ZIP* zip) {
354 	/* release all */
355 	free(zip->ent.name);
356 	free(zip->cd);
357 	free(zip->ecd);
358 	/* only if not suspended */
359 	if (zip->fp)
360 		fclose(zip->fp);
361 	free(zip->zip);
362 	free(zip);
363 }
364 
365 /* Suspend access to a zip file (release file handler)
366    in:
367       zip opened zip
368    note:
369      A suspended zip is automatically reopened at first call of
370      readuncompressd() or readcompressed() functions
371 */
suspendzip(ZIP * zip)372 void suspendzip(ZIP* zip) {
373 	if (zip->fp) {
374 		fclose(zip->fp);
375 		zip->fp = 0;
376 	}
377 }
378 
379 /* Revive a suspended zip file (reopen file handler)
380    in:
381      zip suspended zip
382    return:
383 	zip success
384 	==0 error (zip must be closed with closezip)
385 */
revivezip(ZIP * zip)386 static ZIP* revivezip(ZIP* zip) {
387 	if (!zip->fp) {
388 		zip->fp = osd_fopen(zip->pathtype, zip->pathindex, zip->zip, "rb");
389 		if (!zip->fp) {
390 			return 0;
391 		}
392 	}
393 	return zip;
394 
395 }
396 
397 /* Reset a zip stream to the first entry
398    in:
399      zip opened zip
400    note:
401      ZIP file must be opened and not suspended
402 */
rewindzip(ZIP * zip)403 void rewindzip(ZIP* zip) {
404 	zip->cd_pos = 0;
405 }
406 
407 /* Seek zip->fp to compressed data
408    return:
409 	==0 success
410 	<0 error
411 */
seekcompresszip(ZIP * zip,struct zipent * ent)412 int seekcompresszip(ZIP* zip, struct zipent* ent) {
413 	char buf[ZIPNAME];
414 	long offset;
415 
416 	if (!zip->fp) {
417 		if (!revivezip(zip))
418 			return -1;
419 	}
420 
421 	if (fseek(zip->fp, ent->offset_lcl_hdr_frm_frst_disk, SEEK_SET)!=0) {
422 		errormsg ("Seeking to header", ERROR_CORRUPT, zip->zip);
423 		return -1;
424 	}
425 
426 	if (fread(buf, 1, ZIPNAME, zip->fp)!=ZIPNAME) {
427 		errormsg ("Reading header", ERROR_CORRUPT, zip->zip);
428 		return -1;
429 	}
430 
431 	{
432 		UINT16 filename_length = read_word (buf+ZIPFNLN);
433 		UINT16 extra_field_length = read_word (buf+ZIPXTRALN);
434 
435 		/* calculate offset to data and fseek() there */
436 		offset = ent->offset_lcl_hdr_frm_frst_disk + ZIPNAME + filename_length + extra_field_length;
437 
438 		if (fseek(zip->fp, offset, SEEK_SET) != 0) {
439 			errormsg ("Seeking to compressed data", ERROR_CORRUPT, zip->zip);
440 			return -1;
441 		}
442 
443 	}
444 
445 	return 0;
446 }
447 
448 /* Inflate a file
449    in:
450    in_file stream to inflate
451    in_size size of the compressed data to read
452    out_size size of decompressed data
453    out:
454    out_data buffer for decompressed data
455    return:
456    ==0 ok
457 
458    990525 rewritten for use with zlib MLR
459 */
inflate_file(FILE * in_file,unsigned in_size,unsigned char * out_data,unsigned out_size)460 static int inflate_file(FILE* in_file, unsigned in_size, unsigned char* out_data, unsigned out_size)
461 {
462     int err;
463 	unsigned char* in_buffer;
464     z_stream d_stream; /* decompression stream */
465 
466     d_stream.zalloc = 0;
467     d_stream.zfree = 0;
468     d_stream.opaque = 0;
469 
470 	d_stream.next_in  = 0;
471 	d_stream.avail_in = 0;
472     d_stream.next_out = out_data;
473     d_stream.avail_out = out_size;
474 
475     err = inflateInit2(&d_stream, -MAX_WBITS);
476 	/* windowBits is passed < 0 to tell that there is no zlib header.
477 	 * Note that in this case inflate *requires* an extra "dummy" byte
478 	 * after the compressed stream in order to complete decompression and
479 	 * return Z_STREAM_END.
480 	 */
481     if (err != Z_OK)
482 	{
483 		log_cb(RETRO_LOG_ERROR, LOGPRE "inflateInit error: %d\n", err);
484         return -1;
485 	}
486 
487 	in_buffer = (unsigned char*)malloc(INFLATE_INPUT_BUFFER_MAX+1);
488 	if (!in_buffer)
489 		return -1;
490 
491     for (;;)
492 	{
493 		if (in_size <= 0)
494 		{
495 			log_cb(RETRO_LOG_ERROR, LOGPRE "inflate error: compressed size too small\n");
496 			free (in_buffer);
497 			return -1;
498 		}
499 		d_stream.next_in  = in_buffer;
500 		d_stream.avail_in = fread (in_buffer, 1, MIN(in_size, INFLATE_INPUT_BUFFER_MAX), in_file);
501 		in_size -= d_stream.avail_in;
502 		if (in_size == 0)
503 			d_stream.avail_in++; /* add dummy byte at end of compressed data */
504 
505         err = inflate(&d_stream, Z_NO_FLUSH);
506         if (err == Z_STREAM_END)
507 			break;
508 		if (err != Z_OK)
509 		{
510 			log_cb(RETRO_LOG_ERROR, LOGPRE "inflate error: %d\n", err);
511 			free (in_buffer);
512 			return -1;
513 		}
514     }
515 
516     err = inflateEnd(&d_stream);
517 	if (err != Z_OK)
518 	{
519 		log_cb(RETRO_LOG_ERROR, LOGPRE "inflateEnd error: %d\n", err);
520 		free (in_buffer);
521 		return -1;
522 	}
523 
524 	free (in_buffer);
525 
526 	if ((d_stream.avail_out > 0) || (in_size > 0))
527 	{
528 		log_cb(RETRO_LOG_ERROR, LOGPRE "zip size mismatch. %i\n", in_size);
529 		return -1;
530 	}
531 
532 	return 0;
533 }
534 
535 /* Read compressed data
536    out:
537 	data compressed data read
538    return:
539 	==0 success
540 	<0 error
541 */
readcompresszip(ZIP * zip,struct zipent * ent,char * data)542 int readcompresszip(ZIP* zip, struct zipent* ent, char* data) {
543 	int err = seekcompresszip(zip,ent);
544 	if (err!=0)
545 		return err;
546 
547 	if (fread(data, 1, ent->compressed_size, zip->fp)!=ent->compressed_size) {
548 		errormsg ("Reading compressed data", ERROR_CORRUPT, zip->zip);
549 		return -1;
550 	}
551 
552 	return 0;
553 }
554 
555 /* Read UNcompressed data
556    out:
557 	data UNcompressed data
558    return:
559 	==0 success
560 	<0 error
561 */
readuncompresszip(ZIP * zip,struct zipent * ent,char * data)562 int readuncompresszip(ZIP* zip, struct zipent* ent, char* data) {
563 	if (ent->compression_method == 0x0000) {
564 		/* file is not compressed, simply stored */
565 
566 		/* check if size are equal */
567 		if (ent->compressed_size != ent->uncompressed_size) {
568 			errormsg("Wrong uncompressed size in store compression", ERROR_CORRUPT,zip->zip);
569 			return -3;
570 		}
571 
572 		return readcompresszip(zip,ent,data);
573 	} else if (ent->compression_method == 0x0008) {
574 		/* file is compressed using "Deflate" method */
575 		if (ent->version_needed_to_extract > 0x14) {
576 			errormsg("Version too new", ERROR_UNSUPPORTED,zip->zip);
577 			return -2;
578 		}
579 
580 		if (ent->os_needed_to_extract != 0x00) {
581 			errormsg("OS not supported", ERROR_UNSUPPORTED,zip->zip);
582 			return -2;
583 		}
584 
585 		if (ent->disk_number_start != zip->number_of_this_disk) {
586 			errormsg("Cannot span disks", ERROR_UNSUPPORTED,zip->zip);
587 			return -2;
588 		}
589 
590 		/* read compressed data */
591 		if (seekcompresszip(zip,ent)!=0) {
592 			return -1;
593 		}
594 
595 		/* configure inflate */
596 		if (inflate_file( zip->fp, ent->compressed_size, (unsigned char*)data, ent->uncompressed_size))
597 		{
598 			errormsg("Inflating compressed data", ERROR_CORRUPT, zip->zip);
599 			return -3;
600 		}
601 
602 		return 0;
603 	} else {
604 		errormsg("Compression method unsupported", ERROR_UNSUPPORTED, zip->zip);
605 		return -2;
606 	}
607 }
608 
609 /* -------------------------------------------------------------------------
610    Zip cache support
611  ------------------------------------------------------------------------- */
612 
613 /* Use the zip cache */
614 #define ZIP_CACHE
615 
616 #ifdef ZIP_CACHE
617 
618 /* ZIP cache entries */
619 #define ZIP_CACHE_MAX 5
620 
621 /* ZIP cache buffer LRU ( Last Recently Used )
622      zip_cache_map[0] is the newer
623      zip_cache_map[ZIP_CACHE_MAX-1] is the older
624 */
625 static ZIP* zip_cache_map[ZIP_CACHE_MAX];
626 
cache_openzip(int pathtype,int pathindex,const char * zipfile)627 static ZIP* cache_openzip(int pathtype, int pathindex, const char* zipfile) {
628 	ZIP* zip;
629 	unsigned i;
630 
631 	/* search in the cache buffer */
632 	for(i=0;i<ZIP_CACHE_MAX;++i) {
633 		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) {
634 			/* found */
635 			unsigned j;
636 
637 /*
638 			log_cb(RETRO_LOG_ERROR, LOGPRE "Zip cache HIT  for %s\n", zipfile);
639 */
640 
641 			/* reset the zip directory */
642 			rewindzip( zip_cache_map[i] );
643 
644 			/* store */
645 			zip = zip_cache_map[i];
646 
647 			/* shift */
648 			for(j=i;j>0;--j)
649 				zip_cache_map[j] = zip_cache_map[j-1];
650 
651 			/* set the first entry */
652 			zip_cache_map[0] = zip;
653 
654 			return zip_cache_map[0];
655 		}
656 	}
657 	/* not found */
658 
659 /*
660 	log_cb(RETRO_LOG_ERROR, LOGPRE "Zip cache FAIL for %s\n", zipfile);
661 */
662 
663 	/* open the zip */
664 	zip = openzip( pathtype, pathindex, zipfile );
665 	if (!zip)
666 		return 0;
667 
668 	/* close the oldest entry */
669 	if (zip_cache_map[ZIP_CACHE_MAX-1]) {
670 		/* close last zip */
671 		closezip(zip_cache_map[ZIP_CACHE_MAX-1]);
672 		/* reset the entry */
673 		zip_cache_map[ZIP_CACHE_MAX-1] = 0;
674 	}
675 
676 	/* shift */
677 	for(i=ZIP_CACHE_MAX-1;i>0;--i)
678 		zip_cache_map[i] = zip_cache_map[i-1];
679 
680 	/* set the first entry */
681 	zip_cache_map[0] = zip;
682 
683 	return zip_cache_map[0];
684 }
685 
cache_closezip(ZIP * zip)686 static void cache_closezip(ZIP* zip) {
687 	unsigned i;
688 
689 	/* search in the cache buffer */
690 	for(i=0;i<ZIP_CACHE_MAX;++i) {
691 		if (zip_cache_map[i]==zip) {
692 			/* close zip */
693 			closezip(zip);
694 
695 			/* reset cache entry */
696 			zip_cache_map[i] = 0;
697 			return;
698 
699 		}
700 	}
701 	/* not found */
702 
703 	/* close zip */
704 	closezip(zip);
705 }
706 
707 /* CK980415 added to allow osd code to clear zip cache for auditing--each time
708    the user opens up an audit for a game we should reread the zip */
unzip_cache_clear()709 void unzip_cache_clear()
710 {
711 	unsigned i;
712 
713 	/* search in the cache buffer for any zip info and clear it */
714 	for(i=0;i<ZIP_CACHE_MAX;++i) {
715 		if (zip_cache_map[i] != NULL) {
716 			/* close zip */
717 			closezip(zip_cache_map[i]);
718 
719 			/* reset cache entry */
720 			zip_cache_map[i] = 0;
721 /*			return; */
722 
723 		}
724 	}
725 }
726 
727 #define cache_suspendzip(a) suspendzip(a)
728 
729 #else
730 
731 #define cache_openzip(a,b,c) openzip(a,b,c)
732 #define cache_closezip(a) closezip(a)
733 #define cache_suspendzip(a) closezip(a)
734 
735 #define unzip_cache_clear()
736 
737 #endif
738 
739 /* -------------------------------------------------------------------------
740    Backward MAME compatibility
741  ------------------------------------------------------------------------- */
742 
743 /* Compare two filename
744    note:
745      don't check directory in zip and ignore case
746 */
equal_filename(const char * zipfile,const char * file)747 static int equal_filename(const char* zipfile, const char* file) {
748 	const char* s1 = file;
749 	/* start comparison after last / */
750 	const char* s2 = strrchr(zipfile,'/');
751 	if (s2)
752 		++s2;
753 	else
754 		s2 = zipfile;
755 	while (*s1 && toupper(*s1)==toupper(*s2)) {
756 		++s1;
757 		++s2;
758 	}
759 	return !*s1 && !*s2;
760 }
761 
762 /* Pass the path to the zipfile and the name of the file within the zipfile.
763    buf will be set to point to the uncompressed image of that zipped file.
764    length will be set to the length of the uncompressed data. */
load_zipped_file(int pathtype,int pathindex,const char * zipfile,const char * filename,unsigned char ** buf,unsigned int * length)765 int /* error */ load_zipped_file (int pathtype, int pathindex, const char* zipfile, const char* filename, unsigned char** buf, unsigned int* length) {
766 	ZIP* zip;
767 	struct zipent* ent;
768 
769 	zip = cache_openzip(pathtype, pathindex, zipfile);
770 	if (!zip)
771 		return -1;
772 
773 	while (readzip(zip)) {
774 		/* NS981003: support for "load by CRC" */
775 		char crc[9];
776 
777 		ent = &(zip->ent);
778 
779 		sprintf(crc,"%08x",ent->crc32);
780 		if (equal_filename(ent->name, filename) ||
781 				(ent->crc32 && !strcmp(crc, filename)))
782 		{
783 			*length = ent->uncompressed_size;
784 			*buf = (unsigned char*)malloc( *length );
785 			if (!*buf) {
786 				if (!gUnzipQuiet)
787 					log_cb(RETRO_LOG_ERROR, LOGPRE "load_zipped_file(): Unable to allocate %d bytes of RAM\n",*length);
788 				cache_closezip(zip);
789 				return -1;
790 			}
791 
792 			if (readuncompresszip(zip, ent, (char*)*buf)!=0) {
793 				free(*buf);
794 				cache_closezip(zip);
795 				return -1;
796 			}
797 
798 			cache_suspendzip(zip);
799 			return 0;
800 		}
801 	}
802 
803 	cache_suspendzip(zip);
804 	return -1;
805 }
806 
807 /*	Pass the path to the zipfile and the name of the file within the zipfile.
808 	sum will be set to the CRC-32 of that zipped file. */
809 /*  The caller can preset sum to the expected checksum to enable "load by CRC" */
checksum_zipped_file(int pathtype,int pathindex,const char * zipfile,const char * filename,unsigned int * length,unsigned int * sum)810 int /* error */ checksum_zipped_file (int pathtype, int pathindex, const char *zipfile, const char *filename, unsigned int *length, unsigned int *sum) {
811 	ZIP* zip;
812 	struct zipent* ent;
813 
814 	zip = cache_openzip(pathtype, pathindex, zipfile);
815 	if (!zip)
816 		return -1;
817 
818 	while (readzip(zip)) {
819 		ent = &(zip->ent);
820 
821 		if (equal_filename(ent->name, filename))
822 		{
823 			*length = ent->uncompressed_size;
824 			*sum = ent->crc32;
825 			cache_suspendzip(zip);
826 			return 0;
827 		}
828 	}
829 
830 	cache_suspendzip(zip);
831 
832 	/* NS981003: support for "load by CRC" */
833 	zip = cache_openzip(pathtype, pathindex, zipfile);
834 	if (!zip)
835 		return -1;
836 
837 	while (readzip(zip)) {
838 		ent = &(zip->ent);
839 
840 		if (*sum && ent->crc32 == *sum)
841 		{
842 			*length = ent->uncompressed_size;
843 			*sum = ent->crc32;
844 			cache_suspendzip(zip);
845 			return 0;
846 		}
847 	}
848 
849 	cache_suspendzip(zip);
850 	return -1;
851 }
852