1/* 2 Copyright (c) 1990-2009 Info-ZIP. All rights reserved. 3 4 See the accompanying file LICENSE, version 2009-Jan-02 or later 5 (the contents of which are also included in unzip.h) for terms of use. 6 If, for some reason, all these files are missing, the Info-ZIP license 7 also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html 8*/ 9/*--------------------------------------------------------------------------- 10 11 api.c 12 13 This module supplies an UnZip engine for use directly from C/C++ 14 programs. The functions are: 15 16 ZCONST UzpVer *UzpVersion(void); 17 unsigned UzpVersion2(UzpVer2 *version) 18 int UzpMain(int argc, char *argv[]); 19 int UzpAltMain(int argc, char *argv[], UzpInit *init); 20 int UzpValidate(char *archive, int AllCodes); 21 void UzpFreeMemBuffer(UzpBuffer *retstr); 22 int UzpUnzipToMemory(char *zip, char *file, UzpOpts *optflgs, 23 UzpCB *UsrFuncts, UzpBuffer *retstr); 24 25 non-WINDLL only (a special WINDLL variant is defined in windll/windll.c): 26 int UzpGrep(char *archive, char *file, char *pattern, int cmd, int SkipBin, 27 UzpCB *UsrFuncts); 28 29 OS/2 only (for now): 30 int UzpFileTree(char *name, cbList(callBack), char *cpInclude[], 31 char *cpExclude[]); 32 33 You must define `DLL' in order to include the API extensions. 34 35 ---------------------------------------------------------------------------*/ 36 37 38#ifdef OS2 39# define INCL_DOSMEMMGR 40# include <os2.h> 41#endif 42 43#define UNZIP_INTERNAL 44#include "unzip.h" 45#ifdef WINDLL 46# ifdef POCKET_UNZIP 47# include "wince/intrface.h" 48# else 49# include "windll/windll.h" 50# endif 51#endif 52#include "unzvers.h" 53#include <setjmp.h> 54 55#ifdef DLL /* This source file supplies DLL-only interface code. */ 56 57#ifndef POCKET_UNZIP /* WinCE pUnZip defines this elsewhere. */ 58jmp_buf dll_error_return; 59#endif 60 61/*--------------------------------------------------------------------------- 62 Documented API entry points 63 ---------------------------------------------------------------------------*/ 64 65 66ZCONST UzpVer * UZ_EXP UzpVersion() /* returns pointer to const struct */ 67{ 68 static ZCONST UzpVer version = { /* doesn't change between calls */ 69 /* structure size */ 70 UZPVER_LEN, 71 /* version flags */ 72#ifdef BETA 73# ifdef ZLIB_VERSION 74 3, 75# else 76 1, 77# endif 78#else 79# ifdef ZLIB_VERSION 80 2, 81# else 82 0, 83# endif 84#endif 85 /* betalevel and date strings */ 86 UZ_BETALEVEL, UZ_VERSION_DATE, 87 /* zlib_version string */ 88#ifdef ZLIB_VERSION 89 ZLIB_VERSION, 90#else 91 NULL, 92#endif 93 /*== someday each of these may have a separate patchlevel: ==*/ 94 /* unzip version */ 95 {UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, 0}, 96 /* zipinfo version */ 97 {ZI_MAJORVER, ZI_MINORVER, UZ_PATCHLEVEL, 0}, 98 /* os2dll version (retained for backward compatibility) */ 99 {UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, 0}, 100 /* windll version (retained for backward compatibility)*/ 101 {UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, 0}, 102#ifdef OS2DLL 103 /* os2dll API minimum compatible version*/ 104 {UZ_OS2API_COMP_MAJOR, UZ_OS2API_COMP_MINOR, UZ_OS2API_COMP_REVIS, 0} 105#else /* !OS2DLL */ 106#ifdef WINDLL 107 /* windll API minimum compatible version*/ 108 {UZ_WINAPI_COMP_MAJOR, UZ_WINAPI_COMP_MINOR, UZ_WINAPI_COMP_REVIS, 0} 109#else /* !WINDLL */ 110 /* generic DLL API minimum compatible version*/ 111 {UZ_GENAPI_COMP_MAJOR, UZ_GENAPI_COMP_MINOR, UZ_GENAPI_COMP_REVIS, 0} 112#endif /* ?WINDLL */ 113#endif /* ?OS2DLL */ 114 }; 115 116 return &version; 117} 118 119unsigned UZ_EXP UzpVersion2(UzpVer2 *version) 120{ 121 122 if (version->structlen != sizeof(UzpVer2)) 123 return sizeof(UzpVer2); 124 125#ifdef BETA 126 version->flag = 1; 127#else 128 version->flag = 0; 129#endif 130 strcpy(version->betalevel, UZ_BETALEVEL); 131 strcpy(version->date, UZ_VERSION_DATE); 132 133#ifdef ZLIB_VERSION 134 /* Although ZLIB_VERSION is a compile-time constant, we implement an 135 "overrun-safe" copy because its actual value is not under our control. 136 */ 137 strncpy(version->zlib_version, ZLIB_VERSION, 138 sizeof(version->zlib_version) - 1); 139 version->zlib_version[sizeof(version->zlib_version) - 1] = '\0'; 140 version->flag |= 2; 141#else 142 version->zlib_version[0] = '\0'; 143#endif 144 145 /* someday each of these may have a separate patchlevel: */ 146 version->unzip.major = UZ_MAJORVER; 147 version->unzip.minor = UZ_MINORVER; 148 version->unzip.patchlevel = UZ_PATCHLEVEL; 149 150 version->zipinfo.major = ZI_MAJORVER; 151 version->zipinfo.minor = ZI_MINORVER; 152 version->zipinfo.patchlevel = UZ_PATCHLEVEL; 153 154 /* these are retained for backward compatibility only: */ 155 version->os2dll.major = UZ_MAJORVER; 156 version->os2dll.minor = UZ_MINORVER; 157 version->os2dll.patchlevel = UZ_PATCHLEVEL; 158 159 version->windll.major = UZ_MAJORVER; 160 version->windll.minor = UZ_MINORVER; 161 version->windll.patchlevel = UZ_PATCHLEVEL; 162 163#ifdef OS2DLL 164 /* os2dll API minimum compatible version*/ 165 version->dllapimin.major = UZ_OS2API_COMP_MAJOR; 166 version->dllapimin.minor = UZ_OS2API_COMP_MINOR; 167 version->dllapimin.patchlevel = UZ_OS2API_COMP_REVIS; 168#else /* !OS2DLL */ 169#ifdef WINDLL 170 /* windll API minimum compatible version*/ 171 version->dllapimin.major = UZ_WINAPI_COMP_MAJOR; 172 version->dllapimin.minor = UZ_WINAPI_COMP_MINOR; 173 version->dllapimin.patchlevel = UZ_WINAPI_COMP_REVIS; 174#else /* !WINDLL */ 175 /* generic DLL API minimum compatible version*/ 176 version->dllapimin.major = UZ_GENAPI_COMP_MAJOR; 177 version->dllapimin.minor = UZ_GENAPI_COMP_MINOR; 178 version->dllapimin.patchlevel = UZ_GENAPI_COMP_REVIS; 179#endif /* ?WINDLL */ 180#endif /* ?OS2DLL */ 181 return 0; 182} 183 184 185 186 187 188#ifndef SFX 189#ifndef WINDLL 190 191int UZ_EXP UzpAltMain(int argc, char *argv[], UzpInit *init) 192{ 193 int r, (*dummyfn)(); 194 195 196 CONSTRUCTGLOBALS(); 197 198 if (init->structlen >= (sizeof(ulg) + sizeof(dummyfn)) && init->msgfn) 199 G.message = init->msgfn; 200 201 if (init->structlen >= (sizeof(ulg) + 2*sizeof(dummyfn)) && init->inputfn) 202 G.input = init->inputfn; 203 204 if (init->structlen >= (sizeof(ulg) + 3*sizeof(dummyfn)) && init->pausefn) 205 G.mpause = init->pausefn; 206 207 if (init->structlen >= (sizeof(ulg) + 4*sizeof(dummyfn)) && init->userfn) 208 (*init->userfn)(); /* allow void* arg? */ 209 210 r = unzip(__G__ argc, argv); 211 DESTROYGLOBALS(); 212 RETURN(r); 213} 214 215#endif /* !WINDLL */ 216 217 218 219 220#ifndef __16BIT__ 221 222void UZ_EXP UzpFreeMemBuffer(UzpBuffer *retstr) 223{ 224 if (retstr != NULL && retstr->strptr != NULL) { 225 free(retstr->strptr); 226 retstr->strptr = NULL; 227 retstr->strlength = 0; 228 } 229} 230 231 232 233 234#ifndef WINDLL 235 236static int UzpDLL_Init OF((zvoid *pG, UzpCB *UsrFuncts)); 237 238static int UzpDLL_Init(pG, UsrFuncts) 239zvoid *pG; 240UzpCB *UsrFuncts; 241{ 242 int (*dummyfn)(); 243 244 if (UsrFuncts->structlen >= (sizeof(ulg) + sizeof(dummyfn)) && 245 UsrFuncts->msgfn) 246 ((Uz_Globs *)pG)->message = UsrFuncts->msgfn; 247 else 248 return FALSE; 249 250 if (UsrFuncts->structlen >= (sizeof(ulg) + 2*sizeof(dummyfn)) && 251 UsrFuncts->inputfn) 252 ((Uz_Globs *)pG)->input = UsrFuncts->inputfn; 253 254 if (UsrFuncts->structlen >= (sizeof(ulg) + 3*sizeof(dummyfn)) && 255 UsrFuncts->pausefn) 256 ((Uz_Globs *)pG)->mpause = UsrFuncts->pausefn; 257 258 if (UsrFuncts->structlen >= (sizeof(ulg) + 4*sizeof(dummyfn)) && 259 UsrFuncts->passwdfn) 260 ((Uz_Globs *)pG)->decr_passwd = UsrFuncts->passwdfn; 261 262 if (UsrFuncts->structlen >= (sizeof(ulg) + 5*sizeof(dummyfn)) && 263 UsrFuncts->statrepfn) 264 ((Uz_Globs *)pG)->statreportcb = UsrFuncts->statrepfn; 265 266 return TRUE; 267} 268 269 270int UZ_EXP UzpUnzipToMemory(char *zip, char *file, UzpOpts *optflgs, 271 UzpCB *UsrFuncts, UzpBuffer *retstr) 272{ 273 int r; 274#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO)) 275 char *intern_zip, *intern_file; 276#endif 277 278 CONSTRUCTGLOBALS(); 279#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO)) 280 intern_zip = (char *)malloc(strlen(zip)+1); 281 if (intern_zip == NULL) { 282 DESTROYGLOBALS(); 283 return PK_MEM; 284 } 285 intern_file = (char *)malloc(strlen(file)+1); 286 if (intern_file == NULL) { 287 DESTROYGLOBALS(); 288 free(intern_zip); 289 return PK_MEM; 290 } 291 ISO_TO_INTERN(zip, intern_zip); 292 ISO_TO_INTERN(file, intern_file); 293# define zip intern_zip 294# define file intern_file 295#endif 296 /* Copy those options that are meaningful for UzpUnzipToMemory, instead of 297 * a simple "memcpy(G.UzO, optflgs, sizeof(UzpOpts));" 298 */ 299 uO.pwdarg = optflgs->pwdarg; 300 uO.aflag = optflgs->aflag; 301 uO.C_flag = optflgs->C_flag; 302 uO.qflag = optflgs->qflag; /* currently, overridden in unzipToMemory */ 303 304 if (!UzpDLL_Init((zvoid *)&G, UsrFuncts)) { 305 DESTROYGLOBALS(); 306 return PK_BADERR; 307 } 308 G.redirect_data = 1; 309 310 r = (unzipToMemory(__G__ zip, file, retstr) <= PK_WARN); 311 312 DESTROYGLOBALS(); 313#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO)) 314# undef file 315# undef zip 316 free(intern_file); 317 free(intern_zip); 318#endif 319 if (!r && retstr->strlength) { 320 free(retstr->strptr); 321 retstr->strptr = NULL; 322 } 323 return r; 324} 325#endif /* !WINDLL */ 326#endif /* !__16BIT__ */ 327 328 329 330 331 332#ifdef OS2DLL 333 334int UZ_EXP UzpFileTree(char *name, cbList(callBack), char *cpInclude[], 335 char *cpExclude[]) 336{ 337 int r; 338 339 CONSTRUCTGLOBALS(); 340 uO.qflag = 2; 341 uO.vflag = 1; 342 uO.C_flag = 1; 343 G.wildzipfn = name; 344 G.process_all_files = TRUE; 345 if (cpInclude) { 346 char **ptr = cpInclude; 347 348 while (*ptr != NULL) ptr++; 349 G.filespecs = ptr - cpInclude; 350 G.pfnames = cpInclude, G.process_all_files = FALSE; 351 } 352 if (cpExclude) { 353 char **ptr = cpExclude; 354 355 while (*ptr != NULL) ptr++; 356 G.xfilespecs = ptr - cpExclude; 357 G.pxnames = cpExclude, G.process_all_files = FALSE; 358 } 359 360 G.processExternally = callBack; 361 r = process_zipfiles(__G)==0; 362 DESTROYGLOBALS(); 363 return r; 364} 365 366#endif /* OS2DLL */ 367#endif /* !SFX */ 368 369 370 371 372/*--------------------------------------------------------------------------- 373 Helper functions 374 ---------------------------------------------------------------------------*/ 375 376 377void setFileNotFound(__G) 378 __GDEF 379{ 380 G.filenotfound++; 381} 382 383 384#ifndef SFX 385 386int unzipToMemory(__GPRO__ char *zip, char *file, UzpBuffer *retstr) 387{ 388 int r; 389 char *incname[2]; 390 391 if ((zip == NULL) || (strlen(zip) > ((WSIZE>>2) - 160))) 392 return PK_PARAM; 393 if ((file == NULL) || (strlen(file) > ((WSIZE>>2) - 160))) 394 return PK_PARAM; 395 396 G.process_all_files = FALSE; 397 G.extract_flag = TRUE; 398 uO.qflag = 2; 399 G.wildzipfn = zip; 400 401 G.pfnames = incname; 402 incname[0] = file; 403 incname[1] = NULL; 404 G.filespecs = 1; 405 406 r = process_zipfiles(__G); 407 if (retstr) { 408 retstr->strptr = (char *)G.redirect_buffer; 409 retstr->strlength = G.redirect_size; 410 } 411 return r; /* returns `PK_???' error values */ 412} 413 414#endif /* !SFX */ 415 416/* 417 With the advent of 64 bit support, for now I am assuming that 418 if the size of the file is greater than an unsigned long, there 419 will simply not be enough memory to handle it, and am returning 420 FALSE. 421*/ 422int redirect_outfile(__G) 423 __GDEF 424{ 425#ifdef ZIP64_SUPPORT 426 __int64 check_conversion; 427#endif 428 429 if (G.redirect_size != 0 || G.redirect_buffer != NULL) 430 return FALSE; 431 432#ifndef NO_SLIDE_REDIR 433 G.redirect_slide = !G.pInfo->textmode; 434#endif 435#if (lenEOL != 1) 436 if (G.pInfo->textmode) { 437 G.redirect_size = (ulg)(G.lrec.ucsize * lenEOL); 438 if (G.redirect_size < G.lrec.ucsize) 439 G.redirect_size = (ulg)((G.lrec.ucsize > (ulg)-2L) ? 440 G.lrec.ucsize : -2L); 441#ifdef ZIP64_SUPPORT 442 check_conversion = G.lrec.ucsize * lenEOL; 443#endif 444 } else 445#endif 446 { 447 G.redirect_size = (ulg)G.lrec.ucsize; 448#ifdef ZIP64_SUPPORT 449 check_conversion = (__int64)G.lrec.ucsize; 450#endif 451 } 452 453#ifdef ZIP64_SUPPORT 454 if ((__int64)G.redirect_size != check_conversion) 455 return FALSE; 456#endif 457 458#ifdef __16BIT__ 459 if ((ulg)((extent)G.redirect_size) != G.redirect_size) 460 return FALSE; 461#endif 462#ifdef OS2 463 DosAllocMem((void **)&G.redirect_buffer, G.redirect_size+1, 464 PAG_READ|PAG_WRITE|PAG_COMMIT); 465 G.redirect_pointer = G.redirect_buffer; 466#else 467 G.redirect_pointer = 468 G.redirect_buffer = malloc((extent)(G.redirect_size+1)); 469#endif 470 if (!G.redirect_buffer) 471 return FALSE; 472 G.redirect_pointer[G.redirect_size] = '\0'; 473 return TRUE; 474} 475 476 477 478int writeToMemory(__GPRO__ ZCONST uch *rawbuf, extent size) 479{ 480 int errflg = FALSE; 481 482 if ((uch *)rawbuf != G.redirect_pointer) { 483 extent redir_avail = (G.redirect_buffer + G.redirect_size) - 484 G.redirect_pointer; 485 486 /* Check for output buffer overflow */ 487 if (size > redir_avail) { 488 /* limit transfer data to available space, set error return flag */ 489 size = redir_avail; 490 errflg = TRUE; 491 } 492 memcpy(G.redirect_pointer, rawbuf, size); 493 } 494 G.redirect_pointer += size; 495 return errflg; 496} 497 498 499 500 501int close_redirect(__G) 502 __GDEF 503{ 504 if (G.pInfo->textmode) { 505 *G.redirect_pointer = '\0'; 506 G.redirect_size = (ulg)(G.redirect_pointer - G.redirect_buffer); 507 if ((G.redirect_buffer = 508 realloc(G.redirect_buffer, G.redirect_size + 1)) == NULL) { 509 G.redirect_size = 0; 510 return EOF; 511 } 512 } 513 return 0; 514} 515 516 517 518 519#ifndef SFX 520#ifndef __16BIT__ 521#ifndef WINDLL 522 523/* Purpose: Determine if file in archive contains the string szSearch 524 525 Parameters: archive = archive name 526 file = file contained in the archive. This cannot be 527 a wildcard to be meaningful 528 pattern = string to search for 529 cmd = 0 - case-insensitive search 530 1 - case-sensitve search 531 2 - case-insensitive, whole words only 532 3 - case-sensitive, whole words only 533 SkipBin = if true, skip any files that have control 534 characters other than CR, LF, or tab in the first 535 100 characters. 536 537 Returns: TRUE if a match is found 538 FALSE if no match is found 539 -1 on error 540 541 Comments: This does not pretend to be as useful as the standard 542 Unix grep, which returns the strings associated with a 543 particular pattern, nor does it search past the first 544 matching occurrence of the pattern. 545 */ 546 547int UZ_EXP UzpGrep(char *archive, char *file, char *pattern, int cmd, 548 int SkipBin, UzpCB *UsrFuncts) 549{ 550 int retcode = FALSE, compare; 551 ulg i, j, patternLen, buflen; 552 char * sz, *p; 553 UzpOpts flgopts; 554 UzpBuffer retstr; 555 556 memzero(&flgopts, sizeof(UzpOpts)); /* no special options */ 557 558 if (!UzpUnzipToMemory(archive, file, &flgopts, UsrFuncts, &retstr)) { 559 return -1; /* not enough memory, file not found, or other error */ 560 } 561 562 if (SkipBin) { 563 if (retstr.strlength < 100) 564 buflen = retstr.strlength; 565 else 566 buflen = 100; 567 for (i = 0; i < buflen; i++) { 568 if (iscntrl(retstr.strptr[i])) { 569 if ((retstr.strptr[i] != 0x0A) && 570 (retstr.strptr[i] != 0x0D) && 571 (retstr.strptr[i] != 0x09)) 572 { 573 /* OK, we now think we have a binary file of some sort */ 574 free(retstr.strptr); 575 return FALSE; 576 } 577 } 578 } 579 } 580 581 patternLen = strlen(pattern); 582 583 if (retstr.strlength < patternLen) { 584 free(retstr.strptr); 585 return FALSE; 586 } 587 588 sz = malloc(patternLen + 3); /* add two in case doing whole words only */ 589 if (cmd > 1) { 590 strcpy(sz, " "); 591 strcat(sz, pattern); 592 strcat(sz, " "); 593 } else 594 strcpy(sz, pattern); 595 596 if ((cmd == 0) || (cmd == 2)) { 597 for (i = 0; i < strlen(sz); i++) 598 sz[i] = toupper(sz[i]); 599 for (i = 0; i < retstr.strlength; i++) 600 retstr.strptr[i] = toupper(retstr.strptr[i]); 601 } 602 603 for (i = 0; i < (retstr.strlength - patternLen); i++) { 604 p = &retstr.strptr[i]; 605 compare = TRUE; 606 for (j = 0; j < patternLen; j++) { 607 /* We cannot do strncmp here, as we may be dealing with a 608 * "binary" file, such as a word processing file, or perhaps 609 * even a true executable of some sort. */ 610 if (p[j] != sz[j]) { 611 compare = FALSE; 612 break; 613 } 614 } 615 if (compare == TRUE) { 616 retcode = TRUE; 617 break; 618 } 619 } 620 621 free(sz); 622 free(retstr.strptr); 623 624 return retcode; 625} 626#endif /* !WINDLL */ 627#endif /* !__16BIT__ */ 628 629 630 631int UZ_EXP UzpValidate(char *archive, int AllCodes) 632{ 633 int retcode; 634 CONSTRUCTGLOBALS(); 635 636 uO.jflag = 1; 637 uO.tflag = 1; 638 uO.overwrite_none = 0; 639 G.extract_flag = (!uO.zipinfo_mode && 640 !uO.cflag && !uO.tflag && !uO.vflag && !uO.zflag 641#ifdef TIMESTAMP 642 && !uO.T_flag 643#endif 644 ); 645 646 uO.qflag = 2; /* turn off all messages */ 647 G.fValidate = TRUE; 648 G.pfnames = (char **)&fnames[0]; /* assign default filename vector */ 649 650 if (archive == NULL) { /* something is screwed up: no filename */ 651 DESTROYGLOBALS(); 652 retcode = PK_NOZIP; 653 goto exit_retcode; 654 } 655 656 if (strlen(archive) >= FILNAMSIZ) { 657 /* length of supplied archive name exceed the system's filename limit */ 658 DESTROYGLOBALS(); 659 retcode = PK_PARAM; 660 goto exit_retcode; 661 } 662 663 G.wildzipfn = (char *)malloc(FILNAMSIZ); 664 strcpy(G.wildzipfn, archive); 665#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO)) 666 _ISO_INTERN(G.wildzipfn); 667#endif 668 669#ifdef WINDLL 670 Wiz_NoPrinting(TRUE); 671#endif 672 673 G.process_all_files = TRUE; /* for speed */ 674 675 if (setjmp(dll_error_return) != 0) { 676#ifdef WINDLL 677 Wiz_NoPrinting(FALSE); 678#endif 679 free(G.wildzipfn); 680 DESTROYGLOBALS(); 681 retcode = PK_BADERR; 682 goto exit_retcode; 683 } 684 685 retcode = process_zipfiles(__G); 686 687 free(G.wildzipfn); 688#ifdef WINDLL 689 Wiz_NoPrinting(FALSE); 690#endif 691 DESTROYGLOBALS(); 692 693 /* PK_WARN == 1 and PK_FIND == 11. When we are just looking at an 694 archive, we should still be able to see the files inside it, 695 even if we can't decode them for some reason. 696 697 We also still want to be able to get at files even if there is 698 something odd about the zip archive, hence allow PK_WARN, 699 PK_FIND, IZ_UNSUP as well as PK_ERR 700 */ 701 702exit_retcode: 703 if (AllCodes) 704 return retcode; 705 706 if ((retcode == PK_OK) || (retcode == PK_WARN) || (retcode == PK_ERR) || 707 (retcode == IZ_UNSUP) || (retcode == PK_FIND)) 708 return TRUE; 709 else 710 return FALSE; 711} 712 713#endif /* !SFX */ 714#endif /* DLL */ 715