boinc/zip/unzip/api.c

715 lines
19 KiB
C

/*
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 */