unzip.c (45783B)
1 /* 2 This file is part of libextractor. 3 Copyright (C) 2004, 2008, 2012, 2026 Vidyut Samanta and Christian Grothoff 4 5 libextractor is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 libextractor is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with libextractor; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19 */ 20 /** 21 * @file common/unzip.c 22 * @brief API to access ZIP archives 23 * @author Christian Grothoff 24 * 25 * This code is based in part on 26 * unzip 1.00 Copyright 1998-2003 Gilles Vollant 27 * http://www.winimage.com/zLibDll" 28 * 29 * 30 * The filenames for each file in a zipfile are stored in two locations. 31 * There is one at the start of each entry, just before the compressed data, 32 * and another at the end in a 'central directory structure'. 33 * 34 * In order to catch self-extracting executables, we scan backwards from the end 35 * of the file looking for the central directory structure. The previous version 36 * of this went forewards through the local headers, but that only works for plain 37 * vanilla zip's and I don't feel like writing a special case for each of the dozen 38 * self-extracting executable stubs. 39 * 40 * This assumes that the zip file is considered to be non-corrupt/non-truncated. 41 * If it is truncated then it's not considered to be a zip and skipped. 42 * 43 * ZIP format description from appnote.iz and appnote.txt (more or less): 44 * 45 * (this is why you always need to put in the last floppy if you span disks) 46 * 47 * 0- 3 end of central dir signature 4 bytes (0x06054b50) P K ^E ^F 48 * 4- 5 number of this disk 2 bytes 49 * 6- 7 number of the disk with the 50 * start of the central directory 2 bytes 51 * 8- 9 total number of entries in 52 * the central dir on this disk 2 bytes 53 * 10-11 total number of entries in 54 * the central dir 2 bytes 55 * 12-15 size of the central directory 4 bytes 56 * 16-19 offset of start of central 57 * directory with respect to 58 * the starting disk number 4 bytes 59 * 20-21 zipfile comment length 2 bytes 60 * 22-?? zipfile comment (variable size) max length 65536 bytes 61 */ 62 #include "platform.h" 63 #include <ctype.h> 64 #include "extractor.h" 65 #include "le_architecture.h" 66 #include "unzip.h" 67 68 #define CASESENSITIVITY (0) 69 #define MAXFILENAME (256) 70 71 #ifndef UNZ_BUFSIZE 72 #define UNZ_BUFSIZE (16384) 73 #endif 74 75 #ifndef UNZ_MAXFILENAMEINZIP 76 #define UNZ_MAXFILENAMEINZIP (256) 77 #endif 78 79 #define SIZECENTRALDIRITEM (0x2e) 80 #define SIZEZIPLOCALHEADER (0x1e) 81 82 83 /** 84 * IO callbacks for access to the ZIP data. 85 */ 86 struct FileFuncDefs 87 { 88 /** 89 * Callback for reading @a size bytes from the ZIP archive into @a buf. 90 * Returns the number of bytes actually copied, which is less than 91 * @a size at the end of the archive. 92 */ 93 size_t (*zread_file) (void *opaque, void *buf, size_t size); 94 95 /** 96 * Callback to obtain the current read offset in the ZIP archive, 97 * -1 on error. 98 */ 99 int64_t (*ztell_file) (void *opaque); 100 101 /** 102 * Callback for seeking to a different position in the ZIP archive. 103 * Returns 0 on success. 104 */ 105 int (*zseek_file) (void *opaque, int64_t offset, int whence); 106 107 /** 108 * Opaque argument to pass to all IO functions. 109 */ 110 void *opaque; 111 }; 112 113 114 /** 115 * Macro to read using filefunc API. 116 * 117 * @param filefunc filefunc struct 118 * @param buf where to write data 119 * @param size number of bytes to read 120 * @return number of bytes copied to buf 121 */ 122 #define ZREAD(filefunc,buf,size) ((*((filefunc).zread_file))((filefunc).opaque, \ 123 buf, size)) 124 125 /** 126 * Macro to obtain current offset in file using filefunc API. 127 * 128 * @param filefunc filefunc struct 129 * @return current offset in file 130 */ 131 #define ZTELL(filefunc) ((*((filefunc).ztell_file))((filefunc).opaque)) 132 133 /** 134 * Macro to seek using filefunc API. 135 * 136 * @param filefunc filefunc struct 137 * @param pos position to seek 138 * @param mode seek mode 139 * @return 0 on success 140 */ 141 #define ZSEEK(filefunc,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque, \ 142 pos, mode)) 143 144 145 /** 146 * Global data about the ZIPfile 147 * These data comes from the end of central dir 148 */ 149 struct GlobalInfo 150 { 151 152 /** 153 * total number of entries in 154 * the central dir on this disk 2 bytes 155 */ 156 uint16_t number_entry; 157 158 /** 159 * size of the global comment of the zipfile 2 bytes 160 */ 161 uint16_t size_comment; 162 163 /** 164 * offset of the global comment in the zipfile 165 */ 166 uint64_t offset_comment; 167 }; 168 169 170 /** 171 * internal info about a file in zipfile 172 */ 173 struct UnzipFileInfoInternal 174 { 175 176 /** 177 * relative offset of local header 4 bytes 178 */ 179 uint32_t offset_curfile; 180 181 }; 182 183 184 /** 185 * Information about a file in zipfile, when reading and 186 * decompressing it 187 */ 188 struct FileInZipReadInfo 189 { 190 /** 191 * internal buffer for compressed data 192 */ 193 char *read_buffer; 194 195 /** 196 * zLib stream structure for inflate 197 */ 198 z_stream stream; 199 200 /** 201 * position in byte on the zipfile, for fseek 202 */ 203 uint64_t pos_in_zipfile; 204 205 /** 206 * flag set if stream structure is initialised 207 */ 208 int stream_initialised; 209 210 /** 211 * offset of the local extra field 212 */ 213 uint64_t offset_local_extrafield; 214 215 /** 216 * size of the local extra field 2 bytes 217 */ 218 uint16_t size_local_extrafield; 219 220 /** 221 * position in the local extra field in read 222 */ 223 uint32_t pos_local_extrafield; 224 225 /** 226 * crc32 of all data uncompressed so far 4 bytes 227 */ 228 uint32_t crc32; 229 230 /** 231 * crc32 we must obtain after decompress all 4 bytes 232 */ 233 uint32_t crc32_wait; 234 235 /** 236 * number of bytes to be decompressed 4 bytes 237 */ 238 uint32_t rest_read_compressed; 239 240 /** 241 * number of bytes to be obtained after decomp 4 bytes 242 */ 243 uint32_t rest_read_uncompressed; 244 245 /** 246 * IO functions. 247 */ 248 struct FileFuncDefs z_filefunc; 249 250 /** 251 * compression method (0==store) 2 bytes 252 */ 253 uint16_t compression_method; 254 255 /** 256 * byte before the zipfile, (>0 for sfx) 257 */ 258 uint64_t byte_before_the_zipfile; 259 }; 260 261 262 /** 263 * Handle for a ZIP archive. 264 * contains internal information about the zipfile 265 */ 266 struct EXTRACTOR_UnzipFile 267 { 268 /** 269 * io structore of the zipfile 270 */ 271 struct FileFuncDefs z_filefunc; 272 273 /** 274 * public global information 275 */ 276 struct GlobalInfo gi; 277 278 /** 279 * byte before the zipfile, (>0 for sfx) 280 */ 281 uint64_t byte_before_the_zipfile; 282 283 /** 284 * number of the current file in the zipfile 285 */ 286 uint32_t num_file; 287 288 /** 289 * pos of the current file in the central dir 290 */ 291 uint64_t pos_in_central_dir; 292 293 /** 294 * flag about the usability of the current file 295 */ 296 int current_file_ok; 297 298 /** 299 * position of the beginning of the central dir 300 */ 301 uint64_t central_pos; 302 303 /** 304 * size of the central directory 4 bytes 305 */ 306 uint32_t size_central_dir; 307 308 /** 309 * offset of start of central directory with respect to the starting 310 * disk number 4 bytes 311 */ 312 uint32_t offset_central_dir; 313 314 /** 315 * public info about the current file in zip 316 */ 317 struct EXTRACTOR_UnzipFileInfo cur_file_info; 318 319 /** 320 * private info about it 321 */ 322 struct UnzipFileInfoInternal cur_file_info_internal; 323 324 /** 325 * structure about the current file if we are decompressing it 326 */ 327 struct FileInZipReadInfo *pfile_in_zip_read; 328 329 /** 330 * Is the file encrypted? 331 */ 332 int encrypted; 333 }; 334 335 336 /** 337 * Read a 16-bit little-endian field from the archive. 338 * 339 * The whole field is fetched with a single #ZREAD() and only then 340 * byte-swapped, so a truncated archive can be recognised (the read is 341 * short) instead of being papered over one byte at a time. Note that 342 * failure is reported as #EXTRACTOR_UNZIP_ERRNO and never as 343 * #EXTRACTOR_UNZIP_EOF, which is numerically #EXTRACTOR_UNZIP_OK and so 344 * would leave @a val untouched behind a successful-looking return. 345 * 346 * @param ffd functions for performing IO operations 347 * @param[out] val set to the value that was read, untouched on error 348 * @return #EXTRACTOR_UNZIP_OK on success, #EXTRACTOR_UNZIP_ERRNO if the 349 * field could not be read in full 350 */ 351 static int 352 read_uint16_from_ffd (const struct FileFuncDefs *ffd, 353 uint16_t *val) 354 { 355 uint16_t raw; 356 357 if (sizeof (raw) != ZREAD (*ffd, &raw, sizeof (raw))) 358 return EXTRACTOR_UNZIP_ERRNO; 359 *val = LE_le16toh (raw); 360 return EXTRACTOR_UNZIP_OK; 361 } 362 363 364 /** 365 * Read a 32-bit little-endian field from the archive. 366 * 367 * See read_uint16_from_ffd() for why this reads the field in one go and 368 * why it must not return #EXTRACTOR_UNZIP_EOF. 369 * 370 * @param ffd functions for performing IO operations 371 * @param[out] val set to the value that was read, untouched on error 372 * @return #EXTRACTOR_UNZIP_OK on success, #EXTRACTOR_UNZIP_ERRNO if the 373 * field could not be read in full 374 */ 375 static int 376 read_uint32_from_ffd (const struct FileFuncDefs *ffd, 377 uint32_t *val) 378 { 379 uint32_t raw; 380 381 if (sizeof (raw) != ZREAD (*ffd, &raw, sizeof (raw))) 382 return EXTRACTOR_UNZIP_ERRNO; 383 *val = LE_le32toh (raw); 384 return EXTRACTOR_UNZIP_OK; 385 } 386 387 388 #ifndef CASESENSITIVITYDEFAULT_NO 389 #if ! defined(unix) && ! defined(CASESENSITIVITYDEFAULT_YES) 390 #define CASESENSITIVITYDEFAULT_NO 391 #endif 392 #endif 393 394 #ifdef CASESENSITIVITYDEFAULT_NO 395 #define CASESENSITIVITYDEFAULTVALUE 2 396 #else 397 #define CASESENSITIVITYDEFAULTVALUE 1 398 #endif 399 400 401 /** 402 * Compare two filenames (fileName1, fileName2). 403 * 404 * @param filename1 name of first file 405 * @param filename2 name of second file 406 * @param iCaseSensitivity, use 1 for case sensitivity (like strcmp); 407 * 2 for no case sensitivity (like strcmpi or strcasecmp); or 408 * 0 for default of your operating system (like 1 on Unix, 2 on Windows) 409 * @return 0 if names are equal 410 */ 411 static int 412 EXTRACTOR_common_unzip_string_file_name_compare (const char *fileName1, 413 const char *fileName2, 414 int iCaseSensitivity) 415 { 416 if (0 == iCaseSensitivity) 417 iCaseSensitivity = CASESENSITIVITYDEFAULTVALUE; 418 if (1 == iCaseSensitivity) 419 return strcmp (fileName1, 420 fileName2); 421 return strcasecmp (fileName1, 422 fileName2); 423 } 424 425 426 #ifndef BUFREADCOMMENT 427 #define BUFREADCOMMENT (0x400) 428 #endif 429 430 431 /** 432 * Locate the central directory in the ZIP file. 433 * 434 * @param ffd IO functions 435 * @return offset of central directory, -1 on error 436 */ 437 static int64_t 438 locate_central_directory (const struct FileFuncDefs *ffd) 439 { 440 unsigned char buf[BUFREADCOMMENT + 4]; 441 int64_t file_size; 442 int64_t back_read; 443 int64_t max_back = 0xffff; /* maximum size of global comment */ 444 445 if (0 != ZSEEK (*ffd, 0, SEEK_END)) 446 return -1; 447 if (0 > (file_size = ZTELL (*ffd))) 448 return -1; 449 if (max_back > file_size) 450 max_back = file_size; 451 back_read = 4; 452 while (back_read < max_back) 453 { 454 size_t read_size; 455 int64_t read_pos; 456 int i; 457 458 if (back_read + BUFREADCOMMENT > max_back) 459 back_read = max_back; 460 else 461 back_read += BUFREADCOMMENT; 462 read_pos = file_size - back_read; 463 read_size = (size_t) (((BUFREADCOMMENT + 4) < (file_size - read_pos)) 464 ? (BUFREADCOMMENT + 4) 465 : (file_size - read_pos)); 466 if (0 != ZSEEK (*ffd, read_pos, SEEK_SET)) 467 break; 468 if (ZREAD (*ffd, buf, read_size) != read_size) 469 break; 470 i = (int) read_size - 3; 471 while (i-- > 0) 472 if ( (0x50 == (*(buf + i))) && 473 (0x4b == (*(buf + i + 1))) && 474 (0x05 == (*(buf + i + 2))) && 475 (0x06 == (*(buf + i + 3))) ) 476 return read_pos + i; 477 } 478 return -1; 479 } 480 481 482 /** 483 * Translate date/time from Dos format to `struct 484 * EXTRACTOR_UnzipDateTimeInfo` (readable more easilty) 485 * 486 * @param ulDosDate time in DOS format (input) 487 * @param ptm where to write time in readable format 488 */ 489 static void 490 dos_date_to_tmu_date (uint32_t ulDosDate, 491 struct EXTRACTOR_UnzipDateTimeInfo*ptm) 492 { 493 uint32_t uDate; 494 495 uDate = ulDosDate >> 16; 496 ptm->tm_mday = (unsigned int) (uDate & 0x1f); 497 ptm->tm_mon = (unsigned int) ((((uDate) & 0x1E0) / 0x20) - 1); 498 ptm->tm_year = (unsigned int) (((uDate & 0x0FE00) / 0x0200) + 1980); 499 ptm->tm_hour = (unsigned int) ((ulDosDate & 0xF800) / 0x800); 500 ptm->tm_min = (unsigned int) ((ulDosDate & 0x7E0) / 0x20); 501 ptm->tm_sec = (unsigned int) (2 * (ulDosDate & 0x1f)); 502 } 503 504 505 /** 506 * Write info about the ZipFile in the *pglobal_info structure. 507 * No preparation of the structure is needed. 508 * 509 * @param file zipfile to manipulate 510 * @param pfile_info file information to initialize 511 * @param pfile_info_internal internal file information to initialize 512 * @param szFileName where to write the name of the current file 513 * @param fileNameBufferSize number of bytes available in @a szFileName 514 * @param extraField where to write extra data 515 * @param extraFieldBufferSize number of bytes available in extraField 516 * @param szComment where to write the comment on the current file 517 * @param commentBufferSize number of bytes available in @a szComment 518 * @return #EXTRACTOR_UNZIP_OK if there is no problem. 519 */ 520 static int 521 get_current_file_info (struct EXTRACTOR_UnzipFile *file, 522 struct EXTRACTOR_UnzipFileInfo *pfile_info, 523 struct UnzipFileInfoInternal *pfile_info_internal, 524 char *szFileName, 525 size_t fileNameBufferSize, 526 void *extraField, 527 size_t extraFieldBufferSize, 528 char *szComment, 529 size_t commentBufferSize) 530 { 531 struct EXTRACTOR_UnzipFileInfo file_info; 532 struct UnzipFileInfoInternal file_info_internal; 533 uint32_t uMagic; 534 int64_t lSeek; 535 536 if (NULL == file) 537 return EXTRACTOR_UNZIP_PARAMERROR; 538 if (0 != ZSEEK (file->z_filefunc, 539 (int64_t) (file->pos_in_central_dir 540 + file->byte_before_the_zipfile), 541 SEEK_SET)) 542 return EXTRACTOR_UNZIP_ERRNO; 543 544 /* we check the magic */ 545 if (EXTRACTOR_UNZIP_OK != 546 read_uint32_from_ffd (&file->z_filefunc, &uMagic)) 547 return EXTRACTOR_UNZIP_ERRNO; 548 if (0x02014b50 != uMagic) 549 return EXTRACTOR_UNZIP_BADZIPFILE; 550 551 if ( (EXTRACTOR_UNZIP_OK != 552 read_uint16_from_ffd (&file->z_filefunc, 553 &file_info.version)) || 554 (EXTRACTOR_UNZIP_OK != 555 read_uint16_from_ffd (&file->z_filefunc, 556 &file_info.version_needed)) || 557 (EXTRACTOR_UNZIP_OK != 558 read_uint16_from_ffd (&file->z_filefunc, 559 &file_info.flag)) || 560 (EXTRACTOR_UNZIP_OK != 561 read_uint16_from_ffd (&file->z_filefunc, 562 &file_info.compression_method)) || 563 (EXTRACTOR_UNZIP_OK != 564 read_uint32_from_ffd (&file->z_filefunc, 565 &file_info.dosDate)) ) 566 return EXTRACTOR_UNZIP_ERRNO; 567 dos_date_to_tmu_date (file_info.dosDate, 568 &file_info.tmu_date); 569 if ( (EXTRACTOR_UNZIP_OK != 570 read_uint32_from_ffd (&file->z_filefunc, 571 &file_info.crc)) || 572 (EXTRACTOR_UNZIP_OK != 573 read_uint32_from_ffd (&file->z_filefunc, 574 &file_info.compressed_size)) || 575 (EXTRACTOR_UNZIP_OK != 576 read_uint32_from_ffd (&file->z_filefunc, 577 &file_info.uncompressed_size)) || 578 (EXTRACTOR_UNZIP_OK != 579 read_uint16_from_ffd (&file->z_filefunc, 580 &file_info.size_filename)) || 581 (EXTRACTOR_UNZIP_OK != 582 read_uint16_from_ffd (&file->z_filefunc, 583 &file_info.size_file_extra)) || 584 (EXTRACTOR_UNZIP_OK != 585 read_uint16_from_ffd (&file->z_filefunc, 586 &file_info.size_file_comment)) || 587 (EXTRACTOR_UNZIP_OK != 588 read_uint16_from_ffd (&file->z_filefunc, 589 &file_info.disk_num_start)) || 590 (EXTRACTOR_UNZIP_OK != 591 read_uint16_from_ffd (&file->z_filefunc, 592 &file_info.internal_fa)) || 593 (EXTRACTOR_UNZIP_OK != 594 read_uint32_from_ffd (&file->z_filefunc, 595 &file_info.external_fa)) || 596 (EXTRACTOR_UNZIP_OK != 597 read_uint32_from_ffd (&file->z_filefunc, 598 &file_info_internal.offset_curfile)) ) 599 return EXTRACTOR_UNZIP_ERRNO; 600 601 lSeek = file_info.size_filename; 602 if (NULL != szFileName) 603 { 604 size_t uSizeRead; 605 606 if (file_info.size_filename < fileNameBufferSize) 607 { 608 *(szFileName + file_info.size_filename) = '\0'; 609 uSizeRead = file_info.size_filename; 610 } 611 else 612 { 613 if (fileNameBufferSize > 0) 614 { 615 *(szFileName + fileNameBufferSize - 1) = '\0'; 616 uSizeRead = fileNameBufferSize - 1; 617 } 618 else 619 { 620 uSizeRead = 0; 621 } 622 } 623 if ( (file_info.size_filename > 0) && 624 (fileNameBufferSize > 0) ) 625 if (uSizeRead != 626 ZREAD (file->z_filefunc, 627 szFileName, 628 uSizeRead)) 629 return EXTRACTOR_UNZIP_ERRNO; 630 lSeek -= (int64_t) uSizeRead; 631 } 632 633 if (NULL != extraField) 634 { 635 size_t uSizeRead; 636 637 if (file_info.size_file_extra<extraFieldBufferSize) 638 uSizeRead = file_info.size_file_extra; 639 else 640 uSizeRead = extraFieldBufferSize; 641 642 if (0 != lSeek) 643 { 644 if (0 != 645 ZSEEK (file->z_filefunc, 646 lSeek, 647 SEEK_CUR)) 648 return EXTRACTOR_UNZIP_ERRNO; 649 lSeek = 0; 650 } 651 if ( (file_info.size_file_extra > 0) && 652 (extraFieldBufferSize > 0) && 653 (uSizeRead != 654 ZREAD (file->z_filefunc, 655 extraField, 656 uSizeRead)) ) 657 return EXTRACTOR_UNZIP_ERRNO; 658 lSeek += (int64_t) file_info.size_file_extra - (int64_t) uSizeRead; 659 } 660 else 661 { 662 lSeek += file_info.size_file_extra; 663 } 664 665 if (NULL != szComment) 666 { 667 size_t uSizeRead; 668 669 if (file_info.size_file_comment < commentBufferSize) 670 { 671 *(szComment + file_info.size_file_comment) = '\0'; 672 uSizeRead = file_info.size_file_comment; 673 } 674 else if (commentBufferSize > 0) 675 { 676 *(szComment + commentBufferSize - 1) = '\0'; 677 uSizeRead = commentBufferSize - 1; 678 } 679 else 680 { 681 /* Nothing fits, not even the terminator; without this branch 682 `szComment[-1]` is written and `commentBufferSize - 1` wraps to 683 ULONG_MAX. Mirrors the guard the file name branch above has. */ 684 uSizeRead = 0; 685 } 686 687 if (0 != lSeek) 688 { 689 if (0 == 690 ZSEEK (file->z_filefunc, 691 lSeek, 692 SEEK_CUR)) 693 lSeek = 0; 694 else 695 return EXTRACTOR_UNZIP_ERRNO; 696 } 697 if ( (file_info.size_file_comment > 0) && 698 (commentBufferSize > 0) && 699 (uSizeRead != 700 ZREAD (file->z_filefunc, 701 szComment, 702 uSizeRead)) ) 703 return EXTRACTOR_UNZIP_ERRNO; 704 lSeek += (int64_t) file_info.size_file_comment - (int64_t) uSizeRead; 705 } 706 else 707 { 708 lSeek += file_info.size_file_comment; 709 } 710 711 if (NULL != pfile_info) 712 *pfile_info = file_info; 713 if (NULL != pfile_info_internal) 714 *pfile_info_internal = file_info_internal; 715 return EXTRACTOR_UNZIP_OK; 716 } 717 718 719 /** 720 * Set the current file of the zipfile to the first file. 721 * 722 * @param file zipfile to manipulate 723 * @return UNZ_OK if there is no problem 724 */ 725 int 726 EXTRACTOR_common_unzip_go_to_first_file (struct EXTRACTOR_UnzipFile *file) 727 { 728 int err; 729 730 if (NULL == file) 731 return EXTRACTOR_UNZIP_PARAMERROR; 732 file->pos_in_central_dir = file->offset_central_dir; 733 file->num_file = 0; 734 err = get_current_file_info (file, 735 &file->cur_file_info, 736 &file->cur_file_info_internal, 737 NULL, 0, 738 NULL, 0, 739 NULL, 0); 740 file->current_file_ok = (EXTRACTOR_UNZIP_OK == err); 741 return err; 742 } 743 744 745 /** 746 * Open a Zip file. 747 * 748 * @param ffd IO functions 749 * @return NULL on error 750 */ 751 static struct EXTRACTOR_UnzipFile * 752 unzip_open_using_ffd (struct FileFuncDefs *ffd) 753 { 754 struct EXTRACTOR_UnzipFile us; 755 struct EXTRACTOR_UnzipFile *file; 756 int64_t central_pos; 757 int64_t offset_comment; 758 uint32_t uL; 759 uint16_t number_disk; /* number of the current dist, used for 760 spanning ZIP, unsupported, always 0*/ 761 uint16_t number_disk_with_CD; /* number of the disk with central dir, used 762 for spanning ZIP, unsupported, always 0*/ 763 uint16_t number_entry_CD; /* total number of entries in 764 the central dir 765 (same than number_entry on nospan) */ 766 767 memset (&us, 0, sizeof(us)); 768 us.z_filefunc = *ffd; 769 central_pos = locate_central_directory (&us.z_filefunc); 770 if (0 > central_pos) 771 return NULL; 772 if (0 != ZSEEK (us.z_filefunc, 773 central_pos, SEEK_SET)) 774 return NULL; 775 776 /* the signature, already checked */ 777 if (EXTRACTOR_UNZIP_OK != 778 read_uint32_from_ffd (&us.z_filefunc, &uL)) 779 return NULL; 780 781 /* number of this disk */ 782 if (EXTRACTOR_UNZIP_OK != 783 read_uint16_from_ffd (&us.z_filefunc, &number_disk)) 784 return NULL; 785 786 /* number of the disk with the start of the central directory */ 787 if (EXTRACTOR_UNZIP_OK != 788 read_uint16_from_ffd (&us.z_filefunc, &number_disk_with_CD)) 789 return NULL; 790 791 /* total number of entries in the central dir on this disk */ 792 if (EXTRACTOR_UNZIP_OK != 793 read_uint16_from_ffd (&us.z_filefunc, &us.gi.number_entry)) 794 return NULL; 795 796 /* total number of entries in the central dir */ 797 if (EXTRACTOR_UNZIP_OK != 798 read_uint16_from_ffd (&us.z_filefunc, &number_entry_CD)) 799 return NULL; 800 801 if ( (number_entry_CD != us.gi.number_entry) || 802 (0 != number_disk_with_CD) || 803 (0 != number_disk) ) 804 return NULL; 805 806 /* size of the central directory */ 807 if (EXTRACTOR_UNZIP_OK != 808 read_uint32_from_ffd (&us.z_filefunc, &us.size_central_dir)) 809 return NULL; 810 811 /* offset of start of central directory with respect to the 812 starting disk number */ 813 if (EXTRACTOR_UNZIP_OK != 814 read_uint32_from_ffd (&us.z_filefunc, &us.offset_central_dir)) 815 return NULL; 816 817 /* zipfile comment length */ 818 if (EXTRACTOR_UNZIP_OK != 819 read_uint16_from_ffd (&us.z_filefunc, &us.gi.size_comment)) 820 return NULL; 821 if (0 > (offset_comment = ZTELL (us.z_filefunc))) 822 return NULL; 823 us.gi.offset_comment = (uint64_t) offset_comment; 824 if (central_pos < (int64_t) us.offset_central_dir + us.size_central_dir) 825 return NULL; 826 827 us.byte_before_the_zipfile = (uint64_t) central_pos 828 - ((uint64_t) us.offset_central_dir 829 + us.size_central_dir); 830 us.central_pos = (uint64_t) central_pos; 831 us.pfile_in_zip_read = NULL; 832 us.encrypted = 0; 833 834 if (NULL == (file = malloc (sizeof(struct EXTRACTOR_UnzipFile)))) 835 return NULL; 836 *file = us; 837 EXTRACTOR_common_unzip_go_to_first_file (file); 838 return file; 839 } 840 841 842 /** 843 * Close the file in zip opened with #EXTRACTOR_common_unzip_open_current_file(). 844 * 845 * @return #EXTRACTOR_UNZIP_CRCERROR if all the file was read but the CRC is not good 846 */ 847 int 848 EXTRACTOR_common_unzip_close_current_file (struct EXTRACTOR_UnzipFile *file) 849 { 850 struct FileInZipReadInfo*pfile_in_zip_read_info; 851 int err = EXTRACTOR_UNZIP_OK; 852 853 if (NULL == file) 854 return EXTRACTOR_UNZIP_PARAMERROR; 855 if (NULL == (pfile_in_zip_read_info = file->pfile_in_zip_read)) 856 return EXTRACTOR_UNZIP_PARAMERROR; 857 if ( (0 == pfile_in_zip_read_info->rest_read_uncompressed) && 858 (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) ) 859 err = EXTRACTOR_UNZIP_CRCERROR; 860 if (NULL != pfile_in_zip_read_info->read_buffer) 861 free (pfile_in_zip_read_info->read_buffer); 862 pfile_in_zip_read_info->read_buffer = NULL; 863 if (pfile_in_zip_read_info->stream_initialised) 864 inflateEnd (&pfile_in_zip_read_info->stream); 865 pfile_in_zip_read_info->stream_initialised = 0; 866 free (pfile_in_zip_read_info); 867 file->pfile_in_zip_read = NULL; 868 return err; 869 } 870 871 872 /** 873 * Close a ZipFile. 874 * 875 * @param file zip file to close 876 * @return #EXTRACTOR_UNZIP_OK if there is no problem. 877 */ 878 int 879 EXTRACTOR_common_unzip_close (struct EXTRACTOR_UnzipFile *file) 880 { 881 if (NULL == file) 882 return EXTRACTOR_UNZIP_PARAMERROR; 883 if (NULL != file->pfile_in_zip_read) 884 EXTRACTOR_common_unzip_close_current_file (file); 885 free (file); 886 return EXTRACTOR_UNZIP_OK; 887 } 888 889 890 /** 891 * Obtain the global comment from a ZIP file. 892 * 893 * @param file unzip file to inspect 894 * @param comment where to copy the comment 895 * @param comment_len maximum number of bytes available in comment 896 * @return #EXTRACTOR_UNZIP_OK on success 897 */ 898 int 899 EXTRACTOR_common_unzip_get_global_comment (struct EXTRACTOR_UnzipFile *file, 900 char *comment, 901 size_t comment_len) 902 { 903 if (NULL == file) 904 return EXTRACTOR_UNZIP_PARAMERROR; 905 if (0 == comment_len) 906 return EXTRACTOR_UNZIP_ERRNO; /* cannot 0-terminate, hence error */ 907 if (comment_len > file->gi.size_comment) 908 comment_len = file->gi.size_comment + 1; 909 if (0 != 910 ZSEEK (file->z_filefunc, 911 (int64_t) file->gi.offset_comment, 912 SEEK_SET)) 913 return EXTRACTOR_UNZIP_ERRNO; 914 if (comment_len - 1 != 915 ZREAD (file->z_filefunc, 916 comment, 917 comment_len - 1)) 918 return EXTRACTOR_UNZIP_ERRNO; 919 comment[comment_len - 1] = '\0'; 920 return EXTRACTOR_UNZIP_OK; 921 } 922 923 924 /** 925 * Write info about the ZipFile in the *pglobal_info structure. 926 * No preparation of the structure is needed. 927 * 928 * @param file zipfile to manipulate 929 * @param pfile_info file information to initialize 930 * @param szFileName where to write the name of the current file 931 * @param fileNameBufferSize number of bytes available in szFileName 932 * @param extraField where to write extra data 933 * @param extraFieldBufferSize number of bytes available in extraField 934 * @param szComment where to write the comment on the current file 935 * @param commentBufferSize number of bytes available in szComment 936 * @return #EXTRACTOR_UNZIP_OK if there is no problem. 937 */ 938 int 939 EXTRACTOR_common_unzip_get_current_file_info ( 940 struct EXTRACTOR_UnzipFile *file, 941 struct EXTRACTOR_UnzipFileInfo *pfile_info, 942 char *szFileName, 943 size_t fileNameBufferSize, 944 void *extraField, 945 size_t extraFieldBufferSize, 946 char *szComment, 947 size_t commentBufferSize) 948 { 949 return get_current_file_info (file, 950 pfile_info, 951 NULL, 952 szFileName, 953 fileNameBufferSize, 954 extraField, 955 extraFieldBufferSize, 956 szComment, 957 commentBufferSize); 958 } 959 960 961 /** 962 * Set the current file of the zipfile to the next file. 963 * 964 * @param file zipfile to manipulate 965 * @return #EXTRACTOR_UNZIP_OK if there is no problem, 966 * #EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE if the actual file was the latest. 967 */ 968 int 969 EXTRACTOR_common_unzip_go_to_next_file (struct EXTRACTOR_UnzipFile *file) 970 { 971 int err; 972 973 if (NULL == file) 974 return EXTRACTOR_UNZIP_PARAMERROR; 975 if (! file->current_file_ok) 976 return EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE; 977 if (file->num_file + 1 == file->gi.number_entry) 978 return EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE; 979 file->pos_in_central_dir += (uint64_t) SIZECENTRALDIRITEM 980 + file->cur_file_info.size_filename 981 + file->cur_file_info.size_file_extra 982 + file->cur_file_info.size_file_comment; 983 file->num_file++; 984 err = get_current_file_info (file, 985 &file->cur_file_info, 986 &file->cur_file_info_internal, 987 NULL, 0, NULL, 0, NULL, 0); 988 file->current_file_ok = (EXTRACTOR_UNZIP_OK == err); 989 return err; 990 } 991 992 993 /** 994 * Try locate the file szFileName in the zipfile. 995 * 996 * @param file zipfile to manipulate 997 * @param szFileName name to find 998 * @param iCaseSensitivity, use 1 for case sensitivity (like strcmp); 999 * 2 for no case sensitivity (like strcmpi or strcasecmp); or 1000 * 0 for default of your operating system (like 1 on Unix, 2 on Windows) 1001 * @return #EXTRACTOR_UNZIP_OK if the file is found. It becomes the current file. 1002 * #EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE if the file is not found 1003 */ 1004 int 1005 EXTRACTOR_common_unzip_go_find_local_file (struct EXTRACTOR_UnzipFile *file, 1006 const char *szFileName, 1007 int iCaseSensitivity) 1008 { 1009 int err; 1010 /* We remember the 'current' position in the file so that we can jump 1011 * back there if we fail. 1012 */ 1013 struct EXTRACTOR_UnzipFileInfo cur_file_infoSaved; 1014 struct UnzipFileInfoInternal cur_file_info_internalSaved; 1015 uint32_t num_fileSaved; 1016 uint64_t pos_in_central_dirSaved; 1017 1018 if (NULL == file) 1019 return EXTRACTOR_UNZIP_PARAMERROR; 1020 if (strlen (szFileName) >= UNZ_MAXFILENAMEINZIP) 1021 return EXTRACTOR_UNZIP_PARAMERROR; 1022 if (! file->current_file_ok) 1023 return EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE; 1024 1025 /* Save the current state */ 1026 num_fileSaved = file->num_file; 1027 pos_in_central_dirSaved = file->pos_in_central_dir; 1028 cur_file_infoSaved = file->cur_file_info; 1029 cur_file_info_internalSaved = file->cur_file_info_internal; 1030 err = EXTRACTOR_common_unzip_go_to_first_file (file); 1031 1032 while (EXTRACTOR_UNZIP_OK == err) 1033 { 1034 char szCurrentFileName[UNZ_MAXFILENAMEINZIP + 1]; 1035 1036 if (EXTRACTOR_UNZIP_OK != 1037 (err = EXTRACTOR_common_unzip_get_current_file_info ( 1038 file, NULL, 1039 szCurrentFileName, 1040 sizeof (szCurrentFileName) 1041 - 1, 1042 NULL, 0, 1043 NULL, 0))) 1044 break; 1045 if (0 == 1046 EXTRACTOR_common_unzip_string_file_name_compare (szCurrentFileName, 1047 szFileName, 1048 iCaseSensitivity)) 1049 return EXTRACTOR_UNZIP_OK; 1050 err = EXTRACTOR_common_unzip_go_to_next_file (file); 1051 } 1052 1053 /* We failed, so restore the state of the 'current file' to where we 1054 * were. 1055 */ 1056 file->num_file = num_fileSaved; 1057 file->pos_in_central_dir = pos_in_central_dirSaved; 1058 file->cur_file_info = cur_file_infoSaved; 1059 file->cur_file_info_internal = cur_file_info_internalSaved; 1060 return err; 1061 } 1062 1063 1064 /** 1065 * Read bytes from the current file (must have been opened). 1066 * 1067 * @param buf contain buffer where data must be copied 1068 * @param len the size of buf. 1069 * @return the number of byte copied if some bytes are copied 1070 * 0 if the end of file was reached 1071 * <0 with error code if there is an error 1072 * (#EXTRACTOR_UNZIP_ERRNO for IO error, or zLib error for uncompress error) 1073 */ 1074 ssize_t 1075 EXTRACTOR_common_unzip_read_current_file (struct EXTRACTOR_UnzipFile *file, 1076 void *buf, 1077 size_t len) 1078 { 1079 int err = EXTRACTOR_UNZIP_OK; 1080 size_t iRead = 0; 1081 struct FileInZipReadInfo *pfile_in_zip_read_info; 1082 1083 if (NULL == file) 1084 return EXTRACTOR_UNZIP_PARAMERROR; 1085 if (NULL == (pfile_in_zip_read_info = file->pfile_in_zip_read)) 1086 return EXTRACTOR_UNZIP_PARAMERROR; 1087 if (NULL == pfile_in_zip_read_info->read_buffer) 1088 return EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE; 1089 if (0 == len) 1090 return 0; 1091 1092 pfile_in_zip_read_info->stream.next_out = (Bytef *) buf; 1093 pfile_in_zip_read_info->stream.avail_out = (uInt) len; 1094 if (len > pfile_in_zip_read_info->rest_read_uncompressed) 1095 pfile_in_zip_read_info->stream.avail_out = 1096 (uInt) pfile_in_zip_read_info->rest_read_uncompressed; 1097 1098 while (pfile_in_zip_read_info->stream.avail_out > 0) 1099 { 1100 if ( (0 == pfile_in_zip_read_info->stream.avail_in) && 1101 (pfile_in_zip_read_info->rest_read_compressed > 0) ) 1102 { 1103 uInt uReadThis = UNZ_BUFSIZE; 1104 if (pfile_in_zip_read_info->rest_read_compressed<uReadThis) 1105 uReadThis = (uInt) pfile_in_zip_read_info->rest_read_compressed; 1106 if (0 == uReadThis) 1107 return EXTRACTOR_UNZIP_EOF; 1108 if (0 != 1109 ZSEEK (pfile_in_zip_read_info->z_filefunc, 1110 (int64_t) (pfile_in_zip_read_info->pos_in_zipfile 1111 + pfile_in_zip_read_info->byte_before_the_zipfile), 1112 SEEK_SET)) 1113 return EXTRACTOR_UNZIP_ERRNO; 1114 if (ZREAD (pfile_in_zip_read_info->z_filefunc, 1115 pfile_in_zip_read_info->read_buffer, 1116 uReadThis) != uReadThis) 1117 return EXTRACTOR_UNZIP_ERRNO; 1118 1119 pfile_in_zip_read_info->pos_in_zipfile += uReadThis; 1120 pfile_in_zip_read_info->rest_read_compressed -= (uint32_t) uReadThis; 1121 pfile_in_zip_read_info->stream.next_in = 1122 (Bytef *) pfile_in_zip_read_info->read_buffer; 1123 pfile_in_zip_read_info->stream.avail_in = (uInt) uReadThis; 1124 } 1125 1126 if (0 == pfile_in_zip_read_info->compression_method) 1127 { 1128 uInt uDoCopy; 1129 1130 if ( (0 == pfile_in_zip_read_info->stream.avail_in) && 1131 (0 == pfile_in_zip_read_info->rest_read_compressed) ) 1132 return (0 == iRead) ? EXTRACTOR_UNZIP_EOF : (ssize_t) iRead; 1133 1134 if (pfile_in_zip_read_info->stream.avail_out < 1135 pfile_in_zip_read_info->stream.avail_in) 1136 uDoCopy = pfile_in_zip_read_info->stream.avail_out; 1137 else 1138 uDoCopy = pfile_in_zip_read_info->stream.avail_in; 1139 memcpy (pfile_in_zip_read_info->stream.next_out, 1140 pfile_in_zip_read_info->stream.next_in, 1141 uDoCopy); 1142 pfile_in_zip_read_info->crc32 = 1143 (uint32_t) crc32 (pfile_in_zip_read_info->crc32, 1144 pfile_in_zip_read_info->stream.next_out, 1145 uDoCopy); 1146 pfile_in_zip_read_info->rest_read_uncompressed -= (uint32_t) uDoCopy; 1147 pfile_in_zip_read_info->stream.avail_in -= uDoCopy; 1148 pfile_in_zip_read_info->stream.avail_out -= uDoCopy; 1149 pfile_in_zip_read_info->stream.next_out += uDoCopy; 1150 pfile_in_zip_read_info->stream.next_in += uDoCopy; 1151 pfile_in_zip_read_info->stream.total_out += uDoCopy; 1152 iRead += uDoCopy; 1153 } 1154 else 1155 { 1156 uLong uTotalOutBefore; 1157 uLong uTotalOutAfter; 1158 const Bytef *bufBefore; 1159 uLong uOutThis; 1160 int flush = Z_SYNC_FLUSH; 1161 1162 uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; 1163 bufBefore = pfile_in_zip_read_info->stream.next_out; 1164 1165 /* 1166 if ((pfile_in_zip_read_info->rest_read_uncompressed == 1167 pfile_in_zip_read_info->stream.avail_out) && 1168 (pfile_in_zip_read_info->rest_read_compressed == 0)) 1169 flush = Z_FINISH; 1170 */err = inflate (&pfile_in_zip_read_info->stream, flush); 1171 1172 uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; 1173 uOutThis = uTotalOutAfter - uTotalOutBefore; 1174 1175 pfile_in_zip_read_info->crc32 = 1176 (uint32_t) crc32 (pfile_in_zip_read_info->crc32, bufBefore, 1177 (uInt) (uOutThis)); 1178 1179 pfile_in_zip_read_info->rest_read_uncompressed -= 1180 (uint32_t) uOutThis; 1181 1182 iRead += (size_t) (uTotalOutAfter - uTotalOutBefore); 1183 1184 if (Z_STREAM_END == err) 1185 return (0 == iRead) ? EXTRACTOR_UNZIP_EOF : (ssize_t) iRead; 1186 if (Z_OK != err) 1187 break; 1188 } 1189 } 1190 1191 if (Z_OK == err) 1192 return (ssize_t) iRead; 1193 return err; 1194 } 1195 1196 1197 /** 1198 * Read the local header of the current zipfile. Check the coherency of 1199 * the local header and info in the end of central directory about 1200 * this file. Store in *piSizeVar the size of extra info in local 1201 * header (filename and size of extra field data) 1202 * 1203 * @param file zipfile to process 1204 * @param piSizeVar where to store the size of the extra info 1205 * @param poffset_local_extrafield where to store the offset of the local extrafield 1206 * @param psoze_local_extrafield where to store the size of the local extrafield 1207 * @return #EXTRACTOR_UNZIP_OK on success 1208 */ 1209 static int 1210 parse_current_file_coherency_header (struct EXTRACTOR_UnzipFile *file, 1211 uint32_t *piSizeVar, 1212 uint64_t *poffset_local_extrafield, 1213 uint16_t *psize_local_extrafield) 1214 { 1215 uint32_t uMagic; 1216 uint16_t u16; 1217 uint32_t u32; 1218 uint16_t uFlags; 1219 uint16_t size_filename; 1220 uint16_t size_extra_field; 1221 1222 *piSizeVar = 0; 1223 *poffset_local_extrafield = 0; 1224 *psize_local_extrafield = 0; 1225 1226 if (0 != ZSEEK (file->z_filefunc, 1227 (int64_t) (file->cur_file_info_internal.offset_curfile 1228 + file->byte_before_the_zipfile), 1229 SEEK_SET)) 1230 return EXTRACTOR_UNZIP_ERRNO; 1231 if (EXTRACTOR_UNZIP_OK != 1232 read_uint32_from_ffd (&file->z_filefunc, 1233 &uMagic)) 1234 return EXTRACTOR_UNZIP_ERRNO; 1235 if (0x04034b50 != uMagic) 1236 return EXTRACTOR_UNZIP_BADZIPFILE; 1237 if ( (EXTRACTOR_UNZIP_OK != 1238 read_uint16_from_ffd (&file->z_filefunc, &u16)) || /* version */ 1239 (EXTRACTOR_UNZIP_OK != 1240 read_uint16_from_ffd (&file->z_filefunc, &uFlags)) ) 1241 return EXTRACTOR_UNZIP_ERRNO; 1242 if (EXTRACTOR_UNZIP_OK != read_uint16_from_ffd (&file->z_filefunc, &u16)) 1243 return EXTRACTOR_UNZIP_ERRNO; 1244 if (u16 != file->cur_file_info.compression_method) 1245 return EXTRACTOR_UNZIP_BADZIPFILE; 1246 if ( (0 != file->cur_file_info.compression_method) && 1247 (Z_DEFLATED != file->cur_file_info.compression_method) ) 1248 return EXTRACTOR_UNZIP_BADZIPFILE; 1249 if (EXTRACTOR_UNZIP_OK != 1250 read_uint32_from_ffd (&file->z_filefunc, &u32)) /* date/time */ 1251 return EXTRACTOR_UNZIP_ERRNO; 1252 if (EXTRACTOR_UNZIP_OK != 1253 read_uint32_from_ffd (&file->z_filefunc, &u32)) /* crc */ 1254 return EXTRACTOR_UNZIP_ERRNO; 1255 if ( (u32 != file->cur_file_info.crc) && 1256 (0 == (uFlags & 8)) ) 1257 return EXTRACTOR_UNZIP_BADZIPFILE; 1258 if (EXTRACTOR_UNZIP_OK != 1259 read_uint32_from_ffd (&file->z_filefunc, &u32)) /* size compr */ 1260 return EXTRACTOR_UNZIP_ERRNO; 1261 if ( (u32 != file->cur_file_info.compressed_size) && 1262 (0 == (uFlags & 8)) ) 1263 return EXTRACTOR_UNZIP_BADZIPFILE; 1264 if (EXTRACTOR_UNZIP_OK != 1265 read_uint32_from_ffd (&file->z_filefunc, 1266 &u32)) /* size uncompr */ 1267 return EXTRACTOR_UNZIP_ERRNO; 1268 if ( (u32 != file->cur_file_info.uncompressed_size) && 1269 (0 == (uFlags & 8))) 1270 return EXTRACTOR_UNZIP_BADZIPFILE; 1271 if (EXTRACTOR_UNZIP_OK != 1272 read_uint16_from_ffd (&file->z_filefunc, &size_filename)) 1273 return EXTRACTOR_UNZIP_ERRNO; 1274 if (size_filename != file->cur_file_info.size_filename) 1275 return EXTRACTOR_UNZIP_BADZIPFILE; 1276 *piSizeVar += size_filename; 1277 if (EXTRACTOR_UNZIP_OK != 1278 read_uint16_from_ffd (&file->z_filefunc, 1279 &size_extra_field)) 1280 return EXTRACTOR_UNZIP_ERRNO; 1281 *poffset_local_extrafield = (uint64_t) file->cur_file_info_internal. 1282 offset_curfile 1283 + SIZEZIPLOCALHEADER + size_filename; 1284 *psize_local_extrafield = size_extra_field; 1285 *piSizeVar += size_extra_field; 1286 1287 return EXTRACTOR_UNZIP_OK; 1288 } 1289 1290 1291 /** 1292 * Open for reading data the current file in the zipfile. 1293 * 1294 * @param file zipfile to manipulate 1295 * @return #EXTRACTOR_UNZIP_OK on success 1296 */ 1297 int 1298 EXTRACTOR_common_unzip_open_current_file (struct EXTRACTOR_UnzipFile *file) 1299 { 1300 int err; 1301 uint32_t iSizeVar; 1302 struct FileInZipReadInfo *pfile_in_zip_read_info; 1303 uint64_t offset_local_extrafield; /* offset of the local extra field */ 1304 uint16_t size_local_extrafield; /* size of the local extra field */ 1305 1306 if (NULL == file) 1307 return EXTRACTOR_UNZIP_PARAMERROR; 1308 if (! file->current_file_ok) 1309 return EXTRACTOR_UNZIP_PARAMERROR; 1310 if (NULL != file->pfile_in_zip_read) 1311 EXTRACTOR_common_unzip_close_current_file (file); 1312 if (EXTRACTOR_UNZIP_OK != 1313 parse_current_file_coherency_header (file, 1314 &iSizeVar, 1315 &offset_local_extrafield, 1316 &size_local_extrafield)) 1317 return EXTRACTOR_UNZIP_BADZIPFILE; 1318 if (NULL == (pfile_in_zip_read_info 1319 = malloc (sizeof(struct FileInZipReadInfo)))) 1320 return EXTRACTOR_UNZIP_INTERNALERROR; 1321 if (NULL == (pfile_in_zip_read_info->read_buffer = malloc (UNZ_BUFSIZE))) 1322 { 1323 free (pfile_in_zip_read_info); 1324 return EXTRACTOR_UNZIP_INTERNALERROR; 1325 } 1326 pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; 1327 pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; 1328 pfile_in_zip_read_info->pos_local_extrafield = 0; 1329 pfile_in_zip_read_info->stream_initialised = 0; 1330 1331 if ( (0 != file->cur_file_info.compression_method) && 1332 (Z_DEFLATED != file->cur_file_info.compression_method) ) 1333 { 1334 // err = EXTRACTOR_UNZIP_BADZIPFILE; 1335 // FIXME: we don't do anything with this 'err' code. 1336 // Can this happen? Should we abort in this case? 1337 } 1338 1339 pfile_in_zip_read_info->crc32_wait = file->cur_file_info.crc; 1340 pfile_in_zip_read_info->crc32 = 0; 1341 pfile_in_zip_read_info->compression_method = 1342 file->cur_file_info.compression_method; 1343 pfile_in_zip_read_info->z_filefunc = file->z_filefunc; 1344 pfile_in_zip_read_info->byte_before_the_zipfile = 1345 file->byte_before_the_zipfile; 1346 pfile_in_zip_read_info->stream.total_out = 0; 1347 if (Z_DEFLATED == file->cur_file_info.compression_method) 1348 { 1349 pfile_in_zip_read_info->stream.zalloc = (alloc_func) NULL; 1350 pfile_in_zip_read_info->stream.zfree = (free_func) NULL; 1351 pfile_in_zip_read_info->stream.opaque = NULL; 1352 pfile_in_zip_read_info->stream.next_in = NULL; 1353 pfile_in_zip_read_info->stream.avail_in = 0; 1354 if (Z_OK != (err = inflateInit2 (&pfile_in_zip_read_info->stream, 1355 -MAX_WBITS))) 1356 { 1357 free (pfile_in_zip_read_info->read_buffer); 1358 free (pfile_in_zip_read_info); 1359 return err; 1360 } 1361 pfile_in_zip_read_info->stream_initialised = 1; 1362 /* windowBits is passed < 0 to tell that there is no zlib header. 1363 * Note that in this case inflate *requires* an extra "dummy" byte 1364 * after the compressed stream in order to complete decompression and 1365 * return Z_STREAM_END. 1366 * In unzip, i don't wait absolutely Z_STREAM_END because I known the 1367 * size of both compressed and uncompressed data 1368 */} 1369 pfile_in_zip_read_info->rest_read_compressed = 1370 file->cur_file_info.compressed_size; 1371 pfile_in_zip_read_info->rest_read_uncompressed = 1372 file->cur_file_info.uncompressed_size; 1373 pfile_in_zip_read_info->pos_in_zipfile = 1374 file->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER 1375 + iSizeVar; 1376 pfile_in_zip_read_info->stream.avail_in = 0; 1377 file->pfile_in_zip_read = pfile_in_zip_read_info; 1378 return EXTRACTOR_UNZIP_OK; 1379 } 1380 1381 1382 /** 1383 * Callback to perform read operation using LE API. 1384 * Note that partial reads are not allowed. 1385 * 1386 * @param opaque the 'struct EXTRACTOR_ExtractContext' 1387 * @param buf where to write bytes read 1388 * @param size number of bytes desired 1389 * @return number of bytes copied to buf 1390 */ 1391 static size_t 1392 ec_read_file_func (void *opaque, 1393 void *buf, 1394 size_t size) 1395 { 1396 struct EXTRACTOR_ExtractContext *ec = opaque; 1397 void *ptr; 1398 ssize_t ret; 1399 size_t done; 1400 1401 done = 0; 1402 while (done < size) 1403 { 1404 ret = ec->read (ec->cls, 1405 &ptr, 1406 size - done); 1407 if (ret <= 0) 1408 return done; 1409 /* the contract says a read never returns more than was asked for, 1410 but this is the memcpy() that would run off the end of @a buf if 1411 some data source ever got that wrong */ 1412 if ((size_t) ret > size - done) 1413 ret = (ssize_t) (size - done); 1414 memcpy ((char *) buf + done, 1415 ptr, 1416 (size_t) ret); 1417 done += (size_t) ret; 1418 } 1419 return done; 1420 } 1421 1422 1423 /** 1424 * Callback to obtain current offset in file using LE API. 1425 * 1426 * @param opaque the 'struct EXTRACTOR_ExtractContext' 1427 * @return current offset in file, -1 on error 1428 */ 1429 static int64_t 1430 ec_tell_file_func (void *opaque) 1431 { 1432 struct EXTRACTOR_ExtractContext *ec = opaque; 1433 1434 return ec->seek (ec->cls, 1435 0, 1436 SEEK_CUR); 1437 } 1438 1439 1440 /** 1441 * Callback to perform seek operation using LE API. 1442 * 1443 * @param opaque the 'struct EXTRACTOR_ExtractContext' 1444 * @param offset where to seek 1445 * @param whence relative to where should we seek 1446 * @return #EXTRACTOR_UNZIP_OK on success 1447 */ 1448 static int 1449 ec_seek_file_func (void *opaque, 1450 int64_t offset, 1451 int whence) 1452 { 1453 struct EXTRACTOR_ExtractContext *ec = opaque; 1454 1455 if (-1 == ec->seek (ec->cls, offset, whence)) 1456 return EXTRACTOR_UNZIP_INTERNALERROR; 1457 return EXTRACTOR_UNZIP_OK; 1458 } 1459 1460 1461 /** 1462 * Open a zip file for processing using the data access 1463 * functions from the extract context. 1464 * 1465 * @param ec extract context to use 1466 * @return handle to zip data, NULL on error 1467 */ 1468 struct EXTRACTOR_UnzipFile * 1469 EXTRACTOR_common_unzip_open (struct EXTRACTOR_ExtractContext *ec) 1470 { 1471 struct FileFuncDefs ffd; 1472 1473 ffd.zread_file = &ec_read_file_func; 1474 ffd.ztell_file = &ec_tell_file_func; 1475 ffd.zseek_file = &ec_seek_file_func; 1476 ffd.opaque = ec; 1477 1478 return unzip_open_using_ffd (&ffd); 1479 } 1480 1481 1482 /* end of unzip.c */