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