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