0,0 → 1,714 |
/* |
Copyright (c) 1990-2009 Info-ZIP. All rights reserved. |
|
See the accompanying file LICENSE, version 2009-Jan-02 or later |
(the contents of which are also included in unzip.h) for terms of use. |
If, for some reason, all these files are missing, the Info-ZIP license |
also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html |
*/ |
/*--------------------------------------------------------------------------- |
|
api.c |
|
This module supplies an UnZip engine for use directly from C/C++ |
programs. The functions are: |
|
ZCONST UzpVer *UzpVersion(void); |
unsigned UzpVersion2(UzpVer2 *version) |
int UzpMain(int argc, char *argv[]); |
int UzpAltMain(int argc, char *argv[], UzpInit *init); |
int UzpValidate(char *archive, int AllCodes); |
void UzpFreeMemBuffer(UzpBuffer *retstr); |
int UzpUnzipToMemory(char *zip, char *file, UzpOpts *optflgs, |
UzpCB *UsrFuncts, UzpBuffer *retstr); |
|
non-WINDLL only (a special WINDLL variant is defined in windll/windll.c): |
int UzpGrep(char *archive, char *file, char *pattern, int cmd, int SkipBin, |
UzpCB *UsrFuncts); |
|
OS/2 only (for now): |
int UzpFileTree(char *name, cbList(callBack), char *cpInclude[], |
char *cpExclude[]); |
|
You must define `DLL' in order to include the API extensions. |
|
---------------------------------------------------------------------------*/ |
|
|
#ifdef OS2 |
# define INCL_DOSMEMMGR |
# include <os2.h> |
#endif |
|
#define UNZIP_INTERNAL |
#include "unzip.h" |
#ifdef WINDLL |
# ifdef POCKET_UNZIP |
# include "wince/intrface.h" |
# else |
# include "windll/windll.h" |
# endif |
#endif |
#include "unzvers.h" |
#include <setjmp.h> |
|
#ifdef DLL /* This source file supplies DLL-only interface code. */ |
|
#ifndef POCKET_UNZIP /* WinCE pUnZip defines this elsewhere. */ |
jmp_buf dll_error_return; |
#endif |
|
/*--------------------------------------------------------------------------- |
Documented API entry points |
---------------------------------------------------------------------------*/ |
|
|
ZCONST UzpVer * UZ_EXP UzpVersion() /* returns pointer to const struct */ |
{ |
static ZCONST UzpVer version = { /* doesn't change between calls */ |
/* structure size */ |
UZPVER_LEN, |
/* version flags */ |
#ifdef BETA |
# ifdef ZLIB_VERSION |
3, |
# else |
1, |
# endif |
#else |
# ifdef ZLIB_VERSION |
2, |
# else |
0, |
# endif |
#endif |
/* betalevel and date strings */ |
UZ_BETALEVEL, UZ_VERSION_DATE, |
/* zlib_version string */ |
#ifdef ZLIB_VERSION |
ZLIB_VERSION, |
#else |
NULL, |
#endif |
/*== someday each of these may have a separate patchlevel: ==*/ |
/* unzip version */ |
{UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, 0}, |
/* zipinfo version */ |
{ZI_MAJORVER, ZI_MINORVER, UZ_PATCHLEVEL, 0}, |
/* os2dll version (retained for backward compatibility) */ |
{UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, 0}, |
/* windll version (retained for backward compatibility)*/ |
{UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, 0}, |
#ifdef OS2DLL |
/* os2dll API minimum compatible version*/ |
{UZ_OS2API_COMP_MAJOR, UZ_OS2API_COMP_MINOR, UZ_OS2API_COMP_REVIS, 0} |
#else /* !OS2DLL */ |
#ifdef WINDLL |
/* windll API minimum compatible version*/ |
{UZ_WINAPI_COMP_MAJOR, UZ_WINAPI_COMP_MINOR, UZ_WINAPI_COMP_REVIS, 0} |
#else /* !WINDLL */ |
/* generic DLL API minimum compatible version*/ |
{UZ_GENAPI_COMP_MAJOR, UZ_GENAPI_COMP_MINOR, UZ_GENAPI_COMP_REVIS, 0} |
#endif /* ?WINDLL */ |
#endif /* ?OS2DLL */ |
}; |
|
return &version; |
} |
|
unsigned UZ_EXP UzpVersion2(UzpVer2 *version) |
{ |
|
if (version->structlen != sizeof(UzpVer2)) |
return sizeof(UzpVer2); |
|
#ifdef BETA |
version->flag = 1; |
#else |
version->flag = 0; |
#endif |
strcpy(version->betalevel, UZ_BETALEVEL); |
strcpy(version->date, UZ_VERSION_DATE); |
|
#ifdef ZLIB_VERSION |
/* Although ZLIB_VERSION is a compile-time constant, we implement an |
"overrun-safe" copy because its actual value is not under our control. |
*/ |
strncpy(version->zlib_version, ZLIB_VERSION, |
sizeof(version->zlib_version) - 1); |
version->zlib_version[sizeof(version->zlib_version) - 1] = '\0'; |
version->flag |= 2; |
#else |
version->zlib_version[0] = '\0'; |
#endif |
|
/* someday each of these may have a separate patchlevel: */ |
version->unzip.major = UZ_MAJORVER; |
version->unzip.minor = UZ_MINORVER; |
version->unzip.patchlevel = UZ_PATCHLEVEL; |
|
version->zipinfo.major = ZI_MAJORVER; |
version->zipinfo.minor = ZI_MINORVER; |
version->zipinfo.patchlevel = UZ_PATCHLEVEL; |
|
/* these are retained for backward compatibility only: */ |
version->os2dll.major = UZ_MAJORVER; |
version->os2dll.minor = UZ_MINORVER; |
version->os2dll.patchlevel = UZ_PATCHLEVEL; |
|
version->windll.major = UZ_MAJORVER; |
version->windll.minor = UZ_MINORVER; |
version->windll.patchlevel = UZ_PATCHLEVEL; |
|
#ifdef OS2DLL |
/* os2dll API minimum compatible version*/ |
version->dllapimin.major = UZ_OS2API_COMP_MAJOR; |
version->dllapimin.minor = UZ_OS2API_COMP_MINOR; |
version->dllapimin.patchlevel = UZ_OS2API_COMP_REVIS; |
#else /* !OS2DLL */ |
#ifdef WINDLL |
/* windll API minimum compatible version*/ |
version->dllapimin.major = UZ_WINAPI_COMP_MAJOR; |
version->dllapimin.minor = UZ_WINAPI_COMP_MINOR; |
version->dllapimin.patchlevel = UZ_WINAPI_COMP_REVIS; |
#else /* !WINDLL */ |
/* generic DLL API minimum compatible version*/ |
version->dllapimin.major = UZ_GENAPI_COMP_MAJOR; |
version->dllapimin.minor = UZ_GENAPI_COMP_MINOR; |
version->dllapimin.patchlevel = UZ_GENAPI_COMP_REVIS; |
#endif /* ?WINDLL */ |
#endif /* ?OS2DLL */ |
return 0; |
} |
|
|
|
|
|
#ifndef SFX |
#ifndef WINDLL |
|
int UZ_EXP UzpAltMain(int argc, char *argv[], UzpInit *init) |
{ |
int r, (*dummyfn)(); |
|
|
CONSTRUCTGLOBALS(); |
|
if (init->structlen >= (sizeof(ulg) + sizeof(dummyfn)) && init->msgfn) |
G.message = init->msgfn; |
|
if (init->structlen >= (sizeof(ulg) + 2*sizeof(dummyfn)) && init->inputfn) |
G.input = init->inputfn; |
|
if (init->structlen >= (sizeof(ulg) + 3*sizeof(dummyfn)) && init->pausefn) |
G.mpause = init->pausefn; |
|
if (init->structlen >= (sizeof(ulg) + 4*sizeof(dummyfn)) && init->userfn) |
(*init->userfn)(); /* allow void* arg? */ |
|
r = unzip(__G__ argc, argv); |
DESTROYGLOBALS(); |
RETURN(r); |
} |
|
#endif /* !WINDLL */ |
|
|
|
|
#ifndef __16BIT__ |
|
void UZ_EXP UzpFreeMemBuffer(UzpBuffer *retstr) |
{ |
if (retstr != NULL && retstr->strptr != NULL) { |
free(retstr->strptr); |
retstr->strptr = NULL; |
retstr->strlength = 0; |
} |
} |
|
|
|
|
#ifndef WINDLL |
|
static int UzpDLL_Init OF((zvoid *pG, UzpCB *UsrFuncts)); |
|
static int UzpDLL_Init(pG, UsrFuncts) |
zvoid *pG; |
UzpCB *UsrFuncts; |
{ |
int (*dummyfn)(); |
|
if (UsrFuncts->structlen >= (sizeof(ulg) + sizeof(dummyfn)) && |
UsrFuncts->msgfn) |
((Uz_Globs *)pG)->message = UsrFuncts->msgfn; |
else |
return FALSE; |
|
if (UsrFuncts->structlen >= (sizeof(ulg) + 2*sizeof(dummyfn)) && |
UsrFuncts->inputfn) |
((Uz_Globs *)pG)->input = UsrFuncts->inputfn; |
|
if (UsrFuncts->structlen >= (sizeof(ulg) + 3*sizeof(dummyfn)) && |
UsrFuncts->pausefn) |
((Uz_Globs *)pG)->mpause = UsrFuncts->pausefn; |
|
if (UsrFuncts->structlen >= (sizeof(ulg) + 4*sizeof(dummyfn)) && |
UsrFuncts->passwdfn) |
((Uz_Globs *)pG)->decr_passwd = UsrFuncts->passwdfn; |
|
if (UsrFuncts->structlen >= (sizeof(ulg) + 5*sizeof(dummyfn)) && |
UsrFuncts->statrepfn) |
((Uz_Globs *)pG)->statreportcb = UsrFuncts->statrepfn; |
|
return TRUE; |
} |
|
|
int UZ_EXP UzpUnzipToMemory(char *zip, char *file, UzpOpts *optflgs, |
UzpCB *UsrFuncts, UzpBuffer *retstr) |
{ |
int r; |
#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO)) |
char *intern_zip, *intern_file; |
#endif |
|
CONSTRUCTGLOBALS(); |
#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO)) |
intern_zip = (char *)malloc(strlen(zip)+1); |
if (intern_zip == NULL) { |
DESTROYGLOBALS(); |
return PK_MEM; |
} |
intern_file = (char *)malloc(strlen(file)+1); |
if (intern_file == NULL) { |
DESTROYGLOBALS(); |
free(intern_zip); |
return PK_MEM; |
} |
ISO_TO_INTERN(zip, intern_zip); |
ISO_TO_INTERN(file, intern_file); |
# define zip intern_zip |
# define file intern_file |
#endif |
/* Copy those options that are meaningful for UzpUnzipToMemory, instead of |
* a simple "memcpy(G.UzO, optflgs, sizeof(UzpOpts));" |
*/ |
uO.pwdarg = optflgs->pwdarg; |
uO.aflag = optflgs->aflag; |
uO.C_flag = optflgs->C_flag; |
uO.qflag = optflgs->qflag; /* currently, overridden in unzipToMemory */ |
|
if (!UzpDLL_Init((zvoid *)&G, UsrFuncts)) { |
DESTROYGLOBALS(); |
return PK_BADERR; |
} |
G.redirect_data = 1; |
|
r = (unzipToMemory(__G__ zip, file, retstr) <= PK_WARN); |
|
DESTROYGLOBALS(); |
#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO)) |
# undef file |
# undef zip |
free(intern_file); |
free(intern_zip); |
#endif |
if (!r && retstr->strlength) { |
free(retstr->strptr); |
retstr->strptr = NULL; |
} |
return r; |
} |
#endif /* !WINDLL */ |
#endif /* !__16BIT__ */ |
|
|
|
|
|
#ifdef OS2DLL |
|
int UZ_EXP UzpFileTree(char *name, cbList(callBack), char *cpInclude[], |
char *cpExclude[]) |
{ |
int r; |
|
CONSTRUCTGLOBALS(); |
uO.qflag = 2; |
uO.vflag = 1; |
uO.C_flag = 1; |
G.wildzipfn = name; |
G.process_all_files = TRUE; |
if (cpInclude) { |
char **ptr = cpInclude; |
|
while (*ptr != NULL) ptr++; |
G.filespecs = ptr - cpInclude; |
G.pfnames = cpInclude, G.process_all_files = FALSE; |
} |
if (cpExclude) { |
char **ptr = cpExclude; |
|
while (*ptr != NULL) ptr++; |
G.xfilespecs = ptr - cpExclude; |
G.pxnames = cpExclude, G.process_all_files = FALSE; |
} |
|
G.processExternally = callBack; |
r = process_zipfiles(__G)==0; |
DESTROYGLOBALS(); |
return r; |
} |
|
#endif /* OS2DLL */ |
#endif /* !SFX */ |
|
|
|
|
/*--------------------------------------------------------------------------- |
Helper functions |
---------------------------------------------------------------------------*/ |
|
|
void setFileNotFound(__G) |
__GDEF |
{ |
G.filenotfound++; |
} |
|
|
#ifndef SFX |
|
int unzipToMemory(__GPRO__ char *zip, char *file, UzpBuffer *retstr) |
{ |
int r; |
char *incname[2]; |
|
if ((zip == NULL) || (strlen(zip) > ((WSIZE>>2) - 160))) |
return PK_PARAM; |
if ((file == NULL) || (strlen(file) > ((WSIZE>>2) - 160))) |
return PK_PARAM; |
|
G.process_all_files = FALSE; |
G.extract_flag = TRUE; |
uO.qflag = 2; |
G.wildzipfn = zip; |
|
G.pfnames = incname; |
incname[0] = file; |
incname[1] = NULL; |
G.filespecs = 1; |
|
r = process_zipfiles(__G); |
if (retstr) { |
retstr->strptr = (char *)G.redirect_buffer; |
retstr->strlength = G.redirect_size; |
} |
return r; /* returns `PK_???' error values */ |
} |
|
#endif /* !SFX */ |
|
/* |
With the advent of 64 bit support, for now I am assuming that |
if the size of the file is greater than an unsigned long, there |
will simply not be enough memory to handle it, and am returning |
FALSE. |
*/ |
int redirect_outfile(__G) |
__GDEF |
{ |
#ifdef ZIP64_SUPPORT |
__int64 check_conversion; |
#endif |
|
if (G.redirect_size != 0 || G.redirect_buffer != NULL) |
return FALSE; |
|
#ifndef NO_SLIDE_REDIR |
G.redirect_slide = !G.pInfo->textmode; |
#endif |
#if (lenEOL != 1) |
if (G.pInfo->textmode) { |
G.redirect_size = (ulg)(G.lrec.ucsize * lenEOL); |
if (G.redirect_size < G.lrec.ucsize) |
G.redirect_size = (ulg)((G.lrec.ucsize > (ulg)-2L) ? |
G.lrec.ucsize : -2L); |
#ifdef ZIP64_SUPPORT |
check_conversion = G.lrec.ucsize * lenEOL; |
#endif |
} else |
#endif |
{ |
G.redirect_size = (ulg)G.lrec.ucsize; |
#ifdef ZIP64_SUPPORT |
check_conversion = (__int64)G.lrec.ucsize; |
#endif |
} |
|
#ifdef ZIP64_SUPPORT |
if ((__int64)G.redirect_size != check_conversion) |
return FALSE; |
#endif |
|
#ifdef __16BIT__ |
if ((ulg)((extent)G.redirect_size) != G.redirect_size) |
return FALSE; |
#endif |
#ifdef OS2 |
DosAllocMem((void **)&G.redirect_buffer, G.redirect_size+1, |
PAG_READ|PAG_WRITE|PAG_COMMIT); |
G.redirect_pointer = G.redirect_buffer; |
#else |
G.redirect_pointer = |
G.redirect_buffer = malloc((extent)(G.redirect_size+1)); |
#endif |
if (!G.redirect_buffer) |
return FALSE; |
G.redirect_pointer[G.redirect_size] = '\0'; |
return TRUE; |
} |
|
|
|
int writeToMemory(__GPRO__ ZCONST uch *rawbuf, extent size) |
{ |
int errflg = FALSE; |
|
if ((uch *)rawbuf != G.redirect_pointer) { |
extent redir_avail = (G.redirect_buffer + G.redirect_size) - |
G.redirect_pointer; |
|
/* Check for output buffer overflow */ |
if (size > redir_avail) { |
/* limit transfer data to available space, set error return flag */ |
size = redir_avail; |
errflg = TRUE; |
} |
memcpy(G.redirect_pointer, rawbuf, size); |
} |
G.redirect_pointer += size; |
return errflg; |
} |
|
|
|
|
int close_redirect(__G) |
__GDEF |
{ |
if (G.pInfo->textmode) { |
*G.redirect_pointer = '\0'; |
G.redirect_size = (ulg)(G.redirect_pointer - G.redirect_buffer); |
if ((G.redirect_buffer = |
realloc(G.redirect_buffer, G.redirect_size + 1)) == NULL) { |
G.redirect_size = 0; |
return EOF; |
} |
} |
return 0; |
} |
|
|
|
|
#ifndef SFX |
#ifndef __16BIT__ |
#ifndef WINDLL |
|
/* Purpose: Determine if file in archive contains the string szSearch |
|
Parameters: archive = archive name |
file = file contained in the archive. This cannot be |
a wildcard to be meaningful |
pattern = string to search for |
cmd = 0 - case-insensitive search |
1 - case-sensitve search |
2 - case-insensitive, whole words only |
3 - case-sensitive, whole words only |
SkipBin = if true, skip any files that have control |
characters other than CR, LF, or tab in the first |
100 characters. |
|
Returns: TRUE if a match is found |
FALSE if no match is found |
-1 on error |
|
Comments: This does not pretend to be as useful as the standard |
Unix grep, which returns the strings associated with a |
particular pattern, nor does it search past the first |
matching occurrence of the pattern. |
*/ |
|
int UZ_EXP UzpGrep(char *archive, char *file, char *pattern, int cmd, |
int SkipBin, UzpCB *UsrFuncts) |
{ |
int retcode = FALSE, compare; |
ulg i, j, patternLen, buflen; |
char * sz, *p; |
UzpOpts flgopts; |
UzpBuffer retstr; |
|
memzero(&flgopts, sizeof(UzpOpts)); /* no special options */ |
|
if (!UzpUnzipToMemory(archive, file, &flgopts, UsrFuncts, &retstr)) { |
return -1; /* not enough memory, file not found, or other error */ |
} |
|
if (SkipBin) { |
if (retstr.strlength < 100) |
buflen = retstr.strlength; |
else |
buflen = 100; |
for (i = 0; i < buflen; i++) { |
if (iscntrl(retstr.strptr[i])) { |
if ((retstr.strptr[i] != 0x0A) && |
(retstr.strptr[i] != 0x0D) && |
(retstr.strptr[i] != 0x09)) |
{ |
/* OK, we now think we have a binary file of some sort */ |
free(retstr.strptr); |
return FALSE; |
} |
} |
} |
} |
|
patternLen = strlen(pattern); |
|
if (retstr.strlength < patternLen) { |
free(retstr.strptr); |
return FALSE; |
} |
|
sz = malloc(patternLen + 3); /* add two in case doing whole words only */ |
if (cmd > 1) { |
strcpy(sz, " "); |
strcat(sz, pattern); |
strcat(sz, " "); |
} else |
strcpy(sz, pattern); |
|
if ((cmd == 0) || (cmd == 2)) { |
for (i = 0; i < strlen(sz); i++) |
sz[i] = toupper(sz[i]); |
for (i = 0; i < retstr.strlength; i++) |
retstr.strptr[i] = toupper(retstr.strptr[i]); |
} |
|
for (i = 0; i < (retstr.strlength - patternLen); i++) { |
p = &retstr.strptr[i]; |
compare = TRUE; |
for (j = 0; j < patternLen; j++) { |
/* We cannot do strncmp here, as we may be dealing with a |
* "binary" file, such as a word processing file, or perhaps |
* even a true executable of some sort. */ |
if (p[j] != sz[j]) { |
compare = FALSE; |
break; |
} |
} |
if (compare == TRUE) { |
retcode = TRUE; |
break; |
} |
} |
|
free(sz); |
free(retstr.strptr); |
|
return retcode; |
} |
#endif /* !WINDLL */ |
#endif /* !__16BIT__ */ |
|
|
|
int UZ_EXP UzpValidate(char *archive, int AllCodes) |
{ |
int retcode; |
CONSTRUCTGLOBALS(); |
|
uO.jflag = 1; |
uO.tflag = 1; |
uO.overwrite_none = 0; |
G.extract_flag = (!uO.zipinfo_mode && |
!uO.cflag && !uO.tflag && !uO.vflag && !uO.zflag |
#ifdef TIMESTAMP |
&& !uO.T_flag |
#endif |
); |
|
uO.qflag = 2; /* turn off all messages */ |
G.fValidate = TRUE; |
G.pfnames = (char **)&fnames[0]; /* assign default filename vector */ |
|
if (archive == NULL) { /* something is screwed up: no filename */ |
DESTROYGLOBALS(); |
retcode = PK_NOZIP; |
goto exit_retcode; |
} |
|
if (strlen(archive) >= FILNAMSIZ) { |
/* length of supplied archive name exceed the system's filename limit */ |
DESTROYGLOBALS(); |
retcode = PK_PARAM; |
goto exit_retcode; |
} |
|
G.wildzipfn = (char *)malloc(FILNAMSIZ); |
strcpy(G.wildzipfn, archive); |
#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO)) |
_ISO_INTERN(G.wildzipfn); |
#endif |
|
#ifdef WINDLL |
Wiz_NoPrinting(TRUE); |
#endif |
|
G.process_all_files = TRUE; /* for speed */ |
|
if (setjmp(dll_error_return) != 0) { |
#ifdef WINDLL |
Wiz_NoPrinting(FALSE); |
#endif |
free(G.wildzipfn); |
DESTROYGLOBALS(); |
retcode = PK_BADERR; |
goto exit_retcode; |
} |
|
retcode = process_zipfiles(__G); |
|
free(G.wildzipfn); |
#ifdef WINDLL |
Wiz_NoPrinting(FALSE); |
#endif |
DESTROYGLOBALS(); |
|
/* PK_WARN == 1 and PK_FIND == 11. When we are just looking at an |
archive, we should still be able to see the files inside it, |
even if we can't decode them for some reason. |
|
We also still want to be able to get at files even if there is |
something odd about the zip archive, hence allow PK_WARN, |
PK_FIND, IZ_UNSUP as well as PK_ERR |
*/ |
|
exit_retcode: |
if (AllCodes) |
return retcode; |
|
if ((retcode == PK_OK) || (retcode == PK_WARN) || (retcode == PK_ERR) || |
(retcode == IZ_UNSUP) || (retcode == PK_FIND)) |
return TRUE; |
else |
return FALSE; |
} |
|
#endif /* !SFX */ |
#endif /* DLL */ |