vfs: check userland buffers before reading them.
[haiku.git] / src / bin / unzip / api.c
blob1d5edbca8e212c2441ebfae377b5eeb4308bed8d
1 /*
2 Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
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 /*---------------------------------------------------------------------------
11 api.c
13 This module supplies an UnZip engine for use directly from C/C++
14 programs. The functions are:
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);
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);
29 OS/2 only (for now):
30 int UzpFileTree(char *name, cbList(callBack), char *cpInclude[],
31 char *cpExclude[]);
33 You must define `DLL' in order to include the API extensions.
35 ---------------------------------------------------------------------------*/
38 #ifdef OS2
39 # define INCL_DOSMEMMGR
40 # include <os2.h>
41 #endif
42 #include <setjmp.h>
44 #define UNZIP_INTERNAL
45 #include "unzip.h"
46 #ifdef WINDLL
47 # include "windll/windll.h"
48 #endif
49 #include "unzvers.h"
51 #ifdef DLL /* This source file supplies DLL-only interface code. */
53 jmp_buf dll_error_return;
55 /*---------------------------------------------------------------------------
56 Documented API entry points
57 ---------------------------------------------------------------------------*/
60 UzpVer * UZ_EXP UzpVersion() /* should be pointer to const struct */
62 static UzpVer version; /* doesn't change between calls */
65 version.structlen = UZPVER_LEN;
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;
75 #ifdef ZLIB_VERSION
76 version.zlib_version = ZLIB_VERSION;
77 version.flag |= 2;
78 #else
79 version.zlib_version = NULL;
80 #endif
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;
87 version.zipinfo.major = ZI_MAJORVER;
88 version.zipinfo.minor = ZI_MINORVER;
89 version.zipinfo.patchlevel = UZ_PATCHLEVEL;
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;
96 version.windll.major = UZ_MAJORVER;
97 version.windll.minor = UZ_MINORVER;
98 version.windll.patchlevel = UZ_PATCHLEVEL;
100 return &version;
103 void UZ_EXP UzpVersion2(UzpVer2 *version)
106 version->structlen = UZPVER_LEN;
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);
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
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;
128 version->zipinfo.major = ZI_MAJORVER;
129 version->zipinfo.minor = ZI_MINORVER;
130 version->zipinfo.patchlevel = UZ_PATCHLEVEL;
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;
137 version->windll.major = UZ_MAJORVER;
138 version->windll.minor = UZ_MINORVER;
139 version->windll.patchlevel = UZ_PATCHLEVEL;
146 #ifndef WINDLL
148 int UZ_EXP UzpAltMain(int argc, char *argv[], UzpInit *init)
150 int r, (*dummyfn)();
153 CONSTRUCTGLOBALS();
155 if (init->structlen >= (sizeof(ulg) + sizeof(dummyfn)) && init->msgfn)
156 G.message = init->msgfn;
158 if (init->structlen >= (sizeof(ulg) + 2*sizeof(dummyfn)) && init->inputfn)
159 G.input = init->inputfn;
161 if (init->structlen >= (sizeof(ulg) + 3*sizeof(dummyfn)) && init->pausefn)
162 G.mpause = init->pausefn;
164 if (init->structlen >= (sizeof(ulg) + 4*sizeof(dummyfn)) && init->userfn)
165 (*init->userfn)(); /* allow void* arg? */
167 r = unzip(__G__ argc, argv);
168 DESTROYGLOBALS();
169 RETURN(r);
172 #endif /* !WINDLL */
177 #ifndef __16BIT__
179 void UZ_EXP UzpFreeMemBuffer(UzpBuffer *retstr)
181 if (retstr->strptr != NULL) {
182 free(retstr->strptr);
183 retstr->strptr = NULL;
190 #ifndef WINDLL
192 static int UzpDLL_Init OF((zvoid *pG, UzpCB *UsrFuncts));
194 static int UzpDLL_Init(pG, UsrFuncts)
195 zvoid *pG;
196 UzpCB *UsrFuncts;
198 int (*dummyfn)();
200 if (UsrFuncts->structlen >= (sizeof(ulg) + sizeof(dummyfn)) &&
201 UsrFuncts->msgfn)
202 ((Uz_Globs *)pG)->message = UsrFuncts->msgfn;
203 else
204 return FALSE;
206 if (UsrFuncts->structlen >= (sizeof(ulg) + 2*sizeof(dummyfn)) &&
207 UsrFuncts->inputfn)
208 ((Uz_Globs *)pG)->input = UsrFuncts->inputfn;
210 if (UsrFuncts->structlen >= (sizeof(ulg) + 3*sizeof(dummyfn)) &&
211 UsrFuncts->pausefn)
212 ((Uz_Globs *)pG)->mpause = UsrFuncts->pausefn;
214 if (UsrFuncts->structlen >= (sizeof(ulg) + 4*sizeof(dummyfn)) &&
215 UsrFuncts->passwdfn)
216 ((Uz_Globs *)pG)->decr_passwd = UsrFuncts->passwdfn;
218 if (UsrFuncts->structlen >= (sizeof(ulg) + 5*sizeof(dummyfn)) &&
219 UsrFuncts->statrepfn)
220 ((Uz_Globs *)pG)->statreportcb = UsrFuncts->statrepfn;
222 return TRUE;
226 int UZ_EXP UzpUnzipToMemory(char *zip, char *file, UzpOpts *optflgs,
227 UzpCB *UsrFuncts, UzpBuffer *retstr)
229 int r;
230 #if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO))
231 char *intern_zip, *intern_file;
232 #endif
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;
241 intern_file = (char *)malloc(strlen(file)+1);
242 if (intern_file == NULL) {
243 DESTROYGLOBALS();
244 free(intern_zip);
245 return PK_MEM;
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));"
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 */
260 if (!UzpDLL_Init((zvoid *)&G, UsrFuncts)) {
261 DESTROYGLOBALS();
262 return PK_BADERR;
264 G.redirect_data = 1;
266 r = (unzipToMemory(__G__ zip, file, retstr) <= PK_WARN);
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;
279 return r;
281 #endif /* !WINDLL */
282 #endif /* !__16BIT__ */
288 #ifdef OS2DLL
290 int UZ_EXP UzpFileTree(char *name, cbList(callBack), char *cpInclude[],
291 char *cpExclude[])
293 int r;
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;
304 while (*ptr != NULL) ptr++;
305 G.filespecs = ptr - cpInclude;
306 G.pfnames = cpInclude, G.process_all_files = FALSE;
308 if (cpExclude) {
309 char **ptr = cpExclude;
311 while (*ptr != NULL) ptr++;
312 G.xfilespecs = ptr - cpExclude;
313 G.pxnames = cpExclude, G.process_all_files = FALSE;
316 G.processExternally = callBack;
317 r = process_zipfiles(__G)==0;
318 DESTROYGLOBALS();
319 return r;
322 #endif /* OS2DLL */
327 /*---------------------------------------------------------------------------
328 Helper functions
329 ---------------------------------------------------------------------------*/
332 void setFileNotFound(__G)
333 __GDEF
335 G.filenotfound++;
340 int unzipToMemory(__GPRO__ char *zip, char *file, UzpBuffer *retstr)
342 int r;
343 char *incname[2];
345 G.process_all_files = FALSE;
346 G.extract_flag = TRUE;
347 uO.qflag = 2;
348 G.wildzipfn = zip;
350 G.pfnames = incname;
351 incname[0] = file;
352 incname[1] = NULL;
353 G.filespecs = 1;
355 r = process_zipfiles(__G);
356 if (retstr) {
357 retstr->strptr = (char *)G.redirect_buffer;
358 retstr->strlength = G.redirect_size;
360 return r; /* returns `PK_???' error values */
365 int redirect_outfile(__G)
366 __GDEF
368 if (G.redirect_size != 0 || G.redirect_buffer != NULL)
369 return FALSE;
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;
396 int writeToMemory(__GPRO__ ZCONST uch *rawbuf, extent size)
398 if ((uch *)rawbuf != G.redirect_pointer)
399 memcpy(G.redirect_pointer, rawbuf, size);
400 G.redirect_pointer += size;
401 return 0;
407 int close_redirect(__G)
408 __GDEF
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;
419 return 0;
425 #ifndef __16BIT__
426 #ifndef WINDLL
428 /* Purpose: Determine if file in archive contains the string szSearch
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.
442 Returns: TRUE if a match is found
443 FALSE if no match is found
444 -1 on error
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.
452 int UZ_EXP UzpGrep(char *archive, char *file, char *pattern, int cmd,
453 int SkipBin, UzpCB *UsrFuncts)
455 int retcode = FALSE, compare;
456 ulg i, j, patternLen, buflen;
457 char * sz, *p;
458 UzpOpts flgopts;
459 UzpBuffer retstr;
461 memzero(&flgopts, sizeof(UzpOpts)); /* no special options */
463 if (!UzpUnzipToMemory(archive, file, &flgopts, UsrFuncts, &retstr)) {
464 return -1; /* not enough memory, file not found, or other error */
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))
478 /* OK, we now think we have a binary file of some sort */
479 free(retstr.strptr);
480 return FALSE;
486 patternLen = strlen(pattern);
488 if (retstr.strlength < patternLen) {
489 free(retstr.strptr);
490 return FALSE;
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);
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]);
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;
520 if (compare == TRUE) {
521 retcode = TRUE;
522 break;
526 free(sz);
527 free(retstr.strptr);
529 return retcode;
531 #endif /* !WINDLL */
532 #endif /* !__16BIT__ */
537 int UZ_EXP UzpValidate(char *archive, int AllCodes)
539 int retcode;
540 CONSTRUCTGLOBALS();
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
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
559 if (archive == NULL) { /* something is screwed up: no filename */
560 DESTROYGLOBALS();
561 return PK_NOZIP;
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
570 G.process_all_files = TRUE; /* for speed */
572 retcode = setjmp(dll_error_return);
574 if (retcode) {
575 #ifdef WINDLL
576 Wiz_NoPrinting(FALSE);
577 #endif
578 free(G.wildzipfn);
579 DESTROYGLOBALS();
580 return PK_BADERR;
583 retcode = process_zipfiles(__G);
585 free(G.wildzipfn);
586 #ifdef WINDLL
587 Wiz_NoPrinting(FALSE);
588 #endif
589 DESTROYGLOBALS();
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.
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
600 if (AllCodes)
601 return retcode;
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;
610 #endif /* DLL */