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