Unzip.cpp (33696B)
1 #include "../idlib/precompiled.h" 2 #pragma hdrstop 3 4 #include "Unzip.h" 5 6 /* unzip.h -- IO for uncompress .zip files using zlib 7 Version 0.15 beta, Mar 19th, 1998, 8 9 Copyright (C) 1998 Gilles Vollant 10 11 This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g 12 WinZip, InfoZip tools and compatible. 13 Encryption and multi volume ZipFile (span) are not supported. 14 Old compressions used by old PKZip 1.x are not supported 15 16 THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE 17 CAN CHANGE IN FUTURE VERSION !! 18 I WAIT FEEDBACK at mail info@winimage.com 19 Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution 20 21 Condition of use and distribution are the same than zlib : 22 23 This software is provided 'as-is', without any express or implied 24 warranty. In no event will the authors be held liable for any damages 25 arising from the use of this software. 26 27 Permission is granted to anyone to use this software for any purpose, 28 including commercial applications, and to alter it and redistribute it 29 freely, subject to the following restrictions: 30 31 1. The origin of this software must not be misrepresented; you must not 32 claim that you wrote the original software. If you use this software 33 in a product, an acknowledgment in the product documentation would be 34 appreciated but is not required. 35 2. Altered source versions must be plainly marked as such, and must not be 36 misrepresented as being the original software. 37 3. This notice may not be removed or altered from any source distribution. 38 39 40 */ 41 /* for more info about .ZIP format, see 42 ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip 43 PkWare has also a specification at : 44 ftp://ftp.pkware.com/probdesc.zip */ 45 46 47 #if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ 48 !defined(CASESENSITIVITYDEFAULT_NO) 49 #define CASESENSITIVITYDEFAULT_NO 50 #endif 51 52 53 #ifndef UNZ_BUFSIZE 54 #define UNZ_BUFSIZE (65536) 55 #endif 56 57 #ifndef UNZ_MAXFILENAMEINZIP 58 #define UNZ_MAXFILENAMEINZIP (256) 59 #endif 60 61 #ifndef ALLOC 62 # define ALLOC(size) (Mem_Alloc(size, TAG_IDFILE)) 63 #endif 64 #ifndef TRYFREE 65 # define TRYFREE(p) {if (p) Mem_Free(p);} 66 #endif 67 68 #define SIZECENTRALDIRITEM (0x2e) 69 #define SIZEZIPLOCALHEADER (0x1e) 70 71 72 idCVar zip_numSeeks( "zip_numSeeks", "0", CVAR_INTEGER, "" ); 73 idCVar zip_skippedSeeks( "zip_skippedSeeks", "0", CVAR_INTEGER, "" ); 74 idCVar zip_seeksForward( "zip_seeksForward", "0", CVAR_INTEGER, "" ); 75 idCVar zip_seeksBackward( "zip_seeksBackward", "0", CVAR_INTEGER, "" ); 76 idCVar zip_avgSeekDistance( "zip_avgSeekDistance", "0", CVAR_INTEGER, "" ); 77 78 /* =========================================================================== 79 Read a byte from a gz_stream; update next_in and avail_in. Return EOF 80 for end of file. 81 IN assertion: the stream s has been sucessfully opened for reading. 82 */ 83 84 /* 85 static int unzlocal_getByte(FILE *fin,int *pi) 86 { 87 unsigned char c; 88 int err = fread(&c, 1, 1, fin); 89 if (err==1) 90 { 91 *pi = (int)c; 92 return UNZ_OK; 93 } 94 else 95 { 96 if (ferror(fin)) 97 return UNZ_ERRNO; 98 else 99 return UNZ_EOF; 100 } 101 } 102 */ 103 104 105 /* =========================================================================== 106 Reads a long in LSB order from the given gz_stream. Sets 107 */ 108 static int unzlocal_getShort (idFile * fin, uLong *pX) 109 { 110 byte s[2]; 111 if ( fin->Read( s, 2 ) != 2 ) { 112 *pX = 0; 113 return UNZ_EOF; 114 } 115 *pX = ( s[1] << 8 ) | s[0]; 116 return UNZ_OK; 117 } 118 119 static int unzlocal_getLong (idFile * fin, uLong *pX) 120 { 121 byte s[4]; 122 if ( fin->Read( s, 4 ) != 4 ) { 123 *pX = 0; 124 return UNZ_EOF; 125 } 126 *pX = ( s[3] << 24 ) | ( s[2] << 16 ) | ( s[1] << 8 ) | s[0]; 127 return UNZ_OK; 128 } 129 130 131 /* My own strcmpi / strcasecmp */ 132 static int strcmpcasenosensitive_internal (const char* fileName1,const char* fileName2) 133 { 134 for (;;) 135 { 136 char c1=*(fileName1++); 137 char c2=*(fileName2++); 138 if ((c1>='a') && (c1<='z')) 139 c1 -= 0x20; 140 if ((c2>='a') && (c2<='z')) 141 c2 -= 0x20; 142 if (c1=='\0') 143 return ((c2=='\0') ? 0 : -1); 144 if (c2=='\0') 145 return 1; 146 if (c1<c2) 147 return -1; 148 if (c1>c2) 149 return 1; 150 } 151 } 152 153 154 #ifdef CASESENSITIVITYDEFAULT_NO 155 #define CASESENSITIVITYDEFAULTVALUE 2 156 #else 157 #define CASESENSITIVITYDEFAULTVALUE 1 158 #endif 159 160 #ifndef STRCMPCASENOSENTIVEFUNCTION 161 #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal 162 #endif 163 164 /* 165 Compare two filename (fileName1,fileName2). 166 If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) 167 If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi 168 or strcasecmp) 169 If iCaseSenisivity = 0, case sensitivity is defaut of your operating system 170 (like 1 on Unix, 2 on Windows) 171 172 */ 173 extern int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity) 174 { 175 if (iCaseSensitivity==0) 176 iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; 177 178 if (iCaseSensitivity==1) 179 return strcmp(fileName1,fileName2); 180 181 return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); 182 } 183 184 #define BUFREADCOMMENT (0x400) 185 186 /* 187 Locate the Central directory of a zipfile (at the end, just before 188 the global comment) 189 */ 190 static uLong unzlocal_SearchCentralDir(idFile * fin) 191 { 192 unsigned char* buf; 193 uLong uSizeFile; 194 uLong uBackRead; 195 uLong uMaxBack=0xffff; /* maximum size of global comment */ 196 uLong uPosFound=0; 197 198 if ( fin->Seek( 0, FS_SEEK_END ) != 0 ) 199 return 0; 200 201 uSizeFile = fin->Tell(); 202 203 if (uMaxBack>uSizeFile) 204 uMaxBack = uSizeFile; 205 206 buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); 207 if (buf==NULL) 208 return 0; 209 210 uBackRead = 4; 211 while (uBackRead<uMaxBack) 212 { 213 uLong uReadSize,uReadPos ; 214 int i; 215 if (uBackRead+BUFREADCOMMENT>uMaxBack) 216 uBackRead = uMaxBack; 217 else 218 uBackRead+=BUFREADCOMMENT; 219 uReadPos = uSizeFile-uBackRead ; 220 221 uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? 222 (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); 223 224 if ( fin->Seek( uReadPos, FS_SEEK_SET ) != 0 ) 225 break; 226 227 if ( fin->Read( buf, uReadSize ) != (int)uReadSize ) 228 break; 229 230 for (i=(int)uReadSize-3; (i--)>0;) 231 if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && 232 ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) 233 { 234 uPosFound = uReadPos+i; 235 break; 236 } 237 238 if (uPosFound!=0) 239 break; 240 } 241 TRYFREE(buf); 242 return uPosFound; 243 } 244 245 extern unzFile unzReOpen (const char* path, unzFile file) 246 { 247 unz_s *s; 248 idFile_Cached * fin; 249 250 fin = fileSystem->OpenExplicitPakFile( path ); 251 if (fin==NULL) 252 return NULL; 253 254 s=(unz_s*)ALLOC(sizeof(unz_s)); 255 memcpy(s, (unz_s*)file, sizeof(unz_s)); 256 257 s->file = fin; 258 s->pfile_in_zip_read = NULL; 259 260 return (unzFile)s; 261 } 262 263 /* 264 Open a Zip file. path contain the full pathname (by example, 265 on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer 266 "zlib/zlib109.zip". 267 If the zipfile cannot be opened (file don't exist or in not valid), the 268 return value is NULL. 269 Else, the return value is a unzFile Handle, usable with other function 270 of this unzip package. 271 */ 272 extern unzFile unzOpen (const char* path) 273 { 274 unz_s us; 275 unz_s *s; 276 uLong central_pos,uL; 277 idFile_Cached * fin ; 278 279 uLong number_disk; /* number of the current dist, used for 280 spaning ZIP, unsupported, always 0*/ 281 uLong number_disk_with_CD; /* number the the disk with central dir, used 282 for spaning ZIP, unsupported, always 0*/ 283 uLong number_entry_CD; /* total number of entries in 284 the central dir 285 (same than number_entry on nospan) */ 286 287 int err=UNZ_OK; 288 289 fin = fileSystem->OpenExplicitPakFile( path ); 290 if (fin==NULL) 291 return NULL; 292 293 central_pos = unzlocal_SearchCentralDir(fin); 294 if (central_pos==0) 295 err=UNZ_ERRNO; 296 297 if ( fin->Seek( central_pos, FS_SEEK_SET ) != 0 ) 298 err = UNZ_ERRNO; 299 300 /* the signature, already checked */ 301 if (unzlocal_getLong(fin,&uL)!=UNZ_OK) 302 err=UNZ_ERRNO; 303 304 /* number of this disk */ 305 if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) 306 err=UNZ_ERRNO; 307 308 /* number of the disk with the start of the central directory */ 309 if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) 310 err=UNZ_ERRNO; 311 312 /* total number of entries in the central dir on this disk */ 313 if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) 314 err=UNZ_ERRNO; 315 316 /* total number of entries in the central dir */ 317 if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) 318 err=UNZ_ERRNO; 319 320 if ((number_entry_CD!=us.gi.number_entry) || 321 (number_disk_with_CD!=0) || 322 (number_disk!=0)) 323 err=UNZ_BADZIPFILE; 324 325 /* size of the central directory */ 326 if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) 327 err=UNZ_ERRNO; 328 329 /* offset of start of central directory with respect to the 330 starting disk number */ 331 if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) 332 err=UNZ_ERRNO; 333 334 /* zipfile comment length */ 335 if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) 336 err=UNZ_ERRNO; 337 338 if ((central_pos<us.offset_central_dir+us.size_central_dir) && 339 (err==UNZ_OK)) 340 err=UNZ_BADZIPFILE; 341 342 if (err!=UNZ_OK) 343 { 344 fileSystem->CloseFile( fin ); 345 return NULL; 346 } 347 348 us.file=fin; 349 us.byte_before_the_zipfile = central_pos - 350 (us.offset_central_dir+us.size_central_dir); 351 us.central_pos = central_pos; 352 us.pfile_in_zip_read = NULL; 353 354 us.file->CacheData( us.offset_central_dir, us.size_central_dir ); 355 356 s=(unz_s*)ALLOC(sizeof(unz_s)); 357 *s=us; 358 359 // unzGoToFirstFile((unzFile)s); 360 return (unzFile)s; 361 } 362 363 364 /* 365 Close a ZipFile opened with unzipOpen. 366 If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), 367 these files MUST be closed with unzipCloseCurrentFile before call unzipClose. 368 return UNZ_OK if there is no problem. */ 369 extern int unzClose (unzFile file) 370 { 371 unz_s* s; 372 if (file==NULL) 373 return UNZ_PARAMERROR; 374 s=(unz_s*)file; 375 376 if (s->pfile_in_zip_read!=NULL) 377 unzCloseCurrentFile(file); 378 379 fileSystem->CloseFile( s->file ); 380 TRYFREE(s); 381 return UNZ_OK; 382 } 383 384 385 /* 386 Write info about the ZipFile in the *pglobal_info structure. 387 No preparation of the structure is needed 388 return UNZ_OK if there is no problem. */ 389 extern int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) 390 { 391 unz_s* s; 392 if (file==NULL) 393 return UNZ_PARAMERROR; 394 s=(unz_s*)file; 395 *pglobal_info=s->gi; 396 return UNZ_OK; 397 } 398 399 400 /* 401 Translate date/time from Dos format to tm_unz (readable more easilty) 402 */ 403 static void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) 404 { 405 uLong uDate; 406 uDate = (uLong)(ulDosDate>>16); 407 ptm->tm_mday = (uInt)(uDate&0x1f) ; 408 ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; 409 ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; 410 411 ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); 412 ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; 413 ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; 414 } 415 416 417 /* 418 Get Info about the current file in the zipfile, with internal only info 419 */ 420 static int unzlocal_GetCurrentFileInfoInternal (unzFile file, 421 unz_file_info *pfile_info, 422 unz_file_info_internal 423 *pfile_info_internal, 424 char *szFileName, 425 uLong fileNameBufferSize, 426 void *extraField, 427 uLong extraFieldBufferSize, 428 char *szComment, 429 uLong commentBufferSize) 430 { 431 unz_s* s; 432 unz_file_info file_info; 433 unz_file_info_internal file_info_internal; 434 int err=UNZ_OK; 435 uLong uMagic; 436 long lSeek=0; 437 438 if (file==NULL) 439 return UNZ_PARAMERROR; 440 s=(unz_s*)file; 441 442 int tellpos = s->file->Tell() - s->pos_in_central_dir + s->byte_before_the_zipfile; 443 if ( tellpos != 0 ) { 444 if ( s->file->Seek( s->pos_in_central_dir + s->byte_before_the_zipfile, FS_SEEK_SET ) != 0 ) { 445 err = UNZ_ERRNO; 446 } 447 if ( tellpos < 0 ) { 448 zip_seeksForward.SetInteger( zip_seeksForward.GetInteger() + 1 ); 449 } else { 450 zip_seeksBackward.SetInteger( zip_seeksBackward.GetInteger() + 1 ); 451 } 452 453 static long zip_totalSeekSize = 0; 454 if ( zip_numSeeks.GetInteger() == 0 ) { 455 zip_totalSeekSize = 0; 456 } 457 zip_totalSeekSize += abs( tellpos ); 458 459 zip_numSeeks.SetInteger( zip_numSeeks.GetInteger() + 1 ); 460 zip_avgSeekDistance.SetInteger( zip_totalSeekSize / zip_numSeeks.GetInteger() ); 461 } else { 462 zip_skippedSeeks.SetInteger( zip_skippedSeeks.GetInteger() + 1 ); 463 } 464 465 466 /* we check the magic */ 467 if (err==UNZ_OK) 468 if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) 469 err=UNZ_ERRNO; 470 else if (uMagic!=0x02014b50) 471 err=UNZ_BADZIPFILE; 472 473 if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) 474 err=UNZ_ERRNO; 475 476 if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) 477 err=UNZ_ERRNO; 478 479 if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) 480 err=UNZ_ERRNO; 481 482 if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) 483 err=UNZ_ERRNO; 484 485 if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) 486 err=UNZ_ERRNO; 487 488 unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); 489 490 if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) 491 err=UNZ_ERRNO; 492 493 if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) 494 err=UNZ_ERRNO; 495 496 if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) 497 err=UNZ_ERRNO; 498 499 if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) 500 err=UNZ_ERRNO; 501 502 if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) 503 err=UNZ_ERRNO; 504 505 if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) 506 err=UNZ_ERRNO; 507 508 if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) 509 err=UNZ_ERRNO; 510 511 if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) 512 err=UNZ_ERRNO; 513 514 if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) 515 err=UNZ_ERRNO; 516 517 if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) 518 err=UNZ_ERRNO; 519 520 lSeek+=file_info.size_filename; 521 if ((err==UNZ_OK) && (szFileName!=NULL)) 522 { 523 uLong uSizeRead ; 524 if (file_info.size_filename<fileNameBufferSize) 525 { 526 *(szFileName+file_info.size_filename)='\0'; 527 uSizeRead = file_info.size_filename; 528 } 529 else 530 uSizeRead = fileNameBufferSize; 531 532 if ((file_info.size_filename>0) && (fileNameBufferSize>0)) 533 if ( s->file->Read( szFileName, uSizeRead ) != (int)uSizeRead ) 534 err=UNZ_ERRNO; 535 lSeek -= uSizeRead; 536 } 537 538 539 if ((err==UNZ_OK) && (extraField!=NULL)) 540 { 541 uLong uSizeRead ; 542 if (file_info.size_file_extra<extraFieldBufferSize) 543 uSizeRead = file_info.size_file_extra; 544 else 545 uSizeRead = extraFieldBufferSize; 546 547 if (lSeek!=0) 548 if ( s->file->Seek( lSeek, FS_SEEK_CUR ) == 0 ) 549 lSeek=0; 550 else 551 err=UNZ_ERRNO; 552 if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) 553 if ( s->file->Read( extraField, uSizeRead ) != (int)uSizeRead ) 554 err=UNZ_ERRNO; 555 lSeek += file_info.size_file_extra - uSizeRead; 556 } 557 else 558 lSeek+=file_info.size_file_extra; 559 560 561 if ((err==UNZ_OK) && (szComment!=NULL)) 562 { 563 uLong uSizeRead ; 564 if (file_info.size_file_comment<commentBufferSize) 565 { 566 *(szComment+file_info.size_file_comment)='\0'; 567 uSizeRead = file_info.size_file_comment; 568 } 569 else 570 uSizeRead = commentBufferSize; 571 572 if (lSeek!=0) 573 if ( s->file->Seek( lSeek, FS_SEEK_CUR ) == 0 ) 574 lSeek=0; 575 else 576 err=UNZ_ERRNO; 577 if ((file_info.size_file_comment>0) && (commentBufferSize>0)) 578 if ( s->file->Read( szComment, uSizeRead ) != (int)uSizeRead ) 579 err=UNZ_ERRNO; 580 lSeek+=file_info.size_file_comment - uSizeRead; 581 } 582 else 583 lSeek+=file_info.size_file_comment; 584 585 if ((err==UNZ_OK) && (pfile_info!=NULL)) 586 *pfile_info=file_info; 587 588 if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) 589 *pfile_info_internal=file_info_internal; 590 591 return err; 592 } 593 594 /* 595 Write info about the ZipFile in the *pglobal_info structure. 596 No preparation of the structure is needed 597 return UNZ_OK if there is no problem. 598 */ 599 extern int unzGetCurrentFileInfo ( unzFile file, unz_file_info *pfile_info, 600 char *szFileName, uLong fileNameBufferSize, 601 void *extraField, uLong extraFieldBufferSize, 602 char *szComment, uLong commentBufferSize) 603 { 604 return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, 605 szFileName,fileNameBufferSize, 606 extraField,extraFieldBufferSize, 607 szComment,commentBufferSize); 608 } 609 610 /* 611 Set the current file of the zipfile to the first file. 612 return UNZ_OK if there is no problem 613 */ 614 extern int unzGoToFirstFile (unzFile file) 615 { 616 int err=UNZ_OK; 617 unz_s* s; 618 if (file==NULL) 619 return UNZ_PARAMERROR; 620 s=(unz_s*)file; 621 s->pos_in_central_dir=s->offset_central_dir; 622 s->num_file=0; 623 err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, 624 &s->cur_file_info_internal, 625 NULL,0,NULL,0,NULL,0); 626 s->current_file_ok = (err == UNZ_OK); 627 return err; 628 } 629 630 /* 631 Set the current file of the zipfile to the next file. 632 return UNZ_OK if there is no problem 633 return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. 634 */ 635 extern int unzGoToNextFile (unzFile file) 636 { 637 unz_s* s; 638 int err; 639 640 if (file==NULL) 641 return UNZ_PARAMERROR; 642 s=(unz_s*)file; 643 if (!s->current_file_ok) 644 return UNZ_END_OF_LIST_OF_FILE; 645 if (s->num_file+1==s->gi.number_entry) 646 return UNZ_END_OF_LIST_OF_FILE; 647 648 s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + 649 s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; 650 s->num_file++; 651 err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, 652 &s->cur_file_info_internal, 653 NULL,0,NULL,0,NULL,0); 654 s->current_file_ok = (err == UNZ_OK); 655 return err; 656 } 657 658 /* 659 Get the position of the info of the current file in the zip. 660 return UNZ_OK if there is no problem 661 */ 662 extern int unzGetCurrentFileInfoPosition (unzFile file, unsigned long *pos ) 663 { 664 unz_s* s; 665 666 if (file==NULL) 667 return UNZ_PARAMERROR; 668 s=(unz_s*)file; 669 670 *pos = s->pos_in_central_dir; 671 return UNZ_OK; 672 } 673 674 /* 675 Set the position of the info of the current file in the zip. 676 return UNZ_OK if there is no problem 677 */ 678 extern int unzSetCurrentFileInfoPosition (unzFile file, unsigned long pos ) 679 { 680 unz_s* s; 681 int err; 682 683 if (file==NULL) 684 return UNZ_PARAMERROR; 685 s=(unz_s*)file; 686 687 s->pos_in_central_dir = pos; 688 err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, 689 &s->cur_file_info_internal, 690 NULL,0,NULL,0,NULL,0); 691 s->current_file_ok = (err == UNZ_OK); 692 return UNZ_OK; 693 } 694 695 /* 696 Try locate the file szFileName in the zipfile. 697 For the iCaseSensitivity signification, see unzipStringFileNameCompare 698 699 return value : 700 UNZ_OK if the file is found. It becomes the current file. 701 UNZ_END_OF_LIST_OF_FILE if the file is not found 702 */ 703 extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) 704 { 705 unz_s* s; 706 int err; 707 708 709 uLong num_fileSaved; 710 uLong pos_in_central_dirSaved; 711 712 713 if (file==NULL) 714 return UNZ_PARAMERROR; 715 716 if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) 717 return UNZ_PARAMERROR; 718 719 s=(unz_s*)file; 720 if (!s->current_file_ok) 721 return UNZ_END_OF_LIST_OF_FILE; 722 723 num_fileSaved = s->num_file; 724 pos_in_central_dirSaved = s->pos_in_central_dir; 725 726 err = unzGoToFirstFile(file); 727 728 while (err == UNZ_OK) 729 { 730 char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; 731 unzGetCurrentFileInfo(file,NULL, 732 szCurrentFileName,sizeof(szCurrentFileName)-1, 733 NULL,0,NULL,0); 734 if (unzStringFileNameCompare(szCurrentFileName, 735 szFileName,iCaseSensitivity)==0) 736 return UNZ_OK; 737 err = unzGoToNextFile(file); 738 } 739 740 s->num_file = num_fileSaved ; 741 s->pos_in_central_dir = pos_in_central_dirSaved ; 742 return err; 743 } 744 745 746 /* 747 Read the static header of the current zipfile 748 Check the coherency of the static header and info in the end of central 749 directory about this file 750 store in *piSizeVar the size of extra info in static header 751 (filename and size of extra field data) 752 */ 753 static int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar, 754 uLong *poffset_local_extrafield, 755 uInt *psize_local_extrafield) 756 { 757 uLong uMagic,uData,uFlags; 758 uLong size_filename; 759 uLong size_extra_field; 760 int err=UNZ_OK; 761 762 *piSizeVar = 0; 763 *poffset_local_extrafield = 0; 764 *psize_local_extrafield = 0; 765 766 if ( s->file->Seek( s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile, FS_SEEK_SET ) != 0 ) 767 return UNZ_ERRNO; 768 769 770 if (err==UNZ_OK) 771 if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) 772 err=UNZ_ERRNO; 773 else if (uMagic!=0x04034b50) 774 err=UNZ_BADZIPFILE; 775 776 if (unzlocal_getShort(s->file,&uData) != UNZ_OK) 777 err=UNZ_ERRNO; 778 /* 779 else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) 780 err=UNZ_BADZIPFILE; 781 */ 782 if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) 783 err=UNZ_ERRNO; 784 785 if (unzlocal_getShort(s->file,&uData) != UNZ_OK) 786 err=UNZ_ERRNO; 787 else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) 788 err=UNZ_BADZIPFILE; 789 790 if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && 791 (s->cur_file_info.compression_method!=Z_DEFLATED)) 792 err=UNZ_BADZIPFILE; 793 794 if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ 795 err=UNZ_ERRNO; 796 797 if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ 798 err=UNZ_ERRNO; 799 else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && 800 ((uFlags & 8)==0)) 801 err=UNZ_BADZIPFILE; 802 803 if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ 804 err=UNZ_ERRNO; 805 else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && 806 ((uFlags & 8)==0)) 807 err=UNZ_BADZIPFILE; 808 809 if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ 810 err=UNZ_ERRNO; 811 else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && 812 ((uFlags & 8)==0)) 813 err=UNZ_BADZIPFILE; 814 815 816 if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) 817 err=UNZ_ERRNO; 818 else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) 819 err=UNZ_BADZIPFILE; 820 821 *piSizeVar += (uInt)size_filename; 822 823 if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) 824 err=UNZ_ERRNO; 825 *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + 826 SIZEZIPLOCALHEADER + size_filename; 827 *psize_local_extrafield = (uInt)size_extra_field; 828 829 *piSizeVar += (uInt)size_extra_field; 830 831 return err; 832 } 833 834 /* 835 Open for reading data the current file in the zipfile. 836 If there is no error and the file is opened, the return value is UNZ_OK. 837 */ 838 extern int unzOpenCurrentFile (unzFile file) 839 { 840 int err=UNZ_OK; 841 int Store; 842 uInt iSizeVar; 843 unz_s* s; 844 file_in_zip_read_info_s* pfile_in_zip_read_info; 845 uLong offset_local_extrafield; /* offset of the static extra field */ 846 uInt size_local_extrafield; /* size of the static extra field */ 847 848 if (file==NULL) 849 return UNZ_PARAMERROR; 850 s=(unz_s*)file; 851 if (!s->current_file_ok) 852 return UNZ_PARAMERROR; 853 854 if (s->pfile_in_zip_read != NULL) 855 unzCloseCurrentFile(file); 856 857 if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, 858 &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) 859 return UNZ_BADZIPFILE; 860 861 pfile_in_zip_read_info = (file_in_zip_read_info_s*) 862 ALLOC(sizeof(file_in_zip_read_info_s)); 863 if (pfile_in_zip_read_info==NULL) 864 return UNZ_INTERNALERROR; 865 866 pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); 867 pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; 868 pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; 869 pfile_in_zip_read_info->pos_local_extrafield=0; 870 871 if (pfile_in_zip_read_info->read_buffer==NULL) 872 { 873 TRYFREE(pfile_in_zip_read_info); 874 return UNZ_INTERNALERROR; 875 } 876 877 pfile_in_zip_read_info->stream_initialised=0; 878 879 if ((s->cur_file_info.compression_method!=0) && 880 (s->cur_file_info.compression_method!=Z_DEFLATED)) 881 err=UNZ_BADZIPFILE; 882 Store = s->cur_file_info.compression_method==0; 883 884 pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; 885 pfile_in_zip_read_info->crc32=0; 886 pfile_in_zip_read_info->compression_method = 887 s->cur_file_info.compression_method; 888 pfile_in_zip_read_info->file=s->file; 889 pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; 890 891 pfile_in_zip_read_info->stream.total_out = 0; 892 893 if (!Store) 894 { 895 pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; 896 pfile_in_zip_read_info->stream.zfree = (free_func)0; 897 pfile_in_zip_read_info->stream.opaque = (voidp)0; 898 899 err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); 900 if (err == Z_OK) 901 pfile_in_zip_read_info->stream_initialised=1; 902 /* windowBits is passed < 0 to tell that there is no zlib header. 903 * Note that in this case inflate *requires* an extra "dummy" byte 904 * after the compressed stream in order to complete decompression and 905 * return Z_STREAM_END. 906 * In unzip, i don't wait absolutely Z_STREAM_END because I known the 907 * size of both compressed and uncompressed data 908 */ 909 } 910 pfile_in_zip_read_info->rest_read_compressed = 911 s->cur_file_info.compressed_size ; 912 pfile_in_zip_read_info->rest_read_uncompressed = 913 s->cur_file_info.uncompressed_size ; 914 915 916 pfile_in_zip_read_info->pos_in_zipfile = 917 s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + 918 iSizeVar; 919 920 pfile_in_zip_read_info->stream.avail_in = (uInt)0; 921 922 923 s->pfile_in_zip_read = pfile_in_zip_read_info; 924 return UNZ_OK; 925 } 926 927 928 /* 929 Read bytes from the current file. 930 buf contain buffer where data must be copied 931 len the size of buf. 932 933 return the number of byte copied if somes bytes are copied 934 return 0 if the end of file was reached 935 return <0 with error code if there is an error 936 (UNZ_ERRNO for IO error, or zLib error for uncompress error) 937 */ 938 extern int unzReadCurrentFile (unzFile file, void *buf, unsigned len) 939 { 940 int err=UNZ_OK; 941 uInt iRead = 0; 942 unz_s* s; 943 file_in_zip_read_info_s* pfile_in_zip_read_info; 944 if (file==NULL) 945 return UNZ_PARAMERROR; 946 s=(unz_s*)file; 947 pfile_in_zip_read_info=s->pfile_in_zip_read; 948 949 if (pfile_in_zip_read_info==NULL) 950 return UNZ_PARAMERROR; 951 952 953 if ((pfile_in_zip_read_info->read_buffer == NULL)) 954 return UNZ_END_OF_LIST_OF_FILE; 955 if (len==0) 956 return 0; 957 958 pfile_in_zip_read_info->stream.next_out = (Byte*)buf; 959 960 pfile_in_zip_read_info->stream.avail_out = (uInt)len; 961 962 if (len>pfile_in_zip_read_info->rest_read_uncompressed) 963 pfile_in_zip_read_info->stream.avail_out = 964 (uInt)pfile_in_zip_read_info->rest_read_uncompressed; 965 966 while (pfile_in_zip_read_info->stream.avail_out>0) 967 { 968 if ((pfile_in_zip_read_info->stream.avail_in==0) && 969 (pfile_in_zip_read_info->rest_read_compressed>0)) 970 { 971 uInt uReadThis = UNZ_BUFSIZE; 972 if (pfile_in_zip_read_info->rest_read_compressed<uReadThis) 973 uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed; 974 if (uReadThis == 0) 975 return UNZ_EOF; 976 if (s->cur_file_info.compressed_size == pfile_in_zip_read_info->rest_read_compressed) 977 if ( pfile_in_zip_read_info->file->Seek( pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile, FS_SEEK_SET ) != 0 ) 978 return UNZ_ERRNO; 979 if ( pfile_in_zip_read_info->file->Read( pfile_in_zip_read_info->read_buffer, uReadThis ) != (int)uReadThis ) 980 return UNZ_ERRNO; 981 pfile_in_zip_read_info->pos_in_zipfile += uReadThis; 982 983 pfile_in_zip_read_info->rest_read_compressed-=uReadThis; 984 985 pfile_in_zip_read_info->stream.next_in = 986 (Byte*)pfile_in_zip_read_info->read_buffer; 987 pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; 988 } 989 990 if (pfile_in_zip_read_info->compression_method==0) 991 { 992 uInt uDoCopy,i ; 993 if (pfile_in_zip_read_info->stream.avail_out < 994 pfile_in_zip_read_info->stream.avail_in) 995 uDoCopy = pfile_in_zip_read_info->stream.avail_out ; 996 else 997 uDoCopy = pfile_in_zip_read_info->stream.avail_in ; 998 999 for (i=0;i<uDoCopy;i++) 1000 *(pfile_in_zip_read_info->stream.next_out+i) = 1001 *(pfile_in_zip_read_info->stream.next_in+i); 1002 1003 pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, 1004 pfile_in_zip_read_info->stream.next_out, 1005 uDoCopy); 1006 pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; 1007 pfile_in_zip_read_info->stream.avail_in -= uDoCopy; 1008 pfile_in_zip_read_info->stream.avail_out -= uDoCopy; 1009 pfile_in_zip_read_info->stream.next_out += uDoCopy; 1010 pfile_in_zip_read_info->stream.next_in += uDoCopy; 1011 pfile_in_zip_read_info->stream.total_out += uDoCopy; 1012 iRead += uDoCopy; 1013 } 1014 else 1015 { 1016 uLong uTotalOutBefore,uTotalOutAfter; 1017 const Byte *bufBefore; 1018 uLong uOutThis; 1019 int flush=Z_SYNC_FLUSH; 1020 1021 uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; 1022 bufBefore = pfile_in_zip_read_info->stream.next_out; 1023 1024 /* 1025 if ((pfile_in_zip_read_info->rest_read_uncompressed == 1026 pfile_in_zip_read_info->stream.avail_out) && 1027 (pfile_in_zip_read_info->rest_read_compressed == 0)) 1028 flush = Z_FINISH; 1029 */ 1030 err=inflate(&pfile_in_zip_read_info->stream,flush); 1031 1032 uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; 1033 uOutThis = uTotalOutAfter-uTotalOutBefore; 1034 1035 pfile_in_zip_read_info->crc32 = 1036 crc32(pfile_in_zip_read_info->crc32,bufBefore, 1037 (uInt)(uOutThis)); 1038 1039 pfile_in_zip_read_info->rest_read_uncompressed -= 1040 uOutThis; 1041 1042 iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); 1043 1044 if (err==Z_STREAM_END) 1045 return (iRead==0) ? UNZ_EOF : iRead; 1046 if (err!=Z_OK) 1047 break; 1048 } 1049 } 1050 1051 if (err==Z_OK) 1052 return iRead; 1053 return err; 1054 } 1055 1056 1057 /* 1058 Give the current position in uncompressed data 1059 */ 1060 extern long unztell (unzFile file) 1061 { 1062 unz_s* s; 1063 file_in_zip_read_info_s* pfile_in_zip_read_info; 1064 if (file==NULL) 1065 return UNZ_PARAMERROR; 1066 s=(unz_s*)file; 1067 pfile_in_zip_read_info=s->pfile_in_zip_read; 1068 1069 if (pfile_in_zip_read_info==NULL) 1070 return UNZ_PARAMERROR; 1071 1072 return (long)pfile_in_zip_read_info->stream.total_out; 1073 } 1074 1075 1076 /* 1077 return 1 if the end of file was reached, 0 elsewhere 1078 */ 1079 extern int unzeof (unzFile file) 1080 { 1081 unz_s* s; 1082 file_in_zip_read_info_s* pfile_in_zip_read_info; 1083 if (file==NULL) 1084 return UNZ_PARAMERROR; 1085 s=(unz_s*)file; 1086 pfile_in_zip_read_info=s->pfile_in_zip_read; 1087 1088 if (pfile_in_zip_read_info==NULL) 1089 return UNZ_PARAMERROR; 1090 1091 if (pfile_in_zip_read_info->rest_read_uncompressed == 0) 1092 return 1; 1093 else 1094 return 0; 1095 } 1096 1097 1098 1099 /* 1100 Read extra field from the current file (opened by unzOpenCurrentFile) 1101 This is the static-header version of the extra field (sometimes, there is 1102 more info in the static-header version than in the central-header) 1103 1104 if buf==NULL, it return the size of the static extra field that can be read 1105 1106 if buf!=NULL, len is the size of the buffer, the extra header is copied in 1107 buf. 1108 the return value is the number of bytes copied in buf, or (if <0) 1109 the error code 1110 */ 1111 extern int unzGetLocalExtrafield (unzFile file,void *buf,unsigned len) 1112 { 1113 unz_s* s; 1114 file_in_zip_read_info_s* pfile_in_zip_read_info; 1115 uInt read_now; 1116 uLong size_to_read; 1117 1118 if (file==NULL) 1119 return UNZ_PARAMERROR; 1120 s=(unz_s*)file; 1121 pfile_in_zip_read_info=s->pfile_in_zip_read; 1122 1123 if (pfile_in_zip_read_info==NULL) 1124 return UNZ_PARAMERROR; 1125 1126 size_to_read = (pfile_in_zip_read_info->size_local_extrafield - 1127 pfile_in_zip_read_info->pos_local_extrafield); 1128 1129 if (buf==NULL) 1130 return (int)size_to_read; 1131 1132 if (len>size_to_read) 1133 read_now = (uInt)size_to_read; 1134 else 1135 read_now = (uInt)len ; 1136 1137 if (read_now==0) 1138 return 0; 1139 1140 if ( pfile_in_zip_read_info->file->Seek( pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield, FS_SEEK_SET ) != 0 ) 1141 return UNZ_ERRNO; 1142 1143 if ( pfile_in_zip_read_info->file->Read( buf, size_to_read ) != (int)size_to_read ) 1144 return UNZ_ERRNO; 1145 1146 return (int)read_now; 1147 } 1148 1149 /* 1150 Close the file in zip opened with unzipOpenCurrentFile 1151 Return UNZ_CRCERROR if all the file was read but the CRC is not good 1152 */ 1153 extern int unzCloseCurrentFile (unzFile file) 1154 { 1155 int err=UNZ_OK; 1156 1157 unz_s* s; 1158 file_in_zip_read_info_s* pfile_in_zip_read_info; 1159 if (file==NULL) 1160 return UNZ_PARAMERROR; 1161 s=(unz_s*)file; 1162 pfile_in_zip_read_info=s->pfile_in_zip_read; 1163 1164 if (pfile_in_zip_read_info==NULL) 1165 return UNZ_PARAMERROR; 1166 1167 1168 if (pfile_in_zip_read_info->rest_read_uncompressed == 0) 1169 { 1170 if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) 1171 err=UNZ_CRCERROR; 1172 } 1173 1174 1175 TRYFREE(pfile_in_zip_read_info->read_buffer); 1176 pfile_in_zip_read_info->read_buffer = NULL; 1177 if (pfile_in_zip_read_info->stream_initialised) 1178 inflateEnd(&pfile_in_zip_read_info->stream); 1179 1180 pfile_in_zip_read_info->stream_initialised = 0; 1181 TRYFREE(pfile_in_zip_read_info); 1182 1183 s->pfile_in_zip_read=NULL; 1184 1185 return err; 1186 } 1187 1188 1189 /* 1190 Get the global comment string of the ZipFile, in the szComment buffer. 1191 uSizeBuf is the size of the szComment buffer. 1192 return the number of byte copied or an error code <0 1193 */ 1194 extern int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) 1195 { 1196 unz_s* s; 1197 uLong uReadThis ; 1198 if (file==NULL) 1199 return UNZ_PARAMERROR; 1200 s=(unz_s*)file; 1201 1202 uReadThis = uSizeBuf; 1203 if (uReadThis>s->gi.size_comment) 1204 uReadThis = s->gi.size_comment; 1205 1206 if ( s->file->Seek( s->central_pos + 22, FS_SEEK_SET ) == 0 ) 1207 return UNZ_ERRNO; 1208 1209 if (uReadThis>0) 1210 { 1211 if ( szComment == NULL ) { 1212 return (int)uReadThis; 1213 } 1214 *szComment='\0'; 1215 if ( s->file->Read( szComment, uReadThis ) != (int)uReadThis ) 1216 return UNZ_ERRNO; 1217 } 1218 1219 if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) 1220 *(szComment+s->gi.size_comment)='\0'; 1221 return (int)uReadThis; 1222 }