1/*
2  Copyright (c) 1990-2001 Info-ZIP.  All rights reserved.
3
4  See the accompanying file LICENSE, version 2000-Apr-09 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    UzpVer *UzpVersion(void);
17    void 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#include <setjmp.h>
43
44#define UNZIP_INTERNAL
45#include "unzip.h"
46#ifdef WINDLL
47#  include "windll/windll.h"
48#endif
49#include "unzvers.h"
50
51#ifdef DLL      /* This source file supplies DLL-only interface code. */
52
53jmp_buf dll_error_return;
54
55/*---------------------------------------------------------------------------
56    Documented API entry points
57  ---------------------------------------------------------------------------*/
58
59
60UzpVer * UZ_EXP UzpVersion()   /* should be pointer to const struct */
61{
62    static UzpVer version;     /* doesn't change between calls */
63
64
65    version.structlen = UZPVER_LEN;
66
67#ifdef BETA
68    version.flag = 1;
69#else
70    version.flag = 0;
71#endif
72    version.betalevel = UZ_BETALEVEL;
73    version.date = UZ_VERSION_DATE;
74
75#ifdef ZLIB_VERSION
76    version.zlib_version = ZLIB_VERSION;
77    version.flag |= 2;
78#else
79    version.zlib_version = NULL;
80#endif
81
82    /* someday each of these may have a separate patchlevel: */
83    version.unzip.major = UZ_MAJORVER;
84    version.unzip.minor = UZ_MINORVER;
85    version.unzip.patchlevel = UZ_PATCHLEVEL;
86
87    version.zipinfo.major = ZI_MAJORVER;
88    version.zipinfo.minor = ZI_MINORVER;
89    version.zipinfo.patchlevel = UZ_PATCHLEVEL;
90
91    /* these are retained for backward compatibility only: */
92    version.os2dll.major = UZ_MAJORVER;
93    version.os2dll.minor = UZ_MINORVER;
94    version.os2dll.patchlevel = UZ_PATCHLEVEL;
95
96    version.windll.major = UZ_MAJORVER;
97    version.windll.minor = UZ_MINORVER;
98    version.windll.patchlevel = UZ_PATCHLEVEL;
99
100    return &version;
101}
102
103void UZ_EXP UzpVersion2(UzpVer2 *version)
104{
105
106    version->structlen = UZPVER_LEN;
107
108#ifdef BETA
109    version->flag = 1;
110#else
111    version->flag = 0;
112#endif
113    strcpy(version->betalevel, UZ_BETALEVEL);
114    strcpy(version->date, UZ_VERSION_DATE);
115
116#ifdef ZLIB_VERSION
117    strcpy(version->zlib_version, ZLIB_VERSION);
118    version->flag |= 2;
119#else
120    version->zlib_version[0] = '\0';
121#endif
122
123    /* someday each of these may have a separate patchlevel: */
124    version->unzip.major = UZ_MAJORVER;
125    version->unzip.minor = UZ_MINORVER;
126    version->unzip.patchlevel = UZ_PATCHLEVEL;
127
128    version->zipinfo.major = ZI_MAJORVER;
129    version->zipinfo.minor = ZI_MINORVER;
130    version->zipinfo.patchlevel = UZ_PATCHLEVEL;
131
132    /* these are retained for backward compatibility only: */
133    version->os2dll.major = UZ_MAJORVER;
134    version->os2dll.minor = UZ_MINORVER;
135    version->os2dll.patchlevel = UZ_PATCHLEVEL;
136
137    version->windll.major = UZ_MAJORVER;
138    version->windll.minor = UZ_MINORVER;
139    version->windll.patchlevel = UZ_PATCHLEVEL;
140}
141
142
143
144
145
146#ifndef WINDLL
147
148int UZ_EXP UzpAltMain(int argc, char *argv[], UzpInit *init)
149{
150    int r, (*dummyfn)();
151
152
153    CONSTRUCTGLOBALS();
154
155    if (init->structlen >= (sizeof(ulg) + sizeof(dummyfn)) && init->msgfn)
156        G.message = init->msgfn;
157
158    if (init->structlen >= (sizeof(ulg) + 2*sizeof(dummyfn)) && init->inputfn)
159        G.input = init->inputfn;
160
161    if (init->structlen >= (sizeof(ulg) + 3*sizeof(dummyfn)) && init->pausefn)
162        G.mpause = init->pausefn;
163
164    if (init->structlen >= (sizeof(ulg) + 4*sizeof(dummyfn)) && init->userfn)
165        (*init->userfn)();    /* allow void* arg? */
166
167    r = unzip(__G__ argc, argv);
168    DESTROYGLOBALS();
169    RETURN(r);
170}
171
172#endif /* !WINDLL */
173
174
175
176
177#ifndef __16BIT__
178
179void UZ_EXP UzpFreeMemBuffer(UzpBuffer *retstr)
180{
181    if (retstr->strptr != NULL) {
182        free(retstr->strptr);
183        retstr->strptr = NULL;
184    }
185}
186
187
188
189
190#ifndef WINDLL
191
192static int UzpDLL_Init OF((zvoid *pG, UzpCB *UsrFuncts));
193
194static int UzpDLL_Init(pG, UsrFuncts)
195zvoid *pG;
196UzpCB *UsrFuncts;
197{
198    int (*dummyfn)();
199
200    if (UsrFuncts->structlen >= (sizeof(ulg) + sizeof(dummyfn)) &&
201        UsrFuncts->msgfn)
202        ((Uz_Globs *)pG)->message = UsrFuncts->msgfn;
203    else
204        return FALSE;
205
206    if (UsrFuncts->structlen >= (sizeof(ulg) + 2*sizeof(dummyfn)) &&
207        UsrFuncts->inputfn)
208        ((Uz_Globs *)pG)->input = UsrFuncts->inputfn;
209
210    if (UsrFuncts->structlen >= (sizeof(ulg) + 3*sizeof(dummyfn)) &&
211        UsrFuncts->pausefn)
212        ((Uz_Globs *)pG)->mpause = UsrFuncts->pausefn;
213
214    if (UsrFuncts->structlen >= (sizeof(ulg) + 4*sizeof(dummyfn)) &&
215        UsrFuncts->passwdfn)
216        ((Uz_Globs *)pG)->decr_passwd = UsrFuncts->passwdfn;
217
218    if (UsrFuncts->structlen >= (sizeof(ulg) + 5*sizeof(dummyfn)) &&
219        UsrFuncts->statrepfn)
220        ((Uz_Globs *)pG)->statreportcb = UsrFuncts->statrepfn;
221
222    return TRUE;
223}
224
225
226int UZ_EXP UzpUnzipToMemory(char *zip, char *file, UzpOpts *optflgs,
227    UzpCB *UsrFuncts, UzpBuffer *retstr)
228{
229    int r;
230#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO))
231    char *intern_zip, *intern_file;
232#endif
233
234    CONSTRUCTGLOBALS();
235#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO))
236    intern_zip = (char *)malloc(strlen(zip)+1);
237    if (intern_zip == NULL) {
238       DESTROYGLOBALS();
239       return PK_MEM;
240    }
241    intern_file = (char *)malloc(strlen(file)+1);
242    if (intern_file == NULL) {
243       DESTROYGLOBALS();
244       free(intern_zip);
245       return PK_MEM;
246    }
247    ISO_TO_INTERN(zip, intern_zip);
248    ISO_TO_INTERN(file, intern_file);
249#   define zip intern_zip
250#   define file intern_file
251#endif
252    /* Copy those options that are meaningful for UzpUnzipToMemory, instead of
253     * a simple "memcpy(G.UzO, optflgs, sizeof(UzpOpts));"
254     */
255    uO.pwdarg = optflgs->pwdarg;
256    uO.aflag = optflgs->aflag;
257    uO.C_flag = optflgs->C_flag;
258    uO.qflag = optflgs->qflag;  /* currently,  overridden in unzipToMemory */
259
260    if (!UzpDLL_Init((zvoid *)&G, UsrFuncts)) {
261       DESTROYGLOBALS();
262       return PK_BADERR;
263    }
264    G.redirect_data = 1;
265
266    r = (unzipToMemory(__G__ zip, file, retstr) <= PK_WARN);
267
268    DESTROYGLOBALS();
269#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO))
270#  undef file
271#  undef zip
272    free(intern_file);
273    free(intern_zip);
274#endif
275    if (!r && retstr->strlength) {
276       free(retstr->strptr);
277       retstr->strptr = NULL;
278    }
279    return r;
280}
281#endif /* !WINDLL */
282#endif /* !__16BIT__ */
283
284
285
286
287
288#ifdef OS2DLL
289
290int UZ_EXP UzpFileTree(char *name, cbList(callBack), char *cpInclude[],
291                char *cpExclude[])
292{
293    int r;
294
295    CONSTRUCTGLOBALS();
296    uO.qflag = 2;
297    uO.vflag = 1;
298    uO.C_flag = 1;
299    G.wildzipfn = name;
300    G.process_all_files = TRUE;
301    if (cpInclude) {
302        char **ptr = cpInclude;
303
304        while (*ptr != NULL) ptr++;
305        G.filespecs = ptr - cpInclude;
306        G.pfnames = cpInclude, G.process_all_files = FALSE;
307    }
308    if (cpExclude) {
309        char **ptr = cpExclude;
310
311        while (*ptr != NULL) ptr++;
312        G.xfilespecs = ptr - cpExclude;
313        G.pxnames = cpExclude, G.process_all_files = FALSE;
314    }
315
316    G.processExternally = callBack;
317    r = process_zipfiles(__G)==0;
318    DESTROYGLOBALS();
319    return r;
320}
321
322#endif /* OS2DLL */
323
324
325
326
327/*---------------------------------------------------------------------------
328    Helper functions
329  ---------------------------------------------------------------------------*/
330
331
332void setFileNotFound(__G)
333    __GDEF
334{
335    G.filenotfound++;
336}
337
338
339
340int unzipToMemory(__GPRO__ char *zip, char *file, UzpBuffer *retstr)
341{
342    int r;
343    char *incname[2];
344
345    G.process_all_files = FALSE;
346    G.extract_flag = TRUE;
347    uO.qflag = 2;
348    G.wildzipfn = zip;
349
350    G.pfnames = incname;
351    incname[0] = file;
352    incname[1] = NULL;
353    G.filespecs = 1;
354
355    r = process_zipfiles(__G);
356    if (retstr) {
357        retstr->strptr = (char *)G.redirect_buffer;
358        retstr->strlength = G.redirect_size;
359    }
360    return r;                   /* returns `PK_???' error values */
361}
362
363
364
365int redirect_outfile(__G)
366     __GDEF
367{
368    if (G.redirect_size != 0 || G.redirect_buffer != NULL)
369        return FALSE;
370
371#ifndef NO_SLIDE_REDIR
372    G.redirect_slide = !G.pInfo->textmode;
373#endif
374    G.redirect_size = (G.pInfo->textmode ?
375                       G.lrec.ucsize * lenEOL : G.lrec.ucsize);
376#ifdef OS2
377    DosAllocMem((void **)&G.redirect_buffer, G.redirect_size+1,
378      PAG_READ|PAG_WRITE|PAG_COMMIT);
379    G.redirect_pointer = G.redirect_buffer;
380#else
381#ifdef __16BIT__
382    if ((ulg)((extent)G.redirect_size) != G.redirect_size)
383        return FALSE;
384#endif
385    G.redirect_pointer =
386      G.redirect_buffer = malloc((extent)(G.redirect_size+1));
387#endif
388    if (!G.redirect_buffer)
389        return FALSE;
390    G.redirect_pointer[G.redirect_size] = '\0';
391    return TRUE;
392}
393
394
395
396int writeToMemory(__GPRO__ ZCONST uch *rawbuf, extent size)
397{
398    if ((uch *)rawbuf != G.redirect_pointer)
399        memcpy(G.redirect_pointer, rawbuf, size);
400    G.redirect_pointer += size;
401    return 0;
402}
403
404
405
406
407int close_redirect(__G)
408     __GDEF
409{
410    if (G.pInfo->textmode) {
411        *G.redirect_pointer = '\0';
412        G.redirect_size = (ulg)(G.redirect_pointer - G.redirect_buffer);
413        if ((G.redirect_buffer =
414             realloc(G.redirect_buffer, G.redirect_size + 1)) == NULL) {
415            G.redirect_size = 0;
416            return EOF;
417        }
418    }
419    return 0;
420}
421
422
423
424
425#ifndef __16BIT__
426#ifndef WINDLL
427
428/* Purpose: Determine if file in archive contains the string szSearch
429
430   Parameters: archive  = archive name
431               file     = file contained in the archive. This cannot be
432                          a wild card to be meaningful
433               pattern  = string to search for
434               cmd      = 0 - case-insensitive search
435                          1 - case-sensitve search
436                          2 - case-insensitive, whole words only
437                          3 - case-sensitive, whole words only
438               SkipBin  = if true, skip any files that have control
439                          characters other than CR, LF, or tab in the first
440                          100 characters.
441
442   Returns:    TRUE if a match is found
443               FALSE if no match is found
444               -1 on error
445
446   Comments: This does not pretend to be as useful as the standard
447             Unix grep, which returns the strings associated with a
448             particular pattern, nor does it search past the first
449             matching occurrence of the pattern.
450 */
451
452int UZ_EXP UzpGrep(char *archive, char *file, char *pattern, int cmd,
453                   int SkipBin, UzpCB *UsrFuncts)
454{
455    int retcode = FALSE, compare;
456    ulg i, j, patternLen, buflen;
457    char * sz, *p;
458    UzpOpts flgopts;
459    UzpBuffer retstr;
460
461    memzero(&flgopts, sizeof(UzpOpts));         /* no special options */
462
463    if (!UzpUnzipToMemory(archive, file, &flgopts, UsrFuncts, &retstr)) {
464       return -1;   /* not enough memory, file not found, or other error */
465    }
466
467    if (SkipBin) {
468        if (retstr.strlength < 100)
469            buflen = retstr.strlength;
470        else
471            buflen = 100;
472        for (i = 0; i < buflen; i++) {
473            if (iscntrl(retstr.strptr[i])) {
474                if ((retstr.strptr[i] != 0x0A) &&
475                    (retstr.strptr[i] != 0x0D) &&
476                    (retstr.strptr[i] != 0x09))
477                {
478                    /* OK, we now think we have a binary file of some sort */
479                    free(retstr.strptr);
480                    return FALSE;
481                }
482            }
483        }
484    }
485
486    patternLen = strlen(pattern);
487
488    if (retstr.strlength < patternLen) {
489        free(retstr.strptr);
490        return FALSE;
491    }
492
493    sz = malloc(patternLen + 3); /* add two in case doing whole words only */
494    if (cmd > 1) {
495        strcpy(sz, " ");
496        strcat(sz, pattern);
497        strcat(sz, " ");
498    } else
499        strcpy(sz, pattern);
500
501    if ((cmd == 0) || (cmd == 2)) {
502        for (i = 0; i < strlen(sz); i++)
503            sz[i] = toupper(sz[i]);
504        for (i = 0; i < retstr.strlength; i++)
505            retstr.strptr[i] = toupper(retstr.strptr[i]);
506    }
507
508    for (i = 0; i < (retstr.strlength - patternLen); i++) {
509        p = &retstr.strptr[i];
510        compare = TRUE;
511        for (j = 0; j < patternLen; j++) {
512            /* We cannot do strncmp here, as we may be dealing with a
513             * "binary" file, such as a word processing file, or perhaps
514             * even a true executable of some sort. */
515            if (p[j] != sz[j]) {
516                compare = FALSE;
517                break;
518            }
519        }
520        if (compare == TRUE) {
521            retcode = TRUE;
522            break;
523        }
524    }
525
526    free(sz);
527    free(retstr.strptr);
528
529    return retcode;
530}
531#endif /* !WINDLL */
532#endif /* !__16BIT__ */
533
534
535
536
537int UZ_EXP UzpValidate(char *archive, int AllCodes)
538{
539    int retcode;
540    CONSTRUCTGLOBALS();
541
542    uO.jflag = 1;
543    uO.tflag = 1;
544    uO.overwrite_none = 0;
545    G.extract_flag = (!uO.zipinfo_mode &&
546                      !uO.cflag && !uO.tflag && !uO.vflag && !uO.zflag
547#ifdef TIMESTAMP
548                      && !uO.T_flag
549#endif
550                     );
551
552    uO.qflag = 2;                        /* turn off all messages */
553    G.fValidate = TRUE;
554    G.pfnames = (char **)&fnames[0];    /* assign default filename vector */
555#ifdef WINDLL
556    Wiz_NoPrinting(TRUE);
557#endif
558
559    if (archive == NULL) {      /* something is screwed up:  no filename */
560        DESTROYGLOBALS();
561        return PK_NOZIP;
562    }
563
564    G.wildzipfn = (char *)malloc(FILNAMSIZ + 1);
565    strcpy(G.wildzipfn, archive);
566#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO))
567    _ISO_INTERN(G.wildzipfn);
568#endif
569
570    G.process_all_files = TRUE;         /* for speed */
571
572    retcode = setjmp(dll_error_return);
573
574    if (retcode) {
575#ifdef WINDLL
576        Wiz_NoPrinting(FALSE);
577#endif
578        free(G.wildzipfn);
579        DESTROYGLOBALS();
580        return PK_BADERR;
581    }
582
583    retcode = process_zipfiles(__G);
584
585    free(G.wildzipfn);
586#ifdef WINDLL
587    Wiz_NoPrinting(FALSE);
588#endif
589    DESTROYGLOBALS();
590
591    /* PK_WARN == 1 and PK_FIND == 11. When we are just looking at an
592       archive, we should still be able to see the files inside it,
593       even if we can't decode them for some reason.
594
595       We also still want to be able to get at files even if there is
596       something odd about the zip archive, hence allow PK_WARN,
597       PK_FIND, IZ_UNSUP as well as PK_ERR
598     */
599
600    if (AllCodes)
601        return retcode;
602
603    if ((retcode == PK_OK) || (retcode == PK_WARN) || (retcode == PK_ERR) ||
604        (retcode == IZ_UNSUP) || (retcode == PK_FIND))
605        return TRUE;
606    else
607        return FALSE;
608}
609
610#endif /* DLL */
611