vfs: check userland buffers before reading them.
[haiku.git] / src / bin / unzip / fileio.c
blobdf72a22587e437b486cabf8973bf5e9ef2ea9fef
1 /*
2 Copyright (c) 1990-2002 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 fileio.c
13 This file contains routines for doing direct but relatively generic input/
14 output, file-related sorts of things, plus some miscellaneous stuff. Most
15 of the stuff has to do with opening, closing, reading and/or writing files.
17 Contains: open_input_file()
18 open_outfile() (not: VMS, AOS/VS, CMSMVS, MACOS, TANDEM)
19 undefer_input()
20 defer_leftover_input()
21 readbuf()
22 readbyte()
23 fillinbuf()
24 seek_zipf()
25 flush() (non-VMS)
26 is_vms_varlen_txt() (non-VMS, VMS_TEXT_CONV only)
27 disk_error() (non-VMS)
28 UzpMessagePrnt()
29 UzpMessageNull() (DLL only)
30 UzpInput()
31 UzpMorePause()
32 UzpPassword() (non-WINDLL)
33 handler()
34 dos_to_unix_time() (non-VMS, non-VM/CMS, non-MVS)
35 check_for_newer() (non-VMS, non-OS/2, non-VM/CMS, non-MVS)
36 do_string()
37 makeword()
38 makelong()
39 str2iso() (CRYPT && NEED_STR2ISO, only)
40 str2oem() (CRYPT && NEED_STR2OEM, only)
41 memset() (ZMEM only)
42 memcpy() (ZMEM only)
43 zstrnicmp() (NO_STRNICMP only)
44 zstat() (REGULUS only)
45 plastchar() (_MBCS only)
46 uzmbschr() (_MBCS && NEED_UZMBSCHR, only)
47 uzmbsrchr() (_MBCS && NEED_UZMBSRCHR, only)
48 fLoadFarString() (SMALL_MEM only)
49 fLoadFarStringSmall() (SMALL_MEM only)
50 fLoadFarStringSmall2() (SMALL_MEM only)
51 zfstrcpy() (SMALL_MEM only)
53 ---------------------------------------------------------------------------*/
56 #define __FILEIO_C /* identifies this source module */
57 #define UNZIP_INTERNAL
58 #include "unzip.h"
59 #ifdef WINDLL
60 # include "windll/windll.h"
61 # include <setjmp.h>
62 #endif
63 #include "crypt.h"
64 #include "ttyio.h"
66 /* setup of codepage conversion for decryption passwords */
67 #if CRYPT
68 # if (defined(CRYP_USES_ISO2OEM) && !defined(IZ_ISO2OEM_ARRAY))
69 # define IZ_ISO2OEM_ARRAY /* pull in iso2oem[] table */
70 # endif
71 # if (defined(CRYP_USES_OEM2ISO) && !defined(IZ_OEM2ISO_ARRAY))
72 # define IZ_OEM2ISO_ARRAY /* pull in oem2iso[] table */
73 # endif
74 #endif
75 #include "ebcdic.h" /* definition/initialization of ebcdic[] */
79 Note: Under Windows, the maximum size of the buffer that can be used
80 with any of the *printf calls is 16,384, so win_fprintf was used to
81 feed the fprintf clone no more than 16K chunks at a time. This should
82 be valid for anything up to 64K (and probably beyond, assuming your
83 buffers are that big).
85 #ifdef WINDLL
86 # define WriteError(buf,len,strm) \
87 (win_fprintf(pG, strm, (extent)len, (char far *)buf) != (int)(len))
88 #else /* !WINDLL */
89 # ifdef USE_FWRITE
90 # define WriteError(buf,len,strm) \
91 ((extent)fwrite((char *)(buf),1,(extent)(len),strm) != (extent)(len))
92 # else
93 # define WriteError(buf,len,strm) \
94 ((extent)write(fileno(strm),(char *)(buf),(extent)(len)) != (extent)(len))
95 # endif
96 #endif /* ?WINDLL */
98 #if (defined(USE_DEFLATE64) && defined(__16BIT__))
99 static int partflush OF((__GPRO__ uch *rawbuf, ulg size, int unshrink));
100 #endif
101 #ifdef VMS_TEXT_CONV
102 static int is_vms_varlen_txt OF((__GPRO__ uch *ef_buf, unsigned ef_len));
103 #endif
104 static int disk_error OF((__GPRO));
107 /****************************/
108 /* Strings used in fileio.c */
109 /****************************/
111 static ZCONST char Far CannotOpenZipfile[] =
112 "error: cannot open zipfile [ %s ]\n";
114 #if (!defined(VMS) && !defined(AOS_VS) && !defined(CMS_MVS) && !defined(MACOS))
115 #if (!defined(TANDEM))
116 #if (defined(BEO_THS_UNX) || defined(DOS_FLX_NLM_OS2_W32))
117 static ZCONST char Far CannotDeleteOldFile[] =
118 "error: cannot delete old %s\n";
119 #ifdef UNIXBACKUP
120 static ZCONST char Far CannotRenameOldFile[] =
121 "error: cannot rename old %s\n";
122 static ZCONST char Far BackupSuffix[] = "~";
123 #endif
124 #endif /* BEO_THS_UNX || DOS_FLX_NLM_OS2_W32 */
125 #ifdef NOVELL_BUG_FAILSAFE
126 static ZCONST char Far NovellBug[] =
127 "error: %s: stat() says does not exist, but fopen() found anyway\n";
128 #endif
129 static ZCONST char Far CannotCreateFile[] = "error: cannot create %s\n";
130 #endif /* !TANDEM */
131 #endif /* !VMS && !AOS_VS && !CMS_MVS && !MACOS */
133 static ZCONST char Far ReadError[] = "error: zipfile read error\n";
134 static ZCONST char Far FilenameTooLongTrunc[] =
135 "warning: filename too long--truncating.\n";
136 static ZCONST char Far ExtraFieldTooLong[] =
137 "warning: extra field too long (%d). Ignoring...\n";
139 #ifdef WINDLL
140 static ZCONST char Far DiskFullQuery[] =
141 "%s: write error (disk full?).\n";
142 #else
143 static ZCONST char Far DiskFullQuery[] =
144 "%s: write error (disk full?). Continue? (y/n/^C) ";
145 static ZCONST char Far ZipfileCorrupt[] =
146 "error: zipfile probably corrupt (%s)\n";
147 # ifdef SYMLINKS
148 static ZCONST char Far FileIsSymLink[] =
149 "%s exists and is a symbolic link%s.\n";
150 # endif
151 # ifdef MORE
152 static ZCONST char Far MorePrompt[] = "--More--(%lu)";
153 # endif
154 static ZCONST char Far QuitPrompt[] =
155 "--- Press `Q' to quit, or any other key to continue ---";
156 static ZCONST char Far HidePrompt[] = /* "\r \r"; */
157 "\r \r";
158 # if CRYPT
159 # ifdef MACOS
160 /* SPC: are names on MacOS REALLY so much longer than elsewhere ??? */
161 static ZCONST char Far PasswPrompt[] = "[%s]\n %s password: ";
162 # else
163 static ZCONST char Far PasswPrompt[] = "[%s] %s password: ";
164 # endif
165 static ZCONST char Far PasswPrompt2[] = "Enter password: ";
166 static ZCONST char Far PasswRetry[] = "password incorrect--reenter: ";
167 # endif /* CRYPT */
168 #endif /* !WINDLL */
174 /******************************/
175 /* Function open_input_file() */
176 /******************************/
178 int open_input_file(__G) /* return 1 if open failed */
179 __GDEF
182 * open the zipfile for reading and in BINARY mode to prevent cr/lf
183 * translation, which would corrupt the bitstreams
186 #ifdef VMS
187 G.zipfd = open(G.zipfn, O_RDONLY, 0, "ctx=stm");
188 #else /* !VMS */
189 #ifdef MACOS
190 G.zipfd = open(G.zipfn, 0);
191 #else /* !MACOS */
192 #ifdef CMS_MVS
193 G.zipfd = vmmvs_open_infile(__G);
194 #else /* !CMS_MVS */
195 #ifdef USE_STRM_INPUT
196 G.zipfd = fopen(G.zipfn, FOPR);
197 #else /* !USE_STRM_INPUT */
198 # ifdef O_BINARY
199 G.zipfd = open(G.zipfn, O_RDONLY | O_BINARY);
200 # else
201 G.zipfd = open(G.zipfn, O_RDONLY);
202 # endif
203 #endif /* ?USE_STRM_INPUT */
204 #endif /* ?CMS_MVS */
205 #endif /* ?MACOS */
206 #endif /* ?VMS */
208 #ifdef USE_STRM_INPUT
209 if (G.zipfd == NULL)
210 #else
211 /* if (G.zipfd < 0) */ /* no good for Windows CE port */
212 if (G.zipfd == -1)
213 #endif
215 Info(slide, 0x401, ((char *)slide, LoadFarString(CannotOpenZipfile),
216 G.zipfn));
217 return 1;
219 return 0;
221 } /* end function open_input_file() */
226 #if (!defined(VMS) && !defined(AOS_VS) && !defined(CMS_MVS) && !defined(MACOS))
227 #if (!defined(TANDEM))
229 /***************************/
230 /* Function open_outfile() */
231 /***************************/
233 int open_outfile(__G) /* return 1 if fail */
234 __GDEF
236 #ifdef DLL
237 if (G.redirect_data)
238 return (redirect_outfile(__G) == FALSE);
239 #endif
240 #ifdef QDOS
241 QFilename(__G__ G.filename);
242 #endif
243 #if (defined(DOS_FLX_NLM_OS2_W32) || defined(BEO_THS_UNX))
244 #ifdef BORLAND_STAT_BUG
245 /* Borland 5.0's stat() barfs if the filename has no extension and the
246 * file doesn't exist. */
247 if (access(G.filename, 0) == -1) {
248 FILE *tmp = fopen(G.filename, "wb+");
250 /* file doesn't exist, so create a dummy file to keep stat() from
251 * failing (will be over-written anyway) */
252 fputc('0', tmp); /* just to have something in the file */
253 fclose(tmp);
255 #endif /* BORLAND_STAT_BUG */
256 #ifdef SYMLINKS
257 if (SSTAT(G.filename, &G.statbuf) == 0 || lstat(G.filename,&G.statbuf) == 0)
258 #else
259 if (SSTAT(G.filename, &G.statbuf) == 0)
260 #endif /* ?SYMLINKS */
262 Trace((stderr, "open_outfile: stat(%s) returns 0: file exists\n",
263 FnFilter1(G.filename)));
264 #ifdef UNIXBACKUP
265 if (uO.B_flag) { /* do backup */
266 char *tname;
267 struct stat tmpstat;
268 int blen, flen, tlen;
270 blen = strlen(BackupSuffix);
271 flen = strlen(G.filename);
272 tlen = flen + blen + 6; /* includes space for 5 digits */
273 if (tlen >= FILNAMSIZ) { /* in case name is too long, truncate */
274 tname = (char *)malloc(FILNAMSIZ);
275 if (tname == NULL)
276 return 1; /* in case we run out of space */
277 tlen = FILNAMSIZ - 1 - blen;
278 strcpy(tname, G.filename); /* make backup name */
279 tname[tlen] = '\0';
280 if (flen > tlen) flen = tlen;
281 tlen = FILNAMSIZ;
282 } else {
283 tname = (char *)malloc(tlen);
284 if (tname == NULL)
285 return 1; /* in case we run out of space */
286 strcpy(tname, G.filename); /* make backup name */
288 strcpy(tname+flen, BackupSuffix);
290 if (IS_OVERWRT_ALL) {
291 /* If there is a previous backup file, delete it,
292 * otherwise the following rename operation may fail.
294 if (SSTAT(tname, &tmpstat) == 0)
295 unlink(tname);
296 } else {
297 /* Check if backupname exists, and, if it's true, try
298 * appending numbers of up to 5 digits to the BackupSuffix,
299 * until an unused name is found.
301 unsigned maxtail, i;
302 char *numtail = tname + flen + blen;
304 maxtail = 65535;
305 switch (tlen - flen - blen - 1) {
306 case 4: maxtail = 9999; break;
307 case 3: maxtail = 999; break;
308 case 2: maxtail = 99; break;
309 case 1: maxtail = 9; break;
310 case 0: maxtail = 0; break;
312 /* while filename exists */
313 for (i = 0; (i <= maxtail) && (SSTAT(tname, &tmpstat) == 0);)
314 sprintf(numtail,"%u", ++i);
317 if (rename(G.filename, tname) != 0) { /* move file */
318 Info(slide, 0x401, ((char *)slide,
319 LoadFarString(CannotRenameOldFile), FnFilter1(G.filename)));
320 free(tname);
321 return 1;
323 Trace((stderr, "open_outfile: %s now renamed into %s\n",
324 FnFilter1(G.filename), FnFilter2(tname)));
325 free(tname);
326 } else
327 #endif /* UNIXBACKUP */
329 #ifdef DOS_FLX_OS2_W32
330 if (!(G.statbuf.st_mode & S_IWRITE)) {
331 Trace((stderr,
332 "open_outfile: existing file %s is read-only\n",
333 FnFilter1(G.filename)));
334 chmod(G.filename, S_IREAD | S_IWRITE);
335 Trace((stderr, "open_outfile: %s now writable\n",
336 FnFilter1(G.filename)));
338 #endif /* DOS_FLX_OS2_W32 */
339 #ifdef NLM
340 /* Give the file read/write permission (non-POSIX shortcut) */
341 chmod(G.filename, 0);
342 #endif /* NLM */
343 if (unlink(G.filename) != 0) {
344 Info(slide, 0x401, ((char *)slide,
345 LoadFarString(CannotDeleteOldFile), FnFilter1(G.filename)));
346 return 1;
348 Trace((stderr, "open_outfile: %s now deleted\n",
349 FnFilter1(G.filename)));
352 #endif /* DOS_FLX_NLM_OS2_W32 || BEO_THS_UNX */
353 #ifdef RISCOS
354 if (SWI_OS_File_7(G.filename,0xDEADDEAD,0xDEADDEAD,G.lrec.ucsize)!=NULL) {
355 Info(slide, 1, ((char *)slide, LoadFarString(CannotCreateFile),
356 FnFilter1(G.filename)));
357 return 1;
359 #endif /* RISCOS */
360 #ifdef TOPS20
361 char *tfilnam;
363 if ((tfilnam = (char *)malloc(2*strlen(G.filename)+1)) == (char *)NULL)
364 return 1;
365 strcpy(tfilnam, G.filename);
366 upper(tfilnam);
367 enquote(tfilnam);
368 if ((G.outfile = fopen(tfilnam, FOPW)) == (FILE *)NULL) {
369 Info(slide, 1, ((char *)slide, LoadFarString(CannotCreateFile),
370 tfilnam));
371 free(tfilnam);
372 return 1;
374 free(tfilnam);
375 #else /* !TOPS20 */
376 #ifdef MTS
377 if (uO.aflag)
378 G.outfile = fopen(G.filename, FOPWT);
379 else
380 G.outfile = fopen(G.filename, FOPW);
381 if (G.outfile == (FILE *)NULL) {
382 Info(slide, 1, ((char *)slide, LoadFarString(CannotCreateFile),
383 FnFilter1(G.filename)));
384 return 1;
386 #else /* !MTS */
387 #ifdef DEBUG
388 Info(slide, 1, ((char *)slide,
389 "open_outfile: doing fopen(%s) for reading\n", FnFilter1(G.filename)));
390 if ((G.outfile = fopen(G.filename, FOPR)) == (FILE *)NULL)
391 Info(slide, 1, ((char *)slide,
392 "open_outfile: fopen(%s) for reading failed: does not exist\n",
393 FnFilter1(G.filename)));
394 else {
395 Info(slide, 1, ((char *)slide,
396 "open_outfile: fopen(%s) for reading succeeded: file exists\n",
397 FnFilter1(G.filename)));
398 fclose(G.outfile);
400 #endif /* DEBUG */
401 #ifdef NOVELL_BUG_FAILSAFE
402 if (G.dne && ((G.outfile = fopen(G.filename, FOPR)) != (FILE *)NULL)) {
403 Info(slide, 0x401, ((char *)slide, LoadFarString(NovellBug),
404 FnFilter1(G.filename)));
405 fclose(G.outfile);
406 return 1; /* with "./" fix in checkdir(), should never reach here */
408 #endif /* NOVELL_BUG_FAILSAFE */
409 Trace((stderr, "open_outfile: doing fopen(%s) for writing\n",
410 FnFilter1(G.filename)));
411 if ((G.outfile = fopen(G.filename, FOPW)) == (FILE *)NULL) {
412 Info(slide, 0x401, ((char *)slide, LoadFarString(CannotCreateFile),
413 FnFilter1(G.filename)));
414 return 1;
416 Trace((stderr, "open_outfile: fopen(%s) for writing succeeded\n",
417 FnFilter1(G.filename)));
418 #endif /* !MTS */
419 #endif /* !TOPS20 */
421 #ifdef USE_FWRITE
422 #ifdef DOS_NLM_OS2_W32
423 /* 16-bit MSC: buffer size must be strictly LESS than 32K (WSIZE): bogus */
424 setbuf(G.outfile, (char *)NULL); /* make output unbuffered */
425 #else /* !DOS_NLM_OS2_W32 */
426 #ifndef RISCOS
427 #ifdef _IOFBF /* make output fully buffered (works just about like write()) */
428 setvbuf(G.outfile, (char *)slide, _IOFBF, WSIZE);
429 #else
430 setbuf(G.outfile, (char *)slide);
431 #endif
432 #endif /* !RISCOS */
433 #endif /* ?DOS_NLM_OS2_W32 */
434 #endif /* USE_FWRITE */
435 #ifdef OS2_W32
436 /* preallocate the final file size to prevent file fragmentation */
437 SetFileSize(G.outfile, G.pInfo->uncompr_size);
438 #endif
439 return 0;
441 } /* end function open_outfile() */
443 #endif /* !TANDEM */
444 #endif /* !VMS && !AOS_VS && !CMS_MVS && !MACOS */
451 * These functions allow NEXTBYTE to function without needing two bounds
452 * checks. Call defer_leftover_input() if you ever have filled G.inbuf
453 * by some means other than readbyte(), and you then want to start using
454 * NEXTBYTE. When going back to processing bytes without NEXTBYTE, call
455 * undefer_input(). For example, extract_or_test_member brackets its
456 * central section that does the decompression with these two functions.
457 * If you need to check the number of bytes remaining in the current
458 * file while using NEXTBYTE, check (G.csize + G.incnt), not G.csize.
461 /****************************/
462 /* function undefer_input() */
463 /****************************/
465 void undefer_input(__G)
466 __GDEF
468 if (G.incnt > 0)
469 G.csize += G.incnt;
470 if (G.incnt_leftover > 0) {
471 /* We know that "(G.csize < MAXINT)" so we can cast G.csize to int:
472 * This condition was checked when G.incnt_leftover was set > 0 in
473 * defer_leftover_input(), and it is NOT allowed to touch G.csize
474 * before calling undefer_input() when (G.incnt_leftover > 0)
475 * (single exception: see read_byte()'s "G.csize <= 0" handling) !!
477 G.incnt = G.incnt_leftover + (int)G.csize;
478 G.inptr = G.inptr_leftover - (int)G.csize;
479 G.incnt_leftover = 0;
480 } else if (G.incnt < 0)
481 G.incnt = 0;
482 } /* end function undefer_input() */
488 /***********************************/
489 /* function defer_leftover_input() */
490 /***********************************/
492 void defer_leftover_input(__G)
493 __GDEF
495 if ((long)G.incnt > G.csize) {
496 /* (G.csize < MAXINT), we can safely cast it to int !! */
497 if (G.csize < 0L)
498 G.csize = 0L;
499 G.inptr_leftover = G.inptr + (int)G.csize;
500 G.incnt_leftover = G.incnt - (int)G.csize;
501 G.incnt = (int)G.csize;
502 } else
503 G.incnt_leftover = 0;
504 G.csize -= G.incnt;
505 } /* end function defer_leftover_input() */
511 /**********************/
512 /* Function readbuf() */
513 /**********************/
515 unsigned readbuf(__G__ buf, size) /* return number of bytes read into buf */
516 __GDEF
517 char *buf;
518 register unsigned size;
520 register unsigned count;
521 unsigned n;
523 n = size;
524 while (size) {
525 if (G.incnt <= 0) {
526 if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) == 0)
527 return (n-size);
528 else if (G.incnt < 0) {
529 /* another hack, but no real harm copying same thing twice */
530 (*G.message)((zvoid *)&G,
531 (uch *)LoadFarString(ReadError), /* CANNOT use slide */
532 (ulg)strlen(LoadFarString(ReadError)), 0x401);
533 return 0; /* discarding some data; better than lock-up */
535 /* buffer ALWAYS starts on a block boundary: */
536 G.cur_zipfile_bufstart += INBUFSIZ;
537 G.inptr = G.inbuf;
539 count = MIN(size, (unsigned)G.incnt);
540 memcpy(buf, G.inptr, count);
541 buf += count;
542 G.inptr += count;
543 G.incnt -= count;
544 size -= count;
546 return n;
548 } /* end function readbuf() */
554 /***********************/
555 /* Function readbyte() */
556 /***********************/
558 int readbyte(__G) /* refill inbuf and return a byte if available, else EOF */
559 __GDEF
561 if (G.mem_mode)
562 return EOF;
563 if (G.csize <= 0) {
564 G.csize--; /* for tests done after exploding */
565 G.incnt = 0;
566 return EOF;
568 if (G.incnt <= 0) {
569 if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) == 0) {
570 G.incnt = 0; /* do not allow negative value to affect stuff */
571 return EOF;
572 } else if (G.incnt < 0) { /* "fail" (abort, retry, ...) returns this */
573 /* another hack, but no real harm copying same thing twice */
574 (*G.message)((zvoid *)&G,
575 (uch *)LoadFarString(ReadError),
576 (ulg)strlen(LoadFarString(ReadError)), 0x401);
577 echon();
578 #ifdef WINDLL
579 longjmp(dll_error_return, 1);
580 #else
581 DESTROYGLOBALS();
582 EXIT(PK_BADERR); /* totally bailing; better than lock-up */
583 #endif
585 G.cur_zipfile_bufstart += INBUFSIZ; /* always starts on block bndry */
586 G.inptr = G.inbuf;
587 defer_leftover_input(__G); /* decrements G.csize */
590 #if CRYPT
591 if (G.pInfo->encrypted) {
592 uch *p;
593 int n;
595 /* This was previously set to decrypt one byte beyond G.csize, when
596 * incnt reached that far. GRR said, "but it's required: why?" This
597 * was a bug in fillinbuf() -- was it also a bug here?
599 for (n = G.incnt, p = G.inptr; n--; p++)
600 zdecode(*p);
602 #endif /* CRYPT */
604 --G.incnt;
605 return *G.inptr++;
607 } /* end function readbyte() */
613 #ifdef USE_ZLIB
615 /************************/
616 /* Function fillinbuf() */
617 /************************/
619 int fillinbuf(__G) /* like readbyte() except returns number of bytes in inbuf */
620 __GDEF
622 if (G.mem_mode ||
623 (G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) <= 0)
624 return 0;
625 G.cur_zipfile_bufstart += INBUFSIZ; /* always starts on a block boundary */
626 G.inptr = G.inbuf;
627 defer_leftover_input(__G); /* decrements G.csize */
629 #if CRYPT
630 if (G.pInfo->encrypted) {
631 uch *p;
632 int n;
634 for (n = G.incnt, p = G.inptr; n--; p++)
635 zdecode(*p);
637 #endif /* CRYPT */
639 return G.incnt;
641 } /* end function fillinbuf() */
643 #endif /* USE_ZLIB */
649 /************************/
650 /* Function seek_zipf() */
651 /************************/
653 int seek_zipf(__G__ abs_offset)
654 __GDEF
655 LONGINT abs_offset;
658 * Seek to the block boundary of the block which includes abs_offset,
659 * then read block into input buffer and set pointers appropriately.
660 * If block is already in the buffer, just set the pointers. This function
661 * is used by do_seekable (process.c), extract_or_test_entrylist (extract.c)
662 * and do_string (fileio.c). Also, a slightly modified version is embedded
663 * within extract_or_test_entrylist (extract.c). readbyte() and readbuf()
664 * (fileio.c) are compatible. NOTE THAT abs_offset is intended to be the
665 * "proper offset" (i.e., if there were no extra bytes prepended);
666 * cur_zipfile_bufstart contains the corrected offset.
668 * Since seek_zipf() is never used during decompression, it is safe to
669 * use the slide[] buffer for the error message.
671 * returns PK error codes:
672 * PK_BADERR if effective offset in zipfile is negative
673 * PK_EOF if seeking past end of zipfile
674 * PK_OK when seek was successful
676 LONGINT request = abs_offset + G.extra_bytes;
677 LONGINT inbuf_offset = request % INBUFSIZ;
678 LONGINT bufstart = request - inbuf_offset;
680 if (request < 0) {
681 Info(slide, 1, ((char *)slide, LoadFarStringSmall(SeekMsg),
682 G.zipfn, LoadFarString(ReportMsg)));
683 return(PK_BADERR);
684 } else if (bufstart != G.cur_zipfile_bufstart) {
685 Trace((stderr,
686 "fpos_zip: abs_offset = %ld, G.extra_bytes = %ld\n",
687 abs_offset, G.extra_bytes));
688 #ifdef USE_STRM_INPUT
689 fseek(G.zipfd, (LONGINT)bufstart, SEEK_SET);
690 G.cur_zipfile_bufstart = ftell(G.zipfd);
691 #else /* !USE_STRM_INPUT */
692 G.cur_zipfile_bufstart = lseek(G.zipfd, (LONGINT)bufstart, SEEK_SET);
693 #endif /* ?USE_STRM_INPUT */
694 Trace((stderr,
695 " request = %ld, (abs+extra) = %ld, inbuf_offset = %ld\n",
696 request, (abs_offset+G.extra_bytes), inbuf_offset));
697 Trace((stderr, " bufstart = %ld, cur_zipfile_bufstart = %ld\n",
698 bufstart, G.cur_zipfile_bufstart));
699 if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) <= 0)
700 return(PK_EOF);
701 G.incnt -= (int)inbuf_offset;
702 G.inptr = G.inbuf + (int)inbuf_offset;
703 } else {
704 G.incnt += (G.inptr-G.inbuf) - (int)inbuf_offset;
705 G.inptr = G.inbuf + (int)inbuf_offset;
707 return(PK_OK);
708 } /* end function seek_zipf() */
714 #ifndef VMS /* for VMS use code in vms.c */
716 /********************/
717 /* Function flush() */ /* returns PK error codes: */
718 /********************/ /* if cflag => always 0; PK_DISK if write error */
720 int flush(__G__ rawbuf, size, unshrink)
721 __GDEF
722 uch *rawbuf;
723 ulg size;
724 int unshrink;
725 #if (defined(USE_DEFLATE64) && defined(__16BIT__))
727 int ret;
729 /* On 16-bit systems (MSDOS, OS/2 1.x), the standard C library functions
730 * cannot handle writes of 64k blocks at once. For these systems, the
731 * blocks to flush are split into pieces of 32k or less.
733 while (size > 0x8000L) {
734 ret = partflush(__G__ rawbuf, 0x8000L, unshrink);
735 if (ret != PK_OK)
736 return ret;
737 size -= 0x8000L;
738 rawbuf += (unsigned)0x8000;
740 return partflush(__G__ rawbuf, size, unshrink);
741 } /* end function flush() */
744 /************************/
745 /* Function partflush() */ /* returns PK error codes: */
746 /************************/ /* if cflag => always 0; PK_DISK if write error */
748 static int partflush(__G__ rawbuf, size, unshrink)
749 __GDEF
750 uch *rawbuf; /* cannot be ZCONST, gets passed to (*G.message)() */
751 ulg size;
752 int unshrink;
753 #endif /* USE_DEFLATE64 && __16BIT__ */
755 register uch *p;
756 register uch *q;
757 uch *transbuf;
758 #if (defined(SMALL_MEM) || defined(MED_MEM) || defined(VMS_TEXT_CONV))
759 ulg transbufsiz;
760 #endif
761 /* static int didCRlast = FALSE; moved to globals.h */
764 /*---------------------------------------------------------------------------
765 Compute the CRC first; if testing or if disk is full, that's it.
766 ---------------------------------------------------------------------------*/
768 G.crc32val = crc32(G.crc32val, rawbuf, (extent)size);
770 #ifdef DLL
771 if ((G.statreportcb != NULL) &&
772 (*G.statreportcb)(__G__ UZ_ST_IN_PROGRESS, G.zipfn, G.filename, NULL))
773 return IZ_CTRLC; /* cancel operation by user request */
774 #endif
776 if (uO.tflag || size == 0L) /* testing or nothing to write: all done */
777 return PK_OK;
779 if (G.disk_full)
780 return PK_DISK; /* disk already full: ignore rest of file */
782 /*---------------------------------------------------------------------------
783 Write the bytes rawbuf[0..size-1] to the output device, first converting
784 end-of-lines and ASCII/EBCDIC as needed. If SMALL_MEM or MED_MEM are NOT
785 defined, outbuf is assumed to be at least as large as rawbuf and is not
786 necessarily checked for overflow.
787 ---------------------------------------------------------------------------*/
789 if (!G.pInfo->textmode) { /* write raw binary data */
790 /* GRR: note that for standard MS-DOS compilers, size argument to
791 * fwrite() can never be more than 65534, so WriteError macro will
792 * have to be rewritten if size can ever be that large. For now,
793 * never more than 32K. Also note that write() returns an int, which
794 * doesn't necessarily limit size to 32767 bytes if write() is used
795 * on 16-bit systems but does make it more of a pain; however, because
796 * at least MSC 5.1 has a lousy implementation of fwrite() (as does
797 * DEC Ultrix cc), write() is used anyway.
799 #ifdef DLL
800 if (G.redirect_data)
801 writeToMemory(__G__ rawbuf, (extent)size);
802 else
803 #endif
804 if (!uO.cflag && WriteError(rawbuf, size, G.outfile))
805 return disk_error(__G);
806 else if (uO.cflag && (*G.message)((zvoid *)&G, rawbuf, size, 0))
807 return PK_OK;
808 } else { /* textmode: aflag is true */
809 if (unshrink) {
810 /* rawbuf = outbuf */
811 transbuf = G.outbuf2;
812 #if (defined(SMALL_MEM) || defined(MED_MEM) || defined(VMS_TEXT_CONV))
813 transbufsiz = TRANSBUFSIZ;
814 #endif
815 } else {
816 /* rawbuf = slide */
817 transbuf = G.outbuf;
818 #if (defined(SMALL_MEM) || defined(MED_MEM) || defined(VMS_TEXT_CONV))
819 transbufsiz = OUTBUFSIZ;
820 Trace((stderr, "\ntransbufsiz = OUTBUFSIZ = %u\n",
821 (unsigned)OUTBUFSIZ));
822 #endif
824 if (G.newfile) {
825 #ifdef VMS_TEXT_CONV
826 if (G.pInfo->hostnum == VMS_ && G.extra_field &&
827 is_vms_varlen_txt(__G__ G.extra_field,
828 G.lrec.extra_field_length))
829 G.VMS_line_state = 0; /* 0: ready to read line length */
830 else
831 G.VMS_line_state = -1; /* -1: don't treat as VMS text */
832 #endif
833 G.didCRlast = FALSE; /* no previous buffers written */
834 G.newfile = FALSE;
837 #ifdef VMS_TEXT_CONV
838 if (G.VMS_line_state >= 0)
840 /* GRR: really want to check for actual VMS extra field, and
841 * ideally for variable-length record format */
843 printf("\n>>>>>> GRR: file is VMS text and has an extra field\n");
846 p = rawbuf;
847 q = transbuf;
848 while (p < rawbuf+(unsigned)size) {
849 switch (G.VMS_line_state) {
851 /* 0: ready to read line length */
852 case 0:
853 G.VMS_line_length = 0;
854 if (p == rawbuf+(unsigned)size-1) { /* last char */
855 G.VMS_line_length = (unsigned)(*p++);
856 G.VMS_line_state = 1;
857 } else {
858 G.VMS_line_length = makeword(p);
859 p += 2;
860 G.VMS_line_state = 2;
862 G.VMS_line_pad =
863 ((G.VMS_line_length & 1) != 0); /* odd */
864 break;
866 /* 1: read one byte of length, need second */
867 case 1:
868 G.VMS_line_length += ((unsigned)(*p++) << 8);
869 G.VMS_line_state = 2;
870 break;
872 /* 2: ready to read VMS_line_length chars */
873 case 2:
875 extent remaining = rawbuf+(unsigned)size-p;
876 extent outroom;
878 if (G.VMS_line_length < remaining) {
879 remaining = G.VMS_line_length;
880 G.VMS_line_state = 3;
883 outroom = transbuf+(unsigned)transbufsiz-q;
884 if (remaining >= outroom) {
885 remaining -= outroom;
886 for (;outroom > 0; p++, outroom--)
887 *q++ = native(*p);
888 #ifdef DLL
889 if (G.redirect_data)
890 writeToMemory(__G__ transbuf,
891 (extent)(q-transbuf));
892 else
893 #endif
894 if (!uO.cflag && WriteError(transbuf,
895 (extent)(q-transbuf), G.outfile))
896 return disk_error(__G);
897 else if (uO.cflag && (*G.message)((zvoid *)&G,
898 transbuf, (ulg)(q-transbuf), 0))
899 return PK_OK;
900 q = transbuf;
901 /* fall through to normal case */
903 G.VMS_line_length -= remaining;
904 for (;remaining > 0; p++, remaining--)
905 *q++ = native(*p);
907 break;
909 /* 3: ready to PutNativeEOL */
910 case 3:
911 if (q > transbuf+(unsigned)transbufsiz-lenEOL) {
912 #ifdef DLL
913 if (G.redirect_data)
914 writeToMemory(__G__ transbuf,
915 (extent)(q-transbuf));
916 else
917 #endif
918 if (!uO.cflag &&
919 WriteError(transbuf, (extent)(q-transbuf),
920 G.outfile))
921 return disk_error(__G);
922 else if (uO.cflag && (*G.message)((zvoid *)&G,
923 transbuf, (ulg)(q-transbuf), 0))
924 return PK_OK;
925 q = transbuf;
927 PutNativeEOL
928 G.VMS_line_state = G.VMS_line_pad ? 4 : 0;
929 break;
931 /* 4: ready to read pad byte */
932 case 4:
933 ++p;
934 G.VMS_line_state = 0;
935 break;
937 } /* end while */
939 } else
940 #endif /* VMS_TEXT_CONV */
942 /*-----------------------------------------------------------------------
943 Algorithm: CR/LF => native; lone CR => native; lone LF => native.
944 This routine is only for non-raw-VMS, non-raw-VM/CMS files (i.e.,
945 stream-oriented files, not record-oriented).
946 -----------------------------------------------------------------------*/
948 /* else not VMS text */ {
949 p = rawbuf;
950 if (*p == LF && G.didCRlast)
951 ++p;
952 G.didCRlast = FALSE;
953 for (q = transbuf; p < rawbuf+(unsigned)size; ++p) {
954 if (*p == CR) { /* lone CR or CR/LF: treat as EOL */
955 PutNativeEOL
956 if (p == rawbuf+(unsigned)size-1) /* last char in buffer */
957 G.didCRlast = TRUE;
958 else if (p[1] == LF) /* get rid of accompanying LF */
959 ++p;
960 } else if (*p == LF) /* lone LF */
961 PutNativeEOL
962 else
963 #ifndef DOS_FLX_OS2_W32
964 if (*p != CTRLZ) /* lose all ^Z's */
965 #endif
966 *q++ = native(*p);
968 #if (defined(SMALL_MEM) || defined(MED_MEM))
969 # if (lenEOL == 1) /* don't check unshrink: both buffers small but equal */
970 if (!unshrink)
971 # endif
972 /* check for danger of buffer overflow and flush */
973 if (q > transbuf+(unsigned)transbufsiz-lenEOL) {
974 Trace((stderr,
975 "p - rawbuf = %u q-transbuf = %u size = %lu\n",
976 (unsigned)(p-rawbuf), (unsigned)(q-transbuf), size));
977 if (!uO.cflag && WriteError(transbuf,
978 (extent)(q-transbuf), G.outfile))
979 return disk_error(__G);
980 else if (uO.cflag && (*G.message)((zvoid *)&G,
981 transbuf, (ulg)(q-transbuf), 0))
982 return PK_OK;
983 q = transbuf;
984 continue;
986 #endif /* SMALL_MEM || MED_MEM */
990 /*-----------------------------------------------------------------------
991 Done translating: write whatever we've got to file (or screen).
992 -----------------------------------------------------------------------*/
994 Trace((stderr, "p - rawbuf = %u q-transbuf = %u size = %lu\n",
995 (unsigned)(p-rawbuf), (unsigned)(q-transbuf), size));
996 if (q > transbuf) {
997 #ifdef DLL
998 if (G.redirect_data)
999 writeToMemory(__G__ transbuf, (extent)(q-transbuf));
1000 else
1001 #endif
1002 if (!uO.cflag && WriteError(transbuf, (extent)(q-transbuf),
1003 G.outfile))
1004 return disk_error(__G);
1005 else if (uO.cflag && (*G.message)((zvoid *)&G, transbuf,
1006 (ulg)(q-transbuf), 0))
1007 return PK_OK;
1011 return PK_OK;
1013 } /* end function flush() [resp. partflush() for 16-bit Deflate64 support] */
1019 #ifdef VMS_TEXT_CONV
1021 /********************************/
1022 /* Function is_vms_varlen_txt() */
1023 /********************************/
1025 static int is_vms_varlen_txt(__G__ ef_buf, ef_len)
1026 __GDEF
1027 uch *ef_buf; /* buffer containing extra field */
1028 unsigned ef_len; /* total length of extra field */
1030 unsigned eb_id;
1031 unsigned eb_len;
1032 uch *eb_data;
1033 unsigned eb_datlen;
1034 #define VMSREC_C_UNDEF 0
1035 #define VMSREC_C_VAR 2
1036 uch vms_rectype = VMSREC_C_UNDEF;
1037 uch vms_fileorg = 0;
1039 #define VMSPK_ITEMID 0
1040 #define VMSPK_ITEMLEN 2
1041 #define VMSPK_ITEMHEADSZ 4
1043 #define VMSATR_C_RECATTR 4
1044 #define VMS_FABSIG 0x42414656 /* "VFAB" */
1045 /* offsets of interesting fields in VMS fabdef structure */
1046 #define VMSFAB_B_RFM 31 /* record format byte */
1047 #define VMSFAB_B_ORG 29 /* file organization byte */
1049 if (ef_len == 0 || ef_buf == NULL)
1050 return FALSE;
1052 while (ef_len >= EB_HEADSIZE) {
1053 eb_id = makeword(EB_ID + ef_buf);
1054 eb_len = makeword(EB_LEN + ef_buf);
1056 if (eb_len > (ef_len - EB_HEADSIZE)) {
1057 /* discovered some extra field inconsistency! */
1058 Trace((stderr,
1059 "is_vms_varlen_txt: block length %u > rest ef_size %u\n", eb_len,
1060 ef_len - EB_HEADSIZE));
1061 break;
1064 switch (eb_id) {
1065 case EF_PKVMS:
1066 /* The PKVMS e.f. raw data part consists of:
1067 * a) 4 bytes CRC checksum
1068 * b) list of uncompressed variable-length data items
1069 * Each data item is introduced by a fixed header
1070 * - 2 bytes data type ID
1071 * - 2 bytes <size> of data
1072 * - <size> bytes of actual attribute data
1075 /* get pointer to start of data and its total length */
1076 eb_data = ef_buf+(EB_HEADSIZE+4);
1077 eb_datlen = eb_len-4;
1079 /* test the CRC checksum */
1080 if (makelong(ef_buf+EB_HEADSIZE) !=
1081 crc32(CRCVAL_INITIAL, eb_data, (extent)eb_datlen))
1083 Info(slide, 1, ((char *)slide,
1084 "[Warning: CRC error, discarding PKWARE extra field]\n"));
1085 /* skip over the data analysis code */
1086 break;
1089 /* scan through the attribute data items */
1090 while (eb_datlen > 4)
1092 unsigned fldsize = makeword(&eb_data[VMSPK_ITEMLEN]);
1094 /* check the item type word */
1095 switch (makeword(&eb_data[VMSPK_ITEMID])) {
1096 case VMSATR_C_RECATTR:
1097 /* we have found the (currently only) interesting
1098 * data item */
1099 if (fldsize >= 1) {
1100 vms_rectype = eb_data[VMSPK_ITEMHEADSZ] & 15;
1101 vms_fileorg = eb_data[VMSPK_ITEMHEADSZ] >> 4;
1103 break;
1104 default:
1105 break;
1107 /* skip to next data item */
1108 eb_datlen -= fldsize + VMSPK_ITEMHEADSZ;
1109 eb_data += fldsize + VMSPK_ITEMHEADSZ;
1111 break;
1113 case EF_IZVMS:
1114 if (makelong(ef_buf+EB_HEADSIZE) == VMS_FABSIG) {
1115 if ((eb_data = extract_izvms_block(__G__
1116 ef_buf+EB_HEADSIZE, eb_len,
1117 &eb_datlen, NULL, 0))
1118 != NULL)
1120 if (eb_datlen >= VMSFAB_B_RFM+1) {
1121 vms_rectype = eb_data[VMSFAB_B_RFM] & 15;
1122 vms_fileorg = eb_data[VMSFAB_B_ORG] >> 4;
1124 free(eb_data);
1127 break;
1129 default:
1130 break;
1133 /* Skip this extra field block */
1134 ef_buf += (eb_len + EB_HEADSIZE);
1135 ef_len -= (eb_len + EB_HEADSIZE);
1138 return (vms_rectype == VMSREC_C_VAR);
1140 } /* end function is_vms_varlen_txtfile() */
1142 #endif /* VMS_TEXT_CONV */
1147 /*************************/
1148 /* Function disk_error() */
1149 /*************************/
1151 static int disk_error(__G)
1152 __GDEF
1154 /* OK to use slide[] here because this file is finished regardless */
1155 Info(slide, 0x4a1, ((char *)slide, LoadFarString(DiskFullQuery),
1156 FnFilter1(G.filename)));
1158 #ifndef WINDLL
1159 fgets(G.answerbuf, 9, stdin);
1160 if (*G.answerbuf == 'y') /* stop writing to this file */
1161 G.disk_full = 1; /* (outfile bad?), but new OK */
1162 else
1163 #endif
1164 G.disk_full = 2; /* no: exit program */
1166 return PK_DISK;
1168 } /* end function disk_error() */
1170 #endif /* !VMS */
1176 /*****************************/
1177 /* Function UzpMessagePrnt() */
1178 /*****************************/
1180 int UZ_EXP UzpMessagePrnt(pG, buf, size, flag)
1181 zvoid *pG; /* globals struct: always passed */
1182 uch *buf; /* preformatted string to be printed */
1183 ulg size; /* length of string (may include nulls) */
1184 int flag; /* flag bits */
1186 /* IMPORTANT NOTE:
1187 * The name of the first parameter of UzpMessagePrnt(), which passes
1188 * the "Uz_Globs" address, >>> MUST <<< be identical to the string
1189 * expansion of the __G__ macro in the REENTRANT case (see globals.h).
1190 * This name identity is mandatory for the LoadFarString() macro
1191 * (in the SMALL_MEM case) !!!
1193 int error;
1194 uch *q=buf, *endbuf=buf+(unsigned)size;
1195 #ifdef MORE
1196 uch *p=buf;
1197 #if (defined(SCREENWIDTH) && defined(SCREENLWRAP))
1198 int islinefeed = FALSE;
1199 #endif
1200 #endif
1201 FILE *outfp;
1204 /*---------------------------------------------------------------------------
1205 These tests are here to allow fine-tuning of UnZip's output messages,
1206 but none of them will do anything without setting the appropriate bit
1207 in the flag argument of every Info() statement which is to be turned
1208 *off*. That is, all messages are currently turned on for all ports.
1209 To turn off *all* messages, use the UzpMessageNull() function instead
1210 of this one.
1211 ---------------------------------------------------------------------------*/
1213 #if (defined(OS2) && defined(DLL))
1214 if (MSG_NO_DLL2(flag)) /* if OS/2 DLL bit is set, do NOT print this msg */
1215 return 0;
1216 #endif
1217 #ifdef WINDLL
1218 if (MSG_NO_WDLL(flag))
1219 return 0;
1220 #endif
1221 #ifdef WINDLL
1222 if (MSG_NO_WGUI(flag))
1223 return 0;
1224 #endif
1226 #ifdef ACORN_GUI
1227 if (MSG_NO_AGUI(flag))
1228 return 0;
1229 #endif
1231 #ifdef DLL /* don't display message if data is redirected */
1232 if (((Uz_Globs *)pG)->redirect_data &&
1233 !((Uz_Globs *)pG)->redirect_text)
1234 return 0;
1235 #endif
1237 if (MSG_STDERR(flag) && !((Uz_Globs *)pG)->UzO.tflag)
1238 outfp = (FILE *)stderr;
1239 else
1240 outfp = (FILE *)stdout;
1242 #ifdef QUERY_TRNEWLN
1243 /* some systems require termination of query prompts with '\n' to force
1244 * immediate display */
1245 if (MSG_MNEWLN(flag)) { /* assumes writable buffer (e.g., slide[]) */
1246 *endbuf++ = '\n'; /* with room for one more char at end of buf */
1247 ++size; /* (safe assumption: only used for four */
1248 } /* short queries in extract.c and fileio.c) */
1249 #endif
1251 if (MSG_TNEWLN(flag)) { /* again assumes writable buffer: fragile... */
1252 if ((!size && !((Uz_Globs *)pG)->sol) ||
1253 (size && (endbuf[-1] != '\n')))
1255 *endbuf++ = '\n';
1256 ++size;
1260 #ifdef MORE
1261 # ifdef SCREENSIZE
1262 /* room for --More-- and one line of overlap: */
1263 # if (defined(SCREENWIDTH) && defined(SCREENLWRAP))
1264 SCREENSIZE(&((Uz_Globs *)pG)->height, &((Uz_Globs *)pG)->width);
1265 # else
1266 SCREENSIZE(&((Uz_Globs *)pG)->height, (int *)NULL);
1267 # endif
1268 ((Uz_Globs *)pG)->height -= 2;
1269 # else
1270 /* room for --More-- and one line of overlap: */
1271 ((Uz_Globs *)pG)->height = SCREENLINES - 2;
1272 # if (defined(SCREENWIDTH) && defined(SCREENLWRAP))
1273 ((Uz_Globs *)pG)->width = SCREENWIDTH;
1274 # endif
1275 # endif
1276 #endif /* MORE */
1278 if (MSG_LNEWLN(flag) && !((Uz_Globs *)pG)->sol) {
1279 /* not at start of line: want newline */
1280 #ifdef OS2DLL
1281 if (!((Uz_Globs *)pG)->redirect_text) {
1282 #endif
1283 putc('\n', outfp);
1284 fflush(outfp);
1285 #ifdef MORE
1286 if (((Uz_Globs *)pG)->M_flag)
1288 #if (defined(SCREENWIDTH) && defined(SCREENLWRAP))
1289 ((Uz_Globs *)pG)->chars = 0;
1290 #endif
1291 ++((Uz_Globs *)pG)->numlines;
1292 ++((Uz_Globs *)pG)->lines;
1293 if (((Uz_Globs *)pG)->lines >= ((Uz_Globs *)pG)->height)
1294 (*((Uz_Globs *)pG)->mpause)((zvoid *)pG,
1295 LoadFarString(MorePrompt), 1);
1297 #endif /* MORE */
1298 if (MSG_STDERR(flag) && ((Uz_Globs *)pG)->UzO.tflag &&
1299 !isatty(1) && isatty(2))
1301 /* error output from testing redirected: also send to stderr */
1302 putc('\n', stderr);
1303 fflush(stderr);
1305 #ifdef OS2DLL
1306 } else
1307 REDIRECTC('\n');
1308 #endif
1309 ((Uz_Globs *)pG)->sol = TRUE;
1312 /* put zipfile name, filename and/or error/warning keywords here */
1314 #ifdef MORE
1315 if (((Uz_Globs *)pG)->M_flag
1316 #ifdef OS2DLL
1317 && !((Uz_Globs *)pG)->redirect_text
1318 #endif
1321 while (p < endbuf) {
1322 if (*p == '\n') {
1323 #if (defined(SCREENWIDTH) && defined(SCREENLWRAP))
1324 islinefeed = TRUE;
1325 } else if (SCREENLWRAP) {
1326 if (*p == '\r') {
1327 ((Uz_Globs *)pG)->chars = 0;
1328 } else {
1329 # ifdef TABSIZE
1330 if (*p == '\t')
1331 ((Uz_Globs *)pG)->chars +=
1332 (TABSIZE - (((Uz_Globs *)pG)->chars % TABSIZE));
1333 else
1334 # endif
1335 ++((Uz_Globs *)pG)->chars;
1337 if (((Uz_Globs *)pG)->chars >= ((Uz_Globs *)pG)->width)
1338 islinefeed = TRUE;
1341 if (islinefeed) {
1342 islinefeed = FALSE;
1343 ((Uz_Globs *)pG)->chars = 0;
1344 #endif /* (SCREENWIDTH && SCREEN_LWRAP) */
1345 ++((Uz_Globs *)pG)->numlines;
1346 ++((Uz_Globs *)pG)->lines;
1347 if (((Uz_Globs *)pG)->lines >= ((Uz_Globs *)pG)->height)
1349 if ((error = WriteError(q, p-q+1, outfp)) != 0)
1350 return error;
1351 fflush(outfp);
1352 ((Uz_Globs *)pG)->sol = TRUE;
1353 q = p + 1;
1354 (*((Uz_Globs *)pG)->mpause)((zvoid *)pG,
1355 LoadFarString(MorePrompt), 1);
1358 INCSTR(p);
1359 } /* end while */
1360 size = (ulg)(p - q); /* remaining text */
1362 #endif /* MORE */
1364 if (size) {
1365 #ifdef OS2DLL
1366 if (!((Uz_Globs *)pG)->redirect_text) {
1367 #endif
1368 if ((error = WriteError(q, size, outfp)) != 0)
1369 return error;
1370 fflush(outfp);
1371 if (MSG_STDERR(flag) && ((Uz_Globs *)pG)->UzO.tflag &&
1372 !isatty(1) && isatty(2))
1374 /* error output from testing redirected: also send to stderr */
1375 if ((error = WriteError(q, size, stderr)) != 0)
1376 return error;
1377 fflush(stderr);
1379 #ifdef OS2DLL
1380 } else { /* GRR: this is ugly: hide with macro */
1381 if ((error = REDIRECTPRINT(q, size)) != 0)
1382 return error;
1384 #endif /* OS2DLL */
1385 ((Uz_Globs *)pG)->sol = (endbuf[-1] == '\n');
1387 return 0;
1389 } /* end function UzpMessagePrnt() */
1395 #ifdef DLL
1397 /*****************************/
1398 /* Function UzpMessageNull() */ /* convenience routine for no output at all */
1399 /*****************************/
1401 int UZ_EXP UzpMessageNull(pG, buf, size, flag)
1402 zvoid *pG; /* globals struct: always passed */
1403 uch *buf; /* preformatted string to be printed */
1404 ulg size; /* length of string (may include nulls) */
1405 int flag; /* flag bits */
1407 return 0;
1409 } /* end function UzpMessageNull() */
1411 #endif /* DLL */
1417 /***********************/
1418 /* Function UzpInput() */ /* GRR: this is a placeholder for now */
1419 /***********************/
1421 int UZ_EXP UzpInput(pG, buf, size, flag)
1422 zvoid *pG; /* globals struct: always passed */
1423 uch *buf; /* preformatted string to be printed */
1424 int *size; /* (address of) size of buf and of returned string */
1425 int flag; /* flag bits (bit 0: no echo) */
1427 /* tell picky compilers to shut up about "unused variable" warnings */
1428 pG = pG; buf = buf; flag = flag;
1430 *size = 0;
1431 return 0;
1433 } /* end function UzpInput() */
1439 #if (!defined(WINDLL) && !defined(MACOS))
1441 /***************************/
1442 /* Function UzpMorePause() */
1443 /***************************/
1445 void UZ_EXP UzpMorePause(pG, prompt, flag)
1446 zvoid *pG; /* globals struct: always passed */
1447 ZCONST char *prompt; /* "--More--" prompt */
1448 int flag; /* 0 = any char OK; 1 = accept only '\n', ' ', q */
1450 uch c;
1452 /*---------------------------------------------------------------------------
1453 Print a prompt and wait for the user to press a key, then erase prompt
1454 if possible.
1455 ---------------------------------------------------------------------------*/
1457 if (!((Uz_Globs *)pG)->sol)
1458 fprintf(stderr, "\n");
1459 /* numlines may or may not be used: */
1460 fprintf(stderr, prompt, ((Uz_Globs *)pG)->numlines);
1461 fflush(stderr);
1462 if (flag & 1) {
1463 do {
1464 c = (uch)FGETCH(0);
1465 } while (
1466 #ifdef THEOS
1467 c != 17 && /* standard QUIT key */
1468 #endif
1469 c != '\r' && c != '\n' && c != ' ' && c != 'q' && c != 'Q');
1470 } else
1471 c = (uch)FGETCH(0);
1473 /* newline was not echoed, so cover up prompt line */
1474 fprintf(stderr, LoadFarString(HidePrompt));
1475 fflush(stderr);
1477 if (
1478 #ifdef THEOS
1479 (c == 17) || /* standard QUIT key */
1480 #endif
1481 (ToLower(c) == 'q')) {
1482 DESTROYGLOBALS();
1483 EXIT(PK_COOL);
1486 ((Uz_Globs *)pG)->sol = TRUE;
1488 #ifdef MORE
1489 /* space for another screen, enter for another line. */
1490 if ((flag & 1) && c == ' ')
1491 ((Uz_Globs *)pG)->lines = 0;
1492 #endif /* MORE */
1494 } /* end function UzpMorePause() */
1496 #endif /* !WINDLL && !MACOS */
1501 #ifndef WINDLL
1503 /**************************/
1504 /* Function UzpPassword() */
1505 /**************************/
1507 int UZ_EXP UzpPassword (pG, rcnt, pwbuf, size, zfn, efn)
1508 zvoid *pG; /* pointer to UnZip's internal global vars */
1509 int *rcnt; /* retry counter */
1510 char *pwbuf; /* buffer for password */
1511 int size; /* size of password buffer */
1512 ZCONST char *zfn; /* name of zip archive */
1513 ZCONST char *efn; /* name of archive entry being processed */
1515 #if CRYPT
1516 int r = IZ_PW_ENTERED;
1517 char *m;
1518 char *prompt;
1520 #ifndef REENTRANT
1521 /* tell picky compilers to shut up about "unused variable" warnings */
1522 pG = pG;
1523 #endif
1525 if (*rcnt == 0) { /* First call for current entry */
1526 *rcnt = 2;
1527 if ((prompt = (char *)malloc(2*FILNAMSIZ + 15)) != (char *)NULL) {
1528 sprintf(prompt, LoadFarString(PasswPrompt),
1529 FnFilter1(zfn), FnFilter2(efn));
1530 m = prompt;
1531 } else
1532 m = (char *)LoadFarString(PasswPrompt2);
1533 } else { /* Retry call, previous password was wrong */
1534 (*rcnt)--;
1535 prompt = NULL;
1536 m = (char *)LoadFarString(PasswRetry);
1539 m = getp(__G__ m, pwbuf, size);
1540 if (prompt != (char *)NULL) {
1541 free(prompt);
1543 if (m == (char *)NULL) {
1544 r = IZ_PW_ERROR;
1546 else if (*pwbuf == '\0') {
1547 r = IZ_PW_CANCELALL;
1549 return r;
1551 #else /* !CRYPT */
1552 /* tell picky compilers to shut up about "unused variable" warnings */
1553 pG = pG; rcnt = rcnt; pwbuf = pwbuf; size = size; zfn = zfn; efn = efn;
1555 return IZ_PW_ERROR; /* internal error; function should never get called */
1556 #endif /* ?CRYPT */
1558 } /* end function UzpPassword() */
1564 /**********************/
1565 /* Function handler() */
1566 /**********************/
1568 void handler(signal) /* upon interrupt, turn on echo and exit cleanly */
1569 int signal;
1571 GETGLOBALS();
1573 #if !(defined(SIGBUS) || defined(SIGSEGV)) /* add a newline if not at */
1574 (*G.message)((zvoid *)&G, slide, 0L, 0x41); /* start of line (to stderr; */
1575 #endif /* slide[] should be safe) */
1577 echon();
1579 #ifdef SIGBUS
1580 if (signal == SIGBUS) {
1581 Info(slide, 0x421, ((char *)slide, LoadFarString(ZipfileCorrupt),
1582 "bus error"));
1583 DESTROYGLOBALS();
1584 EXIT(PK_BADERR);
1586 #endif /* SIGBUS */
1588 #ifdef SIGSEGV
1589 if (signal == SIGSEGV) {
1590 Info(slide, 0x421, ((char *)slide, LoadFarString(ZipfileCorrupt),
1591 "segmentation violation"));
1592 DESTROYGLOBALS();
1593 EXIT(PK_BADERR);
1595 #endif /* SIGSEGV */
1597 /* probably ctrl-C */
1598 DESTROYGLOBALS();
1599 #if defined(AMIGA) && defined(__SASC)
1600 _abort();
1601 #endif
1602 EXIT(IZ_CTRLC); /* was EXIT(0), then EXIT(PK_ERR) */
1605 #endif /* !WINDLL */
1610 #if (!defined(VMS) && !defined(CMS_MVS))
1611 #if (!defined(OS2) || defined(TIMESTAMP))
1613 #if (!defined(HAVE_MKTIME) || defined(WIN32))
1614 /* also used in amiga/filedate.c and win32/win32.c */
1615 ZCONST ush ydays[] =
1616 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
1617 #endif
1619 /*******************************/
1620 /* Function dos_to_unix_time() */ /* used for freshening/updating/timestamps */
1621 /*******************************/
1623 time_t dos_to_unix_time(dosdatetime)
1624 ulg dosdatetime;
1626 time_t m_time;
1628 #ifdef HAVE_MKTIME
1630 ZCONST time_t now = time(NULL);
1631 struct tm *tm;
1632 # define YRBASE 1900
1634 tm = localtime(&now);
1635 tm->tm_isdst = -1; /* let mktime determine if DST is in effect */
1637 /* dissect date */
1638 tm->tm_year = ((int)(dosdatetime >> 25) & 0x7f) + (1980 - YRBASE);
1639 tm->tm_mon = ((int)(dosdatetime >> 21) & 0x0f) - 1;
1640 tm->tm_mday = ((int)(dosdatetime >> 16) & 0x1f);
1642 /* dissect time */
1643 tm->tm_hour = (int)((unsigned)dosdatetime >> 11) & 0x1f;
1644 tm->tm_min = (int)((unsigned)dosdatetime >> 5) & 0x3f;
1645 tm->tm_sec = (int)((unsigned)dosdatetime << 1) & 0x3e;
1647 m_time = mktime(tm);
1648 NATIVE_TO_TIMET(m_time) /* NOP unless MSC 7.0 or Macintosh */
1649 TTrace((stderr, " final m_time = %lu\n", (ulg)m_time));
1651 #else /* !HAVE_MKTIME */
1653 int yr, mo, dy, hh, mm, ss;
1654 #ifdef TOPS20
1655 # define YRBASE 1900
1656 struct tmx *tmx;
1657 char temp[20];
1658 #else /* !TOPS20 */
1659 # define YRBASE 1970
1660 int leap;
1661 unsigned days;
1662 struct tm *tm;
1663 #if (!defined(MACOS) && !defined(RISCOS) && !defined(QDOS) && !defined(TANDEM))
1664 #ifdef WIN32
1665 TIME_ZONE_INFORMATION tzinfo;
1666 DWORD res;
1667 #else /* ! WIN32 */
1668 #ifndef BSD4_4 /* GRR: change to !defined(MODERN) ? */
1669 #if (defined(BSD) || defined(MTS) || defined(__GO32__))
1670 struct timeb tbp;
1671 #else /* !(BSD || MTS || __GO32__) */
1672 #ifdef DECLARE_TIMEZONE
1673 extern time_t timezone;
1674 #endif
1675 #endif /* ?(BSD || MTS || __GO32__) */
1676 #endif /* !BSD4_4 */
1677 #endif /* ?WIN32 */
1678 #endif /* !MACOS && !RISCOS && !QDOS && !TANDEM */
1679 #endif /* ?TOPS20 */
1682 /* dissect date */
1683 yr = ((int)(dosdatetime >> 25) & 0x7f) + (1980 - YRBASE);
1684 mo = ((int)(dosdatetime >> 21) & 0x0f) - 1;
1685 dy = ((int)(dosdatetime >> 16) & 0x1f) - 1;
1687 /* dissect time */
1688 hh = (int)((unsigned)dosdatetime >> 11) & 0x1f;
1689 mm = (int)((unsigned)dosdatetime >> 5) & 0x3f;
1690 ss = (int)((unsigned)dosdatetime & 0x1f) * 2;
1692 #ifdef TOPS20
1693 tmx = (struct tmx *)malloc(sizeof(struct tmx));
1694 sprintf (temp, "%02d/%02d/%02d %02d:%02d:%02d", mo+1, dy+1, yr, hh, mm, ss);
1695 time_parse(temp, tmx, (char *)0);
1696 m_time = time_make(tmx);
1697 free(tmx);
1699 #else /* !TOPS20 */
1701 /*---------------------------------------------------------------------------
1702 Calculate the number of seconds since the epoch, usually 1 January 1970.
1703 ---------------------------------------------------------------------------*/
1705 /* leap = # of leap yrs from YRBASE up to but not including current year */
1706 leap = ((yr + YRBASE - 1) / 4); /* leap year base factor */
1708 /* calculate days from BASE to this year and add expired days this year */
1709 days = (yr * 365) + (leap - 492) + ydays[mo];
1711 /* if year is a leap year and month is after February, add another day */
1712 if ((mo > 1) && ((yr+YRBASE)%4 == 0) && ((yr+YRBASE) != 2100))
1713 ++days; /* OK through 2199 */
1715 /* convert date & time to seconds relative to 00:00:00, 01/01/YRBASE */
1716 m_time = (time_t)((unsigned long)(days + dy) * 86400L +
1717 (unsigned long)hh * 3600L +
1718 (unsigned long)(mm * 60 + ss));
1719 /* - 1; MS-DOS times always rounded up to nearest even second */
1720 TTrace((stderr, "dos_to_unix_time:\n"));
1721 TTrace((stderr, " m_time before timezone = %lu\n", (ulg)m_time));
1723 /*---------------------------------------------------------------------------
1724 Adjust for local standard timezone offset.
1725 ---------------------------------------------------------------------------*/
1727 #if (!defined(MACOS) && !defined(RISCOS) && !defined(QDOS) && !defined(TANDEM))
1728 #ifdef WIN32
1729 /* account for timezone differences */
1730 res = GetTimeZoneInformation(&tzinfo);
1731 if (res != TIME_ZONE_ID_INVALID)
1733 m_time += 60*(tzinfo.Bias);
1734 #else /* !WIN32 */
1735 #if (defined(BSD) || defined(MTS) || defined(__GO32__))
1736 #ifdef BSD4_4
1737 if ( (dosdatetime >= DOSTIME_2038_01_18) &&
1738 (m_time < (time_t)0x70000000L) )
1739 m_time = U_TIME_T_MAX; /* saturate in case of (unsigned) overflow */
1740 if (m_time < (time_t)0L) /* a converted DOS time cannot be negative */
1741 m_time = S_TIME_T_MAX; /* -> saturate at max signed time_t value */
1742 if ((tm = localtime(&m_time)) != (struct tm *)NULL)
1743 m_time -= tm->tm_gmtoff; /* sec. EAST of GMT: subtr. */
1744 #else /* !(BSD4_4 */
1745 ftime(&tbp); /* get `timezone' */
1746 m_time += tbp.timezone * 60L; /* seconds WEST of GMT: add */
1747 #endif /* ?(BSD4_4 || __EMX__) */
1748 #else /* !(BSD || MTS || __GO32__) */
1749 /* tzset was already called at start of process_zipfiles() */
1750 /* tzset(); */ /* set `timezone' variable */
1751 #if (!defined(__BEOS__) && !defined(__HAIKU__)) /* BeOS DR8 has no timezones... */
1752 m_time += timezone; /* seconds WEST of GMT: add */
1753 #endif
1754 #endif /* ?(BSD || MTS || __GO32__) */
1755 #endif /* ?WIN32 */
1756 TTrace((stderr, " m_time after timezone = %lu\n", (ulg)m_time));
1758 /*---------------------------------------------------------------------------
1759 Adjust for local daylight savings (summer) time.
1760 ---------------------------------------------------------------------------*/
1762 #ifndef BSD4_4 /* (DST already added to tm_gmtoff, so skip tm_isdst) */
1763 if ( (dosdatetime >= DOSTIME_2038_01_18) &&
1764 (m_time < (time_t)0x70000000L) )
1765 m_time = U_TIME_T_MAX; /* saturate in case of (unsigned) overflow */
1766 if (m_time < (time_t)0L) /* a converted DOS time cannot be negative */
1767 m_time = S_TIME_T_MAX; /* -> saturate at max signed time_t value */
1768 TIMET_TO_NATIVE(m_time) /* NOP unless MSC 7.0 or Macintosh */
1769 if (((tm = localtime((time_t *)&m_time)) != NULL) && tm->tm_isdst)
1770 #ifdef WIN32
1771 m_time += 60L * tzinfo.DaylightBias; /* adjust with DST bias */
1772 else
1773 m_time += 60L * tzinfo.StandardBias; /* add StdBias (normally 0) */
1774 #else
1775 m_time -= 60L * 60L; /* adjust for daylight savings time */
1776 #endif
1777 NATIVE_TO_TIMET(m_time) /* NOP unless MSC 7.0 or Macintosh */
1778 TTrace((stderr, " m_time after DST = %lu\n", (ulg)m_time));
1779 #endif /* !BSD4_4 */
1780 #ifdef WIN32
1782 #endif
1783 #endif /* !MACOS && !RISCOS && !QDOS && !TANDEM */
1784 #endif /* ?TOPS20 */
1786 #endif /* ?HAVE_MKTIME */
1788 if ( (dosdatetime >= DOSTIME_2038_01_18) &&
1789 (m_time < (time_t)0x70000000L) )
1790 m_time = U_TIME_T_MAX; /* saturate in case of (unsigned) overflow */
1791 if (m_time < (time_t)0L) /* a converted DOS time cannot be negative */
1792 m_time = S_TIME_T_MAX; /* -> saturate at max signed time_t value */
1794 return m_time;
1796 } /* end function dos_to_unix_time() */
1798 #endif /* !OS2 || TIMESTAMP */
1799 #endif /* !VMS && !CMS_MVS */
1803 #if (!defined(VMS) && !defined(OS2) && !defined(CMS_MVS))
1805 /******************************/
1806 /* Function check_for_newer() */ /* used for overwriting/freshening/updating */
1807 /******************************/
1809 int check_for_newer(__G__ filename) /* return 1 if existing file is newer */
1810 __GDEF /* or equal; 0 if older; -1 if doesn't */
1811 char *filename; /* exist yet */
1813 time_t existing, archive;
1814 #ifdef USE_EF_UT_TIME
1815 iztimes z_utime;
1816 #endif
1817 #ifdef AOS_VS
1818 long dyy, dmm, ddd, dhh, dmin, dss;
1821 dyy = (lrec.last_mod_dos_datetime >> 25) + 1980;
1822 dmm = (lrec.last_mod_dos_datetime >> 21) & 0x0f;
1823 ddd = (lrec.last_mod_dos_datetime >> 16) & 0x1f;
1824 dhh = (lrec.last_mod_dos_datetime >> 11) & 0x1f;
1825 dmin = (lrec.last_mod_dos_datetime >> 5) & 0x3f;
1826 dss = (lrec.last_mod_dos_datetime & 0x1f) * 2;
1828 /* under AOS/VS, file times can only be set at creation time,
1829 * with the info in a special DG format. Make sure we can create
1830 * it here - we delete it later & re-create it, whether or not
1831 * it exists now.
1833 if (!zvs_create(filename, (((ulg)dgdate(dmm, ddd, dyy)) << 16) |
1834 (dhh*1800L + dmin*30L + dss/2L), -1L, -1L, (char *) -1, -1, -1, -1))
1835 return DOES_NOT_EXIST;
1836 #endif /* AOS_VS */
1838 Trace((stderr, "check_for_newer: doing stat(%s)\n", FnFilter1(filename)));
1839 if (SSTAT(filename, &G.statbuf)) {
1840 Trace((stderr,
1841 "check_for_newer: stat(%s) returns %d: file does not exist\n",
1842 FnFilter1(filename), SSTAT(filename, &G.statbuf)));
1843 #ifdef SYMLINKS
1844 Trace((stderr, "check_for_newer: doing lstat(%s)\n",
1845 FnFilter1(filename)));
1846 /* GRR OPTION: could instead do this test ONLY if G.symlnk is true */
1847 if (lstat(filename, &G.statbuf) == 0) {
1848 Trace((stderr,
1849 "check_for_newer: lstat(%s) returns 0: symlink does exist\n",
1850 FnFilter1(filename)));
1851 if (QCOND2 && !IS_OVERWRT_ALL)
1852 Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink),
1853 FnFilter1(filename), " with no real file"));
1854 return EXISTS_AND_OLDER; /* symlink dates are meaningless */
1856 #endif /* SYMLINKS */
1857 return DOES_NOT_EXIST;
1859 Trace((stderr, "check_for_newer: stat(%s) returns 0: file exists\n",
1860 FnFilter1(filename)));
1862 #ifdef SYMLINKS
1863 /* GRR OPTION: could instead do this test ONLY if G.symlnk is true */
1864 if (lstat(filename, &G.statbuf) == 0 && S_ISLNK(G.statbuf.st_mode)) {
1865 Trace((stderr, "check_for_newer: %s is a symbolic link\n",
1866 FnFilter1(filename)));
1867 if (QCOND2 && !IS_OVERWRT_ALL)
1868 Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink),
1869 FnFilter1(filename), ""));
1870 return EXISTS_AND_OLDER; /* symlink dates are meaningless */
1872 #endif /* SYMLINKS */
1874 NATIVE_TO_TIMET(G.statbuf.st_mtime) /* NOP unless MSC 7.0 or Macintosh */
1876 #ifdef USE_EF_UT_TIME
1877 /* The `Unix extra field mtime' should be used for comparison with the
1878 * time stamp of the existing file >>>ONLY<<< when the EF info is also
1879 * used to set the modification time of the extracted file.
1881 if (G.extra_field &&
1882 #ifdef IZ_CHECK_TZ
1883 G.tz_is_valid &&
1884 #endif
1885 (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
1886 G.lrec.last_mod_dos_datetime, &z_utime, NULL)
1887 & EB_UT_FL_MTIME))
1889 TTrace((stderr, "check_for_newer: using Unix extra field mtime\n"));
1890 existing = G.statbuf.st_mtime;
1891 archive = z_utime.mtime;
1892 } else {
1893 /* round up existing filetime to nearest 2 seconds for comparison,
1894 * but saturate in case of arithmetic overflow
1896 existing = ((G.statbuf.st_mtime & 1) &&
1897 (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ?
1898 G.statbuf.st_mtime + 1 : G.statbuf.st_mtime;
1899 archive = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
1901 #else /* !USE_EF_UT_TIME */
1902 /* round up existing filetime to nearest 2 seconds for comparison,
1903 * but saturate in case of arithmetic overflow
1905 existing = ((G.statbuf.st_mtime & 1) &&
1906 (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ?
1907 G.statbuf.st_mtime + 1 : G.statbuf.st_mtime;
1908 archive = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
1909 #endif /* ?USE_EF_UT_TIME */
1911 TTrace((stderr, "check_for_newer: existing %lu, archive %lu, e-a %ld\n",
1912 (ulg)existing, (ulg)archive, (long)(existing-archive)));
1914 return (existing >= archive);
1916 } /* end function check_for_newer() */
1918 #endif /* !VMS && !OS2 && !CMS_MVS */
1924 /************************/
1925 /* Function do_string() */
1926 /************************/
1928 int do_string(__G__ length, option) /* return PK-type error code */
1929 __GDEF
1930 unsigned int length; /* without prototype, ush converted to this */
1931 int option;
1933 unsigned comment_bytes_left;
1934 unsigned int block_len;
1935 int error=PK_OK;
1936 #ifdef AMIGA
1937 char tmp_fnote[2 * AMIGA_FILENOTELEN]; /* extra room for squozen chars */
1938 #endif
1941 /*---------------------------------------------------------------------------
1942 This function processes arbitrary-length (well, usually) strings. Four
1943 major options are allowed: SKIP, wherein the string is skipped (pretty
1944 logical, eh?); DISPLAY, wherein the string is printed to standard output
1945 after undergoing any necessary or unnecessary character conversions;
1946 DS_FN, wherein the string is put into the filename[] array after under-
1947 going appropriate conversions (including case-conversion, if that is
1948 indicated: see the global variable pInfo->lcflag); and EXTRA_FIELD,
1949 wherein the `string' is assumed to be an extra field and is copied to
1950 the (freshly malloced) buffer G.extra_field. The third option should
1951 be OK since filename is dimensioned at 1025, but we check anyway.
1953 The string, by the way, is assumed to start at the current file-pointer
1954 position; its length is given by 'length'. So start off by checking the
1955 length of the string: if zero, we're already done.
1956 ---------------------------------------------------------------------------*/
1958 if (!length)
1959 return PK_COOL;
1961 switch (option) {
1963 #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN))
1965 * Special case: See if the comment begins with an autorun command line.
1966 * Save that and display (or skip) the remainder.
1969 case CHECK_AUTORUN:
1970 case CHECK_AUTORUN_Q:
1971 comment_bytes_left = length;
1972 if (length >= 10)
1974 block_len = readbuf(__G__ (char *)G.outbuf, 10);
1975 if (block_len == 0)
1976 return PK_EOF;
1977 comment_bytes_left -= block_len;
1978 G.outbuf[block_len] = '\0';
1979 if (!strcmp((char *)G.outbuf, "$AUTORUN$>")) {
1980 char *eol;
1981 length -= 10;
1982 block_len = readbuf(__G__ G.autorun_command,
1983 MIN(length, sizeof(G.autorun_command)-1));
1984 if (block_len == 0)
1985 return PK_EOF;
1986 comment_bytes_left -= block_len;
1987 G.autorun_command[block_len] = '\0';
1988 A_TO_N(G.autorun_command);
1989 eol = strchr(G.autorun_command, '\n');
1990 if (!eol)
1991 eol = G.autorun_command + strlen(G.autorun_command) - 1;
1992 length -= eol + 1 - G.autorun_command;
1993 while (eol >= G.autorun_command && isspace(*eol))
1994 *eol-- = '\0';
1995 #ifdef WIN32
1996 /* Win9x console always uses OEM character coding, and
1997 WinNT console is set to OEM charset by default, too */
1998 INTERN_TO_OEM(G.autorun_command, G.autorun_command);
1999 #endif /* WIN32 */
2002 if (option == CHECK_AUTORUN_Q) /* don't display the remainder */
2003 length = 0;
2004 /* seek to beginning of remaining part of comment -- rewind if */
2005 /* displaying entire comment, or skip to end if discarding it */
2006 seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes +
2007 (G.inptr - G.inbuf) + comment_bytes_left - length);
2008 if (!length)
2009 break;
2010 /* FALL THROUGH... */
2011 #endif /* SFX && CHEAP_SFX_AUTORUN */
2014 * First normal case: print string on standard output. First set loop
2015 * variables, then loop through the comment in chunks of OUTBUFSIZ bytes,
2016 * converting formats and printing as we go. The second half of the
2017 * loop conditional was added because the file might be truncated, in
2018 * which case comment_bytes_left will remain at some non-zero value for
2019 * all time. outbuf and slide are used as scratch buffers because they
2020 * are available (we should be either before or in between any file pro-
2021 * cessing).
2024 case DISPLAY:
2025 case DISPL_8:
2026 comment_bytes_left = length;
2027 block_len = OUTBUFSIZ; /* for the while statement, first time */
2028 while (comment_bytes_left > 0 && block_len > 0) {
2029 register uch *p = G.outbuf;
2030 register uch *q = G.outbuf;
2032 if ((block_len = readbuf(__G__ (char *)G.outbuf,
2033 MIN((unsigned)OUTBUFSIZ, comment_bytes_left))) == 0)
2034 return PK_EOF;
2035 comment_bytes_left -= block_len;
2037 /* this is why we allocated an extra byte for outbuf: terminate
2038 * with zero (ASCIIZ) */
2039 G.outbuf[block_len] = '\0';
2041 /* remove all ASCII carriage returns from comment before printing
2042 * (since used before A_TO_N(), check for CR instead of '\r')
2044 while (*p) {
2045 while (*p == CR)
2046 ++p;
2047 *q++ = *p++;
2049 /* could check whether (p - outbuf) == block_len here */
2050 *q = '\0';
2052 if (option == DISPL_8) {
2053 /* translate the text coded in the entry's host-dependent
2054 "extended ASCII" charset into the compiler's (system's)
2055 internal text code page */
2056 Ext_ASCII_TO_Native((char *)G.outbuf, G.pInfo->hostnum,
2057 G.pInfo->hostver, G.pInfo->HasUxAtt,
2058 FALSE);
2059 #ifdef WINDLL
2060 /* translate to ANSI (RTL internal codepage may be OEM) */
2061 INTERN_TO_ISO((char *)G.outbuf, (char *)G.outbuf);
2062 #else /* !WINDLL */
2063 #ifdef WIN32
2064 /* Win9x console always uses OEM character coding, and
2065 WinNT console is set to OEM charset by default, too */
2066 INTERN_TO_OEM((char *)G.outbuf, (char *)G.outbuf);
2067 #endif /* WIN32 */
2068 #endif /* ?WINDLL */
2069 } else {
2070 A_TO_N(G.outbuf); /* translate string to native */
2073 #ifdef WINDLL
2074 /* ran out of local mem -- had to cheat */
2075 win_fprintf((zvoid *)&G, stdout, length, (char *)G.outbuf);
2076 win_fprintf((zvoid *)&G, stdout, 2, (char *)"\n\n");
2077 #else /* !WINDLL */
2078 #ifdef NOANSIFILT /* GRR: can ANSI be used with EBCDIC? */
2079 (*G.message)((zvoid *)&G, G.outbuf, (ulg)(q-G.outbuf), 0);
2080 #else /* ASCII, filter out ANSI escape sequences and handle ^S (pause) */
2081 p = G.outbuf - 1;
2082 q = slide;
2083 while (*++p) {
2084 int pause = FALSE;
2086 if (*p == 0x1B) { /* ASCII escape char */
2087 *q++ = '^';
2088 *q++ = '[';
2089 } else if (*p == 0x13) { /* ASCII ^S (pause) */
2090 pause = TRUE;
2091 if (p[1] == LF) /* ASCII LF */
2092 *q++ = *++p;
2093 else if (p[1] == CR && p[2] == LF) { /* ASCII CR LF */
2094 *q++ = *++p;
2095 *q++ = *++p;
2097 } else
2098 *q++ = *p;
2099 if ((unsigned)(q-slide) > WSIZE-3 || pause) { /* flush */
2100 (*G.message)((zvoid *)&G, slide, (ulg)(q-slide), 0);
2101 q = slide;
2102 if (pause && G.extract_flag) /* don't pause for list/test */
2103 (*G.mpause)((zvoid *)&G, LoadFarString(QuitPrompt), 0);
2106 (*G.message)((zvoid *)&G, slide, (ulg)(q-slide), 0);
2107 #endif /* ?NOANSIFILT */
2108 #endif /* ?WINDLL */
2110 /* add '\n' if not at start of line */
2111 (*G.message)((zvoid *)&G, slide, 0L, 0x40);
2112 break;
2115 * Second case: read string into filename[] array. The filename should
2116 * never ever be longer than FILNAMSIZ-1 (1024), but for now we'll check,
2117 * just to be sure.
2120 case DS_FN:
2121 case DS_FN_L:
2122 if (length >= FILNAMSIZ) {
2123 Info(slide, 0x401, ((char *)slide,
2124 LoadFarString(FilenameTooLongTrunc)));
2125 error = PK_WARN;
2126 /* remember excess length in block_len */
2127 block_len = length - (FILNAMSIZ - 1);
2128 length = FILNAMSIZ - 1;
2129 } else
2130 /* no excess size */
2131 block_len = 0;
2132 if (readbuf(__G__ G.filename, length) == 0)
2133 return PK_EOF;
2134 G.filename[length] = '\0'; /* terminate w/zero: ASCIIZ */
2136 /* translate the Zip entry filename coded in host-dependent "extended
2137 ASCII" into the compiler's (system's) internal text code page */
2138 Ext_ASCII_TO_Native(G.filename, G.pInfo->hostnum, G.pInfo->hostver,
2139 G.pInfo->HasUxAtt, (option == DS_FN_L));
2141 if (G.pInfo->lcflag) /* replace with lowercase filename */
2142 STRLOWER(G.filename, G.filename);
2144 if (G.pInfo->vollabel && length > 8 && G.filename[8] == '.') {
2145 char *p = G.filename+8;
2146 while (*p++)
2147 p[-1] = *p; /* disk label, and 8th char is dot: remove dot */
2150 if (!block_len) /* no overflow, we're done here */
2151 break;
2154 * We truncated the filename, so print what's left and then fall
2155 * through to the SKIP routine.
2157 Info(slide, 0x401, ((char *)slide, "[ %s ]\n", FnFilter1(G.filename)));
2158 length = block_len; /* SKIP the excess bytes... */
2159 /* FALL THROUGH... */
2162 * Third case: skip string, adjusting readbuf's internal variables
2163 * as necessary (and possibly skipping to and reading a new block of
2164 * data).
2167 case SKIP:
2168 /* cur_zipfile_bufstart already takes account of extra_bytes, so don't
2169 * correct for it twice: */
2170 seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes +
2171 (G.inptr-G.inbuf) + length);
2172 break;
2175 * Fourth case: assume we're at the start of an "extra field"; malloc
2176 * storage for it and read data into the allocated space.
2179 case EXTRA_FIELD:
2180 if (G.extra_field != (uch *)NULL)
2181 free(G.extra_field);
2182 if ((G.extra_field = (uch *)malloc(length)) == (uch *)NULL) {
2183 Info(slide, 0x401, ((char *)slide, LoadFarString(ExtraFieldTooLong),
2184 length));
2185 /* cur_zipfile_bufstart already takes account of extra_bytes,
2186 * so don't correct for it twice: */
2187 seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes +
2188 (G.inptr-G.inbuf) + length);
2189 } else
2190 if (readbuf(__G__ (char *)G.extra_field, length) == 0)
2191 return PK_EOF;
2192 break;
2194 #ifdef AMIGA
2196 * Fifth case, for the Amiga only: take the comment that would ordinarily
2197 * be skipped over, and turn it into a 79 character string that will be
2198 * attached to the file as a "filenote" after it is extracted.
2201 case FILENOTE:
2202 if ((block_len = readbuf(__G__ tmp_fnote, (unsigned)
2203 MIN(length, 2 * AMIGA_FILENOTELEN - 1))) == 0)
2204 return PK_EOF;
2205 if ((length -= block_len) > 0) /* treat remainder as in case SKIP: */
2206 seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes
2207 + (G.inptr - G.inbuf) + length);
2208 /* convert multi-line text into single line with no ctl-chars: */
2209 tmp_fnote[block_len] = '\0';
2210 while ((short int) --block_len >= 0)
2211 if ((unsigned) tmp_fnote[block_len] < ' ')
2212 if (tmp_fnote[block_len+1] == ' ') /* no excess */
2213 strcpy(tmp_fnote+block_len, tmp_fnote+block_len+1);
2214 else
2215 tmp_fnote[block_len] = ' ';
2216 tmp_fnote[AMIGA_FILENOTELEN - 1] = '\0';
2217 if (G.filenotes[G.filenote_slot])
2218 free(G.filenotes[G.filenote_slot]); /* should not happen */
2219 G.filenotes[G.filenote_slot] = NULL;
2220 if (tmp_fnote[0]) {
2221 if (!(G.filenotes[G.filenote_slot] = malloc(strlen(tmp_fnote)+1)))
2222 return PK_MEM;
2223 strcpy(G.filenotes[G.filenote_slot], tmp_fnote);
2225 break;
2226 #endif /* AMIGA */
2228 } /* end switch (option) */
2230 return error;
2232 } /* end function do_string() */
2238 /***********************/
2239 /* Function makeword() */
2240 /***********************/
2242 ush makeword(b)
2243 ZCONST uch *b;
2246 * Convert Intel style 'short' integer to non-Intel non-16-bit
2247 * host format. This routine also takes care of byte-ordering.
2249 return (ush)((b[1] << 8) | b[0]);
2256 /***********************/
2257 /* Function makelong() */
2258 /***********************/
2260 ulg makelong(sig)
2261 ZCONST uch *sig;
2264 * Convert intel style 'long' variable to non-Intel non-16-bit
2265 * host format. This routine also takes care of byte-ordering.
2267 return (((ulg)sig[3]) << 24)
2268 + (((ulg)sig[2]) << 16)
2269 + (((ulg)sig[1]) << 8)
2270 + ((ulg)sig[0]);
2275 #if CRYPT
2277 #ifdef NEED_STR2ISO
2278 /**********************/
2279 /* Function str2iso() */
2280 /**********************/
2282 char *str2iso(dst, src)
2283 char *dst; /* destination buffer */
2284 register ZCONST char *src; /* source string */
2286 #ifdef INTERN_TO_ISO
2287 INTERN_TO_ISO(src, dst);
2288 #else
2289 register uch c;
2290 register char *dstp = dst;
2292 do {
2293 c = (uch)foreign(*src++);
2294 *dstp++ = (char)ASCII2ISO(c);
2295 } while (c != '\0');
2296 #endif
2298 return dst;
2300 #endif /* NEED_STR2ISO */
2303 #ifdef NEED_STR2OEM
2304 /**********************/
2305 /* Function str2oem() */
2306 /**********************/
2308 char *str2oem(dst, src)
2309 char *dst; /* destination buffer */
2310 register ZCONST char *src; /* source string */
2312 #ifdef INTERN_TO_OEM
2313 INTERN_TO_OEM(src, dst);
2314 #else
2315 register uch c;
2316 register char *dstp = dst;
2318 do {
2319 c = (uch)foreign(*src++);
2320 *dstp++ = (char)ASCII2OEM(c);
2321 } while (c != '\0');
2322 #endif
2324 return dst;
2326 #endif /* NEED_STR2OEM */
2328 #endif /* CRYPT */
2331 #ifdef ZMEM /* memset/memcmp/memcpy for systems without either them or */
2332 /* bzero/bcmp/bcopy */
2333 /* (no known systems as of 960211) */
2335 /*********************/
2336 /* Function memset() */
2337 /*********************/
2339 zvoid *memset(buf, init, len)
2340 register zvoid *buf; /* buffer location */
2341 register int init; /* initializer character */
2342 register unsigned int len; /* length of the buffer */
2344 zvoid *start;
2346 start = buf;
2347 while (len--)
2348 *((char *)buf++) = (char)init;
2349 return start;
2354 /*********************/
2355 /* Function memcmp() */
2356 /*********************/
2358 int memcmp(b1, b2, len)
2359 register ZCONST zvoid *b1;
2360 register ZCONST zvoid *b2;
2361 register unsigned int len;
2363 register int c;
2365 if (len > 0) do {
2366 if ((c = (int)(*((ZCONST unsigned char *)b1)++) -
2367 (int)(*((ZCONST unsigned char *)b2)++)) != 0)
2368 return c;
2369 } while (--len > 0)
2370 return 0;
2375 /*********************/
2376 /* Function memcpy() */
2377 /*********************/
2379 zvoid *memcpy(dst, src, len)
2380 register zvoid *dst;
2381 register ZCONST zvoid *src;
2382 register unsigned int len;
2384 zvoid *start;
2386 start = dst;
2387 while (len-- > 0)
2388 *((char *)dst)++ = *((ZCONST char *)src)++;
2389 return start;
2392 #endif /* ZMEM */
2397 #ifdef NO_STRNICMP
2399 /************************/
2400 /* Function zstrnicmp() */
2401 /************************/
2403 int zstrnicmp(s1, s2, n)
2404 register ZCONST char *s1, *s2;
2405 register unsigned n;
2407 for (; n > 0; --n, ++s1, ++s2) {
2409 if (ToLower(*s1) != ToLower(*s2))
2410 /* test includes early termination of one string */
2411 return (ToLower(*s1) < ToLower(*s2))? -1 : 1;
2413 if (*s1 == '\0') /* both strings terminate early */
2414 return 0;
2416 return 0;
2419 #endif /* NO_STRNICMP */
2424 #ifdef REGULUS /* returns the inode number on success(!)...argh argh argh */
2425 # undef stat
2427 /********************/
2428 /* Function zstat() */
2429 /********************/
2431 int zstat(p, s)
2432 ZCONST char *p;
2433 struct stat *s;
2435 return (stat((char *)p,s) >= 0? 0 : (-1));
2438 #endif /* REGULUS */
2443 #ifdef _MBCS
2445 /* DBCS support for Info-ZIP's zip (mainly for japanese (-: )
2446 * by Yoshioka Tsuneo (QWF00133@nifty.ne.jp,tsuneo-y@is.aist-nara.ac.jp)
2447 * This code is public domain! Date: 1998/12/20
2450 /************************/
2451 /* Function plastchar() */
2452 /************************/
2454 char *plastchar(ptr, len)
2455 ZCONST char *ptr;
2456 extent len;
2458 unsigned clen;
2459 ZCONST char *oldptr = ptr;
2460 while(*ptr != '\0' && len > 0){
2461 oldptr = ptr;
2462 clen = CLEN(ptr);
2463 ptr += clen;
2464 len -= clen;
2466 return (char *)oldptr;
2470 #ifdef NEED_UZMBSCHR
2471 /***********************/
2472 /* Function uzmbschr() */
2473 /***********************/
2475 unsigned char *uzmbschr(str, c)
2476 ZCONST unsigned char *str;
2477 unsigned int c;
2479 while(*str != '\0'){
2480 if (*str == c) {return (unsigned char *)str;}
2481 INCSTR(str);
2483 return NULL;
2485 #endif /* NEED_UZMBSCHR */
2488 #ifdef NEED_UZMBSRCHR
2489 /************************/
2490 /* Function uzmbsrchr() */
2491 /************************/
2493 unsigned char *uzmbsrchr(str, c)
2494 ZCONST unsigned char *str;
2495 unsigned int c;
2497 unsigned char *match = NULL;
2498 while(*str != '\0'){
2499 if (*str == c) {match = (unsigned char *)str;}
2500 INCSTR(str);
2502 return match;
2504 #endif /* NEED_UZMBSRCHR */
2505 #endif /* _MBCS */
2511 #ifdef SMALL_MEM
2513 /*******************************/
2514 /* Function fLoadFarString() */ /* (and friends...) */
2515 /*******************************/
2517 char *fLoadFarString(__GPRO__ const char Far *sz)
2519 (void)zfstrcpy(G.rgchBigBuffer, sz);
2520 return G.rgchBigBuffer;
2523 char *fLoadFarStringSmall(__GPRO__ const char Far *sz)
2525 (void)zfstrcpy(G.rgchSmallBuffer, sz);
2526 return G.rgchSmallBuffer;
2529 char *fLoadFarStringSmall2(__GPRO__ const char Far *sz)
2531 (void)zfstrcpy(G.rgchSmallBuffer2, sz);
2532 return G.rgchSmallBuffer2;
2538 #if (!defined(_MSC_VER) || (_MSC_VER < 600))
2539 /*************************/
2540 /* Function zfstrcpy() */ /* portable clone of _fstrcpy() */
2541 /*************************/
2543 char Far * Far zfstrcpy(char Far *s1, const char Far *s2)
2545 char Far *p = s1;
2547 while ((*s1++ = *s2++) != '\0');
2548 return p;
2550 #endif /* !_MSC_VER || (_MSC_VER < 600) */
2552 #endif /* SMALL_MEM */