xref: /haiku/src/bin/unzip/api.c (revision 17049c451a91f427aec94b944b75876b611103e7)
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 
53 jmp_buf dll_error_return;
54 
55 /*---------------------------------------------------------------------------
56     Documented API entry points
57   ---------------------------------------------------------------------------*/
58 
59 
UzpVersion()60 UzpVer * 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 
UzpVersion2(UzpVer2 * version)103 void 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 
UzpAltMain(int argc,char * argv[],UzpInit * init)148 int 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 
UzpFreeMemBuffer(UzpBuffer * retstr)179 void 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 
192 static int UzpDLL_Init OF((zvoid *pG, UzpCB *UsrFuncts));
193 
UzpDLL_Init(pG,UsrFuncts)194 static int UzpDLL_Init(pG, UsrFuncts)
195 zvoid *pG;
196 UzpCB *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 
UzpUnzipToMemory(char * zip,char * file,UzpOpts * optflgs,UzpCB * UsrFuncts,UzpBuffer * retstr)226 int 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 
UzpFileTree(char * name,cbList (callBack),char * cpInclude[],char * cpExclude[])290 int 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 
setFileNotFound(__G)332 void setFileNotFound(__G)
333     __GDEF
334 {
335     G.filenotfound++;
336 }
337 
338 
339 
unzipToMemory(__GPRO__ char * zip,char * file,UzpBuffer * retstr)340 int 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 
redirect_outfile(__G)365 int 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 
writeToMemory(__GPRO__ ZCONST uch * rawbuf,extent size)396 int 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 
close_redirect(__G)407 int 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 
UzpGrep(char * archive,char * file,char * pattern,int cmd,int SkipBin,UzpCB * UsrFuncts)452 int 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 
UzpValidate(char * archive,int AllCodes)537 int 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