| 1 | #include "unzip.h"\r |
| 2 | \r |
| 3 | #include <stdlib.h>\r |
| 4 | #include <string.h>\r |
| 5 | #include <ctype.h>\r |
| 6 | #include <assert.h>\r |
| 7 | \r |
| 8 | #ifdef __SYMBIAN32__\r |
| 9 | #include <ezlib.h>\r |
| 10 | #else\r |
| 11 | #include "zlib/zlib.h"\r |
| 12 | #endif\r |
| 13 | \r |
| 14 | /* public globals */\r |
| 15 | //int gUnzipQuiet = 0; /* flag controls error messages */\r |
| 16 | \r |
| 17 | #define ERROR_CORRUPT "The zipfile seems to be corrupt, please check it"\r |
| 18 | #define ERROR_FILESYSTEM "Your filesystem seems to be corrupt, please check it"\r |
| 19 | #define ERROR_UNSUPPORTED "The format of this zipfile is not supported, please recompress it"\r |
| 20 | \r |
| 21 | #define INFLATE_INPUT_BUFFER_MAX 16384\r |
| 22 | #ifndef MIN\r |
| 23 | #define MIN(x,y) ((x)<(y)?(x):(y))\r |
| 24 | #endif\r |
| 25 | \r |
| 26 | \r |
| 27 | // notaz\r |
| 28 | #ifdef __DEBUG_PRINT\r |
| 29 | void dprintf(char *format, ...);\r |
| 30 | #define logerror dprintf\r |
| 31 | void errormsg(const char* extmsg, const char* usermsg, const char* zipname)\r |
| 32 | {\r |
| 33 | dprintf("Error in zipfile %s: %s", zipname, extmsg);\r |
| 34 | }\r |
| 35 | #else\r |
| 36 | #define logerror(x...)\r |
| 37 | #define errormsg(x...)\r |
| 38 | #endif\r |
| 39 | \r |
| 40 | /* Print a error message */\r |
| 41 | //void errormsg(const char* extmsg, const char* usermsg, const char* zipname) {\r |
| 42 | /* Output to the user with no internal detail */\r |
| 43 | // if (!gUnzipQuiet)\r |
| 44 | // printf("Error in zipfile %s\n%s\n", zipname, usermsg);\r |
| 45 | /* Output to log file with all informations */\r |
| 46 | // logerror("Error in zipfile %s: %s\n", zipname, extmsg);\r |
| 47 | // printf("Error in zipfile %s: %s\n", zipname, extmsg);\r |
| 48 | //}\r |
| 49 | \r |
| 50 | /* -------------------------------------------------------------------------\r |
| 51 | Unzip support\r |
| 52 | ------------------------------------------------------------------------- */\r |
| 53 | \r |
| 54 | /* Use these to avoid structure padding and byte-ordering problems */\r |
| 55 | static UINT16 read_word (char *buf) {\r |
| 56 | unsigned char *ubuf = (unsigned char *) buf;\r |
| 57 | \r |
| 58 | return ((UINT16)ubuf[1] << 8) | (UINT16)ubuf[0];\r |
| 59 | }\r |
| 60 | \r |
| 61 | /* Use these to avoid structure padding and byte-ordering problems */\r |
| 62 | static UINT32 read_dword (char *buf) {\r |
| 63 | unsigned char *ubuf = (unsigned char *) buf;\r |
| 64 | \r |
| 65 | return ((UINT32)ubuf[3] << 24) | ((UINT32)ubuf[2] << 16) | ((UINT32)ubuf[1] << 8) | (UINT32)ubuf[0];\r |
| 66 | }\r |
| 67 | \r |
| 68 | /* Locate end-of-central-dir sig in buffer and return offset\r |
| 69 | out:\r |
| 70 | *offset offset of cent dir start in buffer\r |
| 71 | return:\r |
| 72 | ==0 not found\r |
| 73 | !=0 found, *offset valid\r |
| 74 | */\r |
| 75 | static int ecd_find_sig (char *buffer, int buflen, int *offset)\r |
| 76 | {\r |
| 77 | static char ecdsig[] = { 'P', 'K', 0x05, 0x06 };\r |
| 78 | int i;\r |
| 79 | for (i=buflen-22; i>=0; i--) {\r |
| 80 | if (memcmp(buffer+i, ecdsig, 4) == 0) {\r |
| 81 | *offset = i;\r |
| 82 | return 1;\r |
| 83 | }\r |
| 84 | }\r |
| 85 | return 0;\r |
| 86 | }\r |
| 87 | \r |
| 88 | /* Read ecd data in zip structure\r |
| 89 | in:\r |
| 90 | zip->fp, zip->length zip file\r |
| 91 | out:\r |
| 92 | zip->ecd, zip->ecd_length ecd data\r |
| 93 | */\r |
| 94 | static int ecd_read(ZIP* zip) {\r |
| 95 | char* buf;\r |
| 96 | int buf_length = 1024; /* initial buffer length */\r |
| 97 | \r |
| 98 | while (1) {\r |
| 99 | int offset;\r |
| 100 | \r |
| 101 | if (buf_length > zip->length)\r |
| 102 | buf_length = zip->length;\r |
| 103 | \r |
| 104 | if (fseek(zip->fp, zip->length - buf_length, SEEK_SET) != 0) {\r |
| 105 | return -1;\r |
| 106 | }\r |
| 107 | \r |
| 108 | /* allocate buffer */\r |
| 109 | buf = (char*)malloc( buf_length );\r |
| 110 | if (!buf) {\r |
| 111 | return -1;\r |
| 112 | }\r |
| 113 | \r |
| 114 | if (fread( buf, buf_length, 1, zip->fp ) != 1) {\r |
| 115 | free(buf);\r |
| 116 | return -1;\r |
| 117 | }\r |
| 118 | \r |
| 119 | if (ecd_find_sig(buf, buf_length, &offset)) {\r |
| 120 | zip->ecd_length = buf_length - offset;\r |
| 121 | \r |
| 122 | zip->ecd = (char*)malloc( zip->ecd_length );\r |
| 123 | if (!zip->ecd) {\r |
| 124 | free(buf);\r |
| 125 | return -1;\r |
| 126 | }\r |
| 127 | \r |
| 128 | memcpy(zip->ecd, buf + offset, zip->ecd_length);\r |
| 129 | \r |
| 130 | free(buf);\r |
| 131 | return 0;\r |
| 132 | }\r |
| 133 | \r |
| 134 | free(buf);\r |
| 135 | \r |
| 136 | if (buf_length < zip->length) {\r |
| 137 | /* double buffer */\r |
| 138 | buf_length = 2*buf_length;\r |
| 139 | \r |
| 140 | logerror("Retry reading of zip ecd for %d bytes\n",buf_length);\r |
| 141 | \r |
| 142 | } else {\r |
| 143 | return -1;\r |
| 144 | }\r |
| 145 | }\r |
| 146 | }\r |
| 147 | \r |
| 148 | /* offsets in end of central directory structure */\r |
| 149 | #define ZIPESIG 0x00\r |
| 150 | #define ZIPEDSK 0x04\r |
| 151 | #define ZIPECEN 0x06\r |
| 152 | #define ZIPENUM 0x08\r |
| 153 | #define ZIPECENN 0x0a\r |
| 154 | #define ZIPECSZ 0x0c\r |
| 155 | #define ZIPEOFST 0x10\r |
| 156 | #define ZIPECOML 0x14\r |
| 157 | #define ZIPECOM 0x16\r |
| 158 | \r |
| 159 | /* offsets in central directory entry structure */\r |
| 160 | #define ZIPCENSIG 0x0\r |
| 161 | #define ZIPCVER 0x4\r |
| 162 | #define ZIPCOS 0x5\r |
| 163 | #define ZIPCVXT 0x6\r |
| 164 | #define ZIPCEXOS 0x7\r |
| 165 | #define ZIPCFLG 0x8\r |
| 166 | #define ZIPCMTHD 0xa\r |
| 167 | #define ZIPCTIM 0xc\r |
| 168 | #define ZIPCDAT 0xe\r |
| 169 | #define ZIPCCRC 0x10\r |
| 170 | #define ZIPCSIZ 0x14\r |
| 171 | #define ZIPCUNC 0x18\r |
| 172 | #define ZIPCFNL 0x1c\r |
| 173 | #define ZIPCXTL 0x1e\r |
| 174 | #define ZIPCCML 0x20\r |
| 175 | #define ZIPDSK 0x22\r |
| 176 | #define ZIPINT 0x24\r |
| 177 | #define ZIPEXT 0x26\r |
| 178 | #define ZIPOFST 0x2a\r |
| 179 | #define ZIPCFN 0x2e\r |
| 180 | \r |
| 181 | /* offsets in local file header structure */\r |
| 182 | #define ZIPLOCSIG 0x00\r |
| 183 | #define ZIPVER 0x04\r |
| 184 | #define ZIPGENFLG 0x06\r |
| 185 | #define ZIPMTHD 0x08\r |
| 186 | #define ZIPTIME 0x0a\r |
| 187 | #define ZIPDATE 0x0c\r |
| 188 | #define ZIPCRC 0x0e\r |
| 189 | #define ZIPSIZE 0x12\r |
| 190 | #define ZIPUNCMP 0x16\r |
| 191 | #define ZIPFNLN 0x1a\r |
| 192 | #define ZIPXTRALN 0x1c\r |
| 193 | #define ZIPNAME 0x1e\r |
| 194 | \r |
| 195 | /* Opens a zip stream for reading\r |
| 196 | return:\r |
| 197 | !=0 success, zip stream\r |
| 198 | ==0 error\r |
| 199 | */\r |
| 200 | ZIP* openzip(const char* zipfile) {\r |
| 201 | /* allocate */\r |
| 202 | ZIP* zip = (ZIP*)malloc( sizeof(ZIP) );\r |
| 203 | if (!zip) {\r |
| 204 | return 0;\r |
| 205 | }\r |
| 206 | \r |
| 207 | /* open */\r |
| 208 | zip->fp = fopen(zipfile, "rb");\r |
| 209 | if (!zip->fp) {\r |
| 210 | errormsg ("Opening for reading", ERROR_FILESYSTEM, zipfile);\r |
| 211 | free(zip);\r |
| 212 | return 0;\r |
| 213 | }\r |
| 214 | \r |
| 215 | /* go to end */\r |
| 216 | if (fseek(zip->fp, 0L, SEEK_END) != 0) {\r |
| 217 | errormsg ("Seeking to end", ERROR_FILESYSTEM, zipfile);\r |
| 218 | fclose(zip->fp);\r |
| 219 | free(zip);\r |
| 220 | return 0;\r |
| 221 | }\r |
| 222 | \r |
| 223 | /* get length */\r |
| 224 | zip->length = ftell(zip->fp);\r |
| 225 | if (zip->length < 0) {\r |
| 226 | errormsg ("Get file size", ERROR_FILESYSTEM, zipfile);\r |
| 227 | fclose(zip->fp);\r |
| 228 | free(zip);\r |
| 229 | return 0;\r |
| 230 | }\r |
| 231 | if (zip->length == 0) {\r |
| 232 | errormsg ("Empty file", ERROR_CORRUPT, zipfile);\r |
| 233 | fclose(zip->fp);\r |
| 234 | free(zip);\r |
| 235 | return 0;\r |
| 236 | }\r |
| 237 | \r |
| 238 | /* read ecd data */\r |
| 239 | if (ecd_read(zip)!=0) {\r |
| 240 | errormsg ("Reading ECD (end of central directory)", ERROR_CORRUPT, zipfile);\r |
| 241 | fclose(zip->fp);\r |
| 242 | free(zip);\r |
| 243 | return 0;\r |
| 244 | }\r |
| 245 | \r |
| 246 | /* compile ecd info */\r |
| 247 | zip->end_of_cent_dir_sig = read_dword (zip->ecd+ZIPESIG);\r |
| 248 | zip->number_of_this_disk = read_word (zip->ecd+ZIPEDSK);\r |
| 249 | zip->number_of_disk_start_cent_dir = read_word (zip->ecd+ZIPECEN);\r |
| 250 | zip->total_entries_cent_dir_this_disk = read_word (zip->ecd+ZIPENUM);\r |
| 251 | zip->total_entries_cent_dir = read_word (zip->ecd+ZIPECENN);\r |
| 252 | zip->size_of_cent_dir = read_dword (zip->ecd+ZIPECSZ);\r |
| 253 | zip->offset_to_start_of_cent_dir = read_dword (zip->ecd+ZIPEOFST);\r |
| 254 | zip->zipfile_comment_length = read_word (zip->ecd+ZIPECOML);\r |
| 255 | zip->zipfile_comment = zip->ecd+ZIPECOM;\r |
| 256 | \r |
| 257 | /* verify that we can work with this zipfile (no disk spanning allowed) */\r |
| 258 | if ((zip->number_of_this_disk != zip->number_of_disk_start_cent_dir) ||\r |
| 259 | (zip->total_entries_cent_dir_this_disk != zip->total_entries_cent_dir) ||\r |
| 260 | (zip->total_entries_cent_dir < 1)) {\r |
| 261 | errormsg("Cannot span disks", ERROR_UNSUPPORTED, zipfile);\r |
| 262 | free(zip->ecd);\r |
| 263 | fclose(zip->fp);\r |
| 264 | free(zip);\r |
| 265 | return 0;\r |
| 266 | }\r |
| 267 | \r |
| 268 | if (fseek(zip->fp, zip->offset_to_start_of_cent_dir, SEEK_SET)!=0) {\r |
| 269 | errormsg ("Seeking to central directory", ERROR_CORRUPT, zipfile);\r |
| 270 | free(zip->ecd);\r |
| 271 | fclose(zip->fp);\r |
| 272 | free(zip);\r |
| 273 | return 0;\r |
| 274 | }\r |
| 275 | \r |
| 276 | /* read from start of central directory */\r |
| 277 | zip->cd = (char*)malloc( zip->size_of_cent_dir );\r |
| 278 | if (!zip->cd) {\r |
| 279 | free(zip->ecd);\r |
| 280 | fclose(zip->fp);\r |
| 281 | free(zip);\r |
| 282 | return 0;\r |
| 283 | }\r |
| 284 | \r |
| 285 | if (fread(zip->cd, zip->size_of_cent_dir, 1, zip->fp)!=1) {\r |
| 286 | errormsg ("Reading central directory", ERROR_CORRUPT, zipfile);\r |
| 287 | free(zip->cd);\r |
| 288 | free(zip->ecd);\r |
| 289 | fclose(zip->fp);\r |
| 290 | free(zip);\r |
| 291 | return 0;\r |
| 292 | }\r |
| 293 | \r |
| 294 | /* reset ent */\r |
| 295 | zip->ent.name = 0;\r |
| 296 | \r |
| 297 | /* rewind */\r |
| 298 | zip->cd_pos = 0;\r |
| 299 | \r |
| 300 | /* file name */\r |
| 301 | zip->zip = (char*)malloc(strlen(zipfile)+1);\r |
| 302 | if (!zip->zip) {\r |
| 303 | free(zip->cd);\r |
| 304 | free(zip->ecd);\r |
| 305 | fclose(zip->fp);\r |
| 306 | free(zip);\r |
| 307 | return 0;\r |
| 308 | }\r |
| 309 | strcpy(zip->zip, zipfile);\r |
| 310 | \r |
| 311 | return zip;\r |
| 312 | }\r |
| 313 | \r |
| 314 | /* Reads the current entry from a zip stream\r |
| 315 | in:\r |
| 316 | zip opened zip\r |
| 317 | return:\r |
| 318 | !=0 success\r |
| 319 | ==0 error\r |
| 320 | */\r |
| 321 | struct zipent* readzip(ZIP* zip) {\r |
| 322 | \r |
| 323 | /* end of directory */\r |
| 324 | if (zip->cd_pos >= zip->size_of_cent_dir)\r |
| 325 | return 0;\r |
| 326 | \r |
| 327 | /* compile zipent info */\r |
| 328 | zip->ent.cent_file_header_sig = read_dword (zip->cd+zip->cd_pos+ZIPCENSIG);\r |
| 329 | zip->ent.version_made_by = *(zip->cd+zip->cd_pos+ZIPCVER);\r |
| 330 | zip->ent.host_os = *(zip->cd+zip->cd_pos+ZIPCOS);\r |
| 331 | zip->ent.version_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCVXT);\r |
| 332 | zip->ent.os_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCEXOS);\r |
| 333 | zip->ent.general_purpose_bit_flag = read_word (zip->cd+zip->cd_pos+ZIPCFLG);\r |
| 334 | zip->ent.compression_method = read_word (zip->cd+zip->cd_pos+ZIPCMTHD);\r |
| 335 | zip->ent.last_mod_file_time = read_word (zip->cd+zip->cd_pos+ZIPCTIM);\r |
| 336 | zip->ent.last_mod_file_date = read_word (zip->cd+zip->cd_pos+ZIPCDAT);\r |
| 337 | zip->ent.crc32 = read_dword (zip->cd+zip->cd_pos+ZIPCCRC);\r |
| 338 | zip->ent.compressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCSIZ);\r |
| 339 | zip->ent.uncompressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCUNC);\r |
| 340 | zip->ent.filename_length = read_word (zip->cd+zip->cd_pos+ZIPCFNL);\r |
| 341 | zip->ent.extra_field_length = read_word (zip->cd+zip->cd_pos+ZIPCXTL);\r |
| 342 | zip->ent.file_comment_length = read_word (zip->cd+zip->cd_pos+ZIPCCML);\r |
| 343 | zip->ent.disk_number_start = read_word (zip->cd+zip->cd_pos+ZIPDSK);\r |
| 344 | zip->ent.internal_file_attrib = read_word (zip->cd+zip->cd_pos+ZIPINT);\r |
| 345 | zip->ent.external_file_attrib = read_dword (zip->cd+zip->cd_pos+ZIPEXT);\r |
| 346 | zip->ent.offset_lcl_hdr_frm_frst_disk = read_dword (zip->cd+zip->cd_pos+ZIPOFST);\r |
| 347 | \r |
| 348 | /* check to see if filename length is illegally long (past the size of this directory\r |
| 349 | entry) */\r |
| 350 | if (zip->cd_pos + ZIPCFN + zip->ent.filename_length > zip->size_of_cent_dir)\r |
| 351 | {\r |
| 352 | errormsg("Invalid filename length in directory", ERROR_CORRUPT,zip->zip);\r |
| 353 | return 0;\r |
| 354 | }\r |
| 355 | \r |
| 356 | /* copy filename */\r |
| 357 | free(zip->ent.name);\r |
| 358 | zip->ent.name = (char*)malloc(zip->ent.filename_length + 1);\r |
| 359 | memcpy(zip->ent.name, zip->cd+zip->cd_pos+ZIPCFN, zip->ent.filename_length);\r |
| 360 | zip->ent.name[zip->ent.filename_length] = 0;\r |
| 361 | \r |
| 362 | /* skip to next entry in central dir */\r |
| 363 | zip->cd_pos += ZIPCFN + zip->ent.filename_length + zip->ent.extra_field_length + zip->ent.file_comment_length;\r |
| 364 | \r |
| 365 | return &zip->ent;\r |
| 366 | }\r |
| 367 | \r |
| 368 | /* Closes a zip stream */\r |
| 369 | void closezip(ZIP* zip) {\r |
| 370 | /* release all */\r |
| 371 | free(zip->ent.name);\r |
| 372 | free(zip->cd);\r |
| 373 | free(zip->ecd);\r |
| 374 | /* only if not suspended */\r |
| 375 | if (zip->fp)\r |
| 376 | fclose(zip->fp);\r |
| 377 | free(zip->zip);\r |
| 378 | free(zip);\r |
| 379 | }\r |
| 380 | \r |
| 381 | /* Suspend access to a zip file (release file handler)\r |
| 382 | in:\r |
| 383 | zip opened zip\r |
| 384 | note:\r |
| 385 | A suspended zip is automatically reopened at first call of\r |
| 386 | readuncompressd() or readcompressed() functions\r |
| 387 | */\r |
| 388 | void suspendzip(ZIP* zip) {\r |
| 389 | if (zip->fp) {\r |
| 390 | fclose(zip->fp);\r |
| 391 | zip->fp = 0;\r |
| 392 | }\r |
| 393 | }\r |
| 394 | \r |
| 395 | /* Revive a suspended zip file (reopen file handler)\r |
| 396 | in:\r |
| 397 | zip suspended zip\r |
| 398 | return:\r |
| 399 | zip success\r |
| 400 | ==0 error (zip must be closed with closezip)\r |
| 401 | */\r |
| 402 | static ZIP* revivezip(ZIP* zip) {\r |
| 403 | if (!zip->fp) {\r |
| 404 | zip->fp = fopen(zip->zip, "rb");\r |
| 405 | if (!zip->fp) {\r |
| 406 | return 0;\r |
| 407 | }\r |
| 408 | }\r |
| 409 | return zip;\r |
| 410 | \r |
| 411 | }\r |
| 412 | \r |
| 413 | /* Reset a zip stream to the first entry\r |
| 414 | in:\r |
| 415 | zip opened zip\r |
| 416 | note:\r |
| 417 | ZIP file must be opened and not suspended\r |
| 418 | */\r |
| 419 | void rewindzip(ZIP* zip) {\r |
| 420 | zip->cd_pos = 0;\r |
| 421 | }\r |
| 422 | \r |
| 423 | /* Seek zip->fp to compressed data\r |
| 424 | return:\r |
| 425 | ==0 success\r |
| 426 | <0 error\r |
| 427 | */\r |
| 428 | int seekcompresszip(ZIP* zip, struct zipent* ent) {\r |
| 429 | char buf[ZIPNAME];\r |
| 430 | long offset;\r |
| 431 | \r |
| 432 | if (!zip->fp) {\r |
| 433 | if (!revivezip(zip))\r |
| 434 | return -1;\r |
| 435 | }\r |
| 436 | \r |
| 437 | if (fseek(zip->fp, ent->offset_lcl_hdr_frm_frst_disk, SEEK_SET)!=0) {\r |
| 438 | errormsg ("Seeking to header", ERROR_CORRUPT, zip->zip);\r |
| 439 | return -1;\r |
| 440 | }\r |
| 441 | \r |
| 442 | if (fread(buf, ZIPNAME, 1, zip->fp)!=1) {\r |
| 443 | errormsg ("Reading header", ERROR_CORRUPT, zip->zip);\r |
| 444 | return -1;\r |
| 445 | }\r |
| 446 | \r |
| 447 | {\r |
| 448 | UINT16 filename_length = read_word (buf+ZIPFNLN);\r |
| 449 | UINT16 extra_field_length = read_word (buf+ZIPXTRALN);\r |
| 450 | \r |
| 451 | /* calculate offset to data and fseek() there */\r |
| 452 | offset = ent->offset_lcl_hdr_frm_frst_disk + ZIPNAME + filename_length + extra_field_length;\r |
| 453 | \r |
| 454 | if (fseek(zip->fp, offset, SEEK_SET) != 0) {\r |
| 455 | errormsg ("Seeking to compressed data", ERROR_CORRUPT, zip->zip);\r |
| 456 | return -1;\r |
| 457 | }\r |
| 458 | \r |
| 459 | }\r |
| 460 | \r |
| 461 | return 0;\r |
| 462 | }\r |
| 463 | \r |
| 464 | /* Inflate a file\r |
| 465 | in:\r |
| 466 | in_file stream to inflate\r |
| 467 | in_size size of the compressed data to read\r |
| 468 | out_size size of decompressed data\r |
| 469 | out:\r |
| 470 | out_data buffer for decompressed data\r |
| 471 | return:\r |
| 472 | ==0 ok\r |
| 473 | \r |
| 474 | 990525 rewritten for use with zlib MLR\r |
| 475 | */\r |
| 476 | static int inflate_file(FILE* in_file, unsigned in_size, unsigned char* out_data, unsigned out_size)\r |
| 477 | {\r |
| 478 | int err;\r |
| 479 | unsigned char* in_buffer;\r |
| 480 | z_stream d_stream; /* decompression stream */\r |
| 481 | \r |
| 482 | d_stream.zalloc = 0;\r |
| 483 | d_stream.zfree = 0;\r |
| 484 | d_stream.opaque = 0;\r |
| 485 | \r |
| 486 | d_stream.next_in = 0;\r |
| 487 | d_stream.avail_in = 0;\r |
| 488 | d_stream.next_out = out_data;\r |
| 489 | d_stream.avail_out = out_size;\r |
| 490 | \r |
| 491 | err = inflateInit2(&d_stream, -MAX_WBITS);\r |
| 492 | /* windowBits is passed < 0 to tell that there is no zlib header.\r |
| 493 | * Note that in this case inflate *requires* an extra "dummy" byte\r |
| 494 | * after the compressed stream in order to complete decompression and\r |
| 495 | * return Z_STREAM_END.\r |
| 496 | */\r |
| 497 | if (err != Z_OK)\r |
| 498 | {\r |
| 499 | logerror("inflateInit error: %d\n", err);\r |
| 500 | return -1;\r |
| 501 | }\r |
| 502 | \r |
| 503 | in_buffer = (unsigned char*)malloc(INFLATE_INPUT_BUFFER_MAX+1);\r |
| 504 | if (!in_buffer)\r |
| 505 | return -1;\r |
| 506 | \r |
| 507 | for (;;)\r |
| 508 | {\r |
| 509 | if (in_size <= 0)\r |
| 510 | {\r |
| 511 | logerror("inflate error: compressed size too small\n");\r |
| 512 | free (in_buffer);\r |
| 513 | return -1;\r |
| 514 | }\r |
| 515 | d_stream.next_in = in_buffer;\r |
| 516 | d_stream.avail_in = fread (in_buffer, 1, MIN(in_size, INFLATE_INPUT_BUFFER_MAX), in_file);\r |
| 517 | in_size -= d_stream.avail_in;\r |
| 518 | if (in_size == 0)\r |
| 519 | d_stream.avail_in++; /* add dummy byte at end of compressed data */\r |
| 520 | \r |
| 521 | err = inflate(&d_stream, Z_NO_FLUSH);\r |
| 522 | if (err == Z_STREAM_END)\r |
| 523 | break;\r |
| 524 | if (err != Z_OK)\r |
| 525 | {\r |
| 526 | logerror("inflate error: %d\n", err);\r |
| 527 | free (in_buffer);\r |
| 528 | return -1;\r |
| 529 | }\r |
| 530 | }\r |
| 531 | \r |
| 532 | err = inflateEnd(&d_stream);\r |
| 533 | if (err != Z_OK)\r |
| 534 | {\r |
| 535 | logerror("inflateEnd error: %d\n", err);\r |
| 536 | free (in_buffer);\r |
| 537 | return -1;\r |
| 538 | }\r |
| 539 | \r |
| 540 | free (in_buffer);\r |
| 541 | \r |
| 542 | if ((d_stream.avail_out > 0) || (in_size > 0))\r |
| 543 | {\r |
| 544 | logerror("zip size mismatch. %i\n", in_size);\r |
| 545 | return -1;\r |
| 546 | }\r |
| 547 | \r |
| 548 | return 0;\r |
| 549 | }\r |
| 550 | \r |
| 551 | /* Read compressed data\r |
| 552 | out:\r |
| 553 | data compressed data read\r |
| 554 | return:\r |
| 555 | ==0 success\r |
| 556 | <0 error\r |
| 557 | */\r |
| 558 | int readcompresszip(ZIP* zip, struct zipent* ent, char* data) {\r |
| 559 | int err = seekcompresszip(zip,ent);\r |
| 560 | if (err!=0)\r |
| 561 | return err;\r |
| 562 | \r |
| 563 | if (fread(data, ent->compressed_size, 1, zip->fp)!=1) {\r |
| 564 | errormsg ("Reading compressed data", ERROR_CORRUPT, zip->zip);\r |
| 565 | return -1;\r |
| 566 | }\r |
| 567 | \r |
| 568 | return 0;\r |
| 569 | }\r |
| 570 | \r |
| 571 | /* Read UNcompressed data\r |
| 572 | out:\r |
| 573 | data UNcompressed data\r |
| 574 | return:\r |
| 575 | ==0 success\r |
| 576 | <0 error\r |
| 577 | */\r |
| 578 | int readuncompresszip(ZIP* zip, struct zipent* ent, char* data) {\r |
| 579 | if (ent->compression_method == 0x0000) {\r |
| 580 | /* file is not compressed, simply stored */\r |
| 581 | \r |
| 582 | /* check if size are equal */\r |
| 583 | if (ent->compressed_size != ent->uncompressed_size) {\r |
| 584 | errormsg("Wrong uncompressed size in store compression", ERROR_CORRUPT,zip->zip);\r |
| 585 | return -3;\r |
| 586 | }\r |
| 587 | \r |
| 588 | return readcompresszip(zip,ent,data);\r |
| 589 | } else if (ent->compression_method == 0x0008) {\r |
| 590 | /* file is compressed using "Deflate" method */\r |
| 591 | if (ent->version_needed_to_extract > 0x14) {\r |
| 592 | errormsg("Version too new", ERROR_UNSUPPORTED,zip->zip);\r |
| 593 | return -2;\r |
| 594 | }\r |
| 595 | \r |
| 596 | if (ent->os_needed_to_extract != 0x00) {\r |
| 597 | errormsg("OS not supported", ERROR_UNSUPPORTED,zip->zip);\r |
| 598 | return -2;\r |
| 599 | }\r |
| 600 | \r |
| 601 | if (ent->disk_number_start != zip->number_of_this_disk) {\r |
| 602 | errormsg("Cannot span disks", ERROR_UNSUPPORTED,zip->zip);\r |
| 603 | return -2;\r |
| 604 | }\r |
| 605 | \r |
| 606 | /* read compressed data */\r |
| 607 | if (seekcompresszip(zip,ent)!=0) {\r |
| 608 | return -1;\r |
| 609 | }\r |
| 610 | \r |
| 611 | /* configure inflate */\r |
| 612 | if (inflate_file( zip->fp, ent->compressed_size, (unsigned char*)data, ent->uncompressed_size))\r |
| 613 | {\r |
| 614 | errormsg("Inflating compressed data", ERROR_CORRUPT, zip->zip);\r |
| 615 | return -3;\r |
| 616 | }\r |
| 617 | \r |
| 618 | return 0;\r |
| 619 | } else {\r |
| 620 | errormsg("Compression method unsupported", ERROR_UNSUPPORTED, zip->zip);\r |
| 621 | return -2;\r |
| 622 | }\r |
| 623 | }\r |