Update install docs
[carla.git] / data / windows / unzipfx-carla-control / process.c
blobc62c5f04a1bf9c8f43fb24fb95e5fe330eafec83
1 /*
2 Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
4 See the accompanying file LICENSE, version 2009-Jan-02 or later
5 (the contents of which are also included in unzip.h) for terms of use.
6 If, for some reason, all these files are missing, the Info-ZIP license
7 also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
8 */
9 /*---------------------------------------------------------------------------
11 process.c
13 This file contains the top-level routines for processing multiple zipfiles.
15 Contains: process_zipfiles()
16 free_G_buffers()
17 do_seekable()
18 file_size()
19 rec_find()
20 find_ecrec64()
21 find_ecrec()
22 process_zip_cmmnt()
23 process_cdir_file_hdr()
24 get_cdir_ent()
25 process_local_file_hdr()
26 getZip64Data()
27 ef_scan_for_izux()
28 getRISCOSexfield()
30 ---------------------------------------------------------------------------*/
33 #define UNZIP_INTERNAL
34 #include "unzip.h"
35 #ifdef WINDLL
36 # ifdef POCKET_UNZIP
37 # include "wince/intrface.h"
38 # else
39 # include "windll/windll.h"
40 # endif
41 #endif
42 #if defined(DYNALLOC_CRCTAB) || defined(UNICODE_SUPPORT)
43 # include "crc32.h"
44 #endif
46 #include "unzipfx/appDetails.h"
48 static int do_seekable OF((__GPRO__ int lastchance));
49 #ifdef DO_SAFECHECK_2GB
50 # ifdef USE_STRM_INPUT
51 static zoff_t file_size OF((FILE *file));
52 # else
53 static zoff_t file_size OF((int fh));
54 # endif
55 #endif /* DO_SAFECHECK_2GB */
56 static int rec_find OF((__GPRO__ zoff_t, char *, int));
57 static int find_ecrec64 OF((__GPRO__ zoff_t searchlen));
58 static int find_ecrec OF((__GPRO__ zoff_t searchlen));
59 static int process_zip_cmmnt OF((__GPRO));
60 static int get_cdir_ent OF((__GPRO));
61 #ifdef IZ_HAVE_UXUIDGID
62 static int read_ux3_value OF((ZCONST uch *dbuf, unsigned uidgid_sz,
63 ulg *p_uidgid));
64 #endif /* IZ_HAVE_UXUIDGID */
67 static ZCONST char Far CannotAllocateBuffers[] =
68 "error: cannot allocate unzip buffers\n";
70 #ifdef SFX
71 static ZCONST char Far CannotFindMyself[] =
72 "unzipsfx: cannot find myself! [%s]\n";
73 # ifdef CHEAP_SFX_AUTORUN
74 static ZCONST char Far AutorunPrompt[] =
75 "\nAuto-run command: %s\nExecute this command? [y/n] ";
76 static ZCONST char Far NotAutoRunning[] =
77 "Not executing auto-run command.";
78 # endif
80 #else /* !SFX */
81 /* process_zipfiles() strings */
82 # if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
83 static ZCONST char Far WarnInvalidTZ[] =
84 "Warning: TZ environment variable not found, cannot use UTC times!!\n";
85 # endif
86 # if !(defined(UNIX) || defined(AMIGA))
87 static ZCONST char Far CannotFindWildcardMatch[] =
88 "%s: cannot find any matches for wildcard specification \"%s\".\n";
89 # endif /* !(UNIX || AMIGA) */
90 static ZCONST char Far FilesProcessOK[] =
91 "%d archive%s successfully processed.\n";
92 static ZCONST char Far ArchiveWarning[] =
93 "%d archive%s had warnings but no fatal errors.\n";
94 static ZCONST char Far ArchiveFatalError[] =
95 "%d archive%s had fatal errors.\n";
96 static ZCONST char Far FileHadNoZipfileDir[] =
97 "%d file%s had no zipfile directory.\n";
98 static ZCONST char Far ZipfileWasDir[] = "1 \"zipfile\" was a directory.\n";
99 static ZCONST char Far ManyZipfilesWereDir[] =
100 "%d \"zipfiles\" were directories.\n";
101 static ZCONST char Far NoZipfileFound[] = "No zipfiles found.\n";
103 /* do_seekable() strings */
104 # ifdef UNIX
105 static ZCONST char Far CannotFindZipfileDirMsg[] =
106 "%s: cannot find zipfile directory in one of %s or\n\
107 %s%s.zip, and cannot find %s, period.\n";
108 static ZCONST char Far CannotFindEitherZipfile[] =
109 "%s: cannot find or open %s, %s.zip or %s.\n";
110 # else /* !UNIX */
111 static ZCONST char Far CannotFindZipfileDirMsg[] =
112 "%s: cannot find zipfile directory in %s,\n\
113 %sand cannot find %s, period.\n";
114 # ifdef VMS
115 static ZCONST char Far CannotFindEitherZipfile[] =
116 "%s: cannot find %s (%s).\n";
117 # else /* !VMS */
118 static ZCONST char Far CannotFindEitherZipfile[] =
119 "%s: cannot find either %s or %s.\n";
120 # endif /* ?VMS */
121 # endif /* ?UNIX */
122 extern ZCONST char Far Zipnfo[]; /* in unzip.c */
123 #ifndef WINDLL
124 static ZCONST char Far Unzip[] = "unzip";
125 #else
126 static ZCONST char Far Unzip[] = "UnZip DLL";
127 #endif
128 #ifdef DO_SAFECHECK_2GB
129 static ZCONST char Far ZipfileTooBig[] =
130 "Trying to read large file (> 2 GiB) without large file support\n";
131 #endif /* DO_SAFECHECK_2GB */
132 static ZCONST char Far MaybeExe[] =
133 "note: %s may be a plain executable, not an archive\n";
134 static ZCONST char Far CentDirNotInZipMsg[] = "\n\
135 [%s]:\n\
136 Zipfile is disk %lu of a multi-disk archive, and this is not the disk on\n\
137 which the central zipfile directory begins (disk %lu).\n";
138 static ZCONST char Far EndCentDirBogus[] =
139 "\nwarning [%s]: end-of-central-directory record claims this\n\
140 is disk %lu but that the central directory starts on disk %lu; this is a\n\
141 contradiction. Attempting to process anyway.\n";
142 # ifdef NO_MULTIPART
143 static ZCONST char Far NoMultiDiskArcSupport[] =
144 "\nerror [%s]: zipfile is part of multi-disk archive\n\
145 (sorry, not yet supported).\n";
146 static ZCONST char Far MaybePakBug[] = "warning [%s]:\
147 zipfile claims to be 2nd disk of a 2-part archive;\n\
148 attempting to process anyway. If no further errors occur, this archive\n\
149 was probably created by PAK v2.51 or earlier. This bug was reported to\n\
150 NoGate in March 1991 and was supposed to have been fixed by mid-1991; as\n\
151 of mid-1992 it still hadn't been. (If further errors do occur, archive\n\
152 was probably created by PKZIP 2.04c or later; UnZip does not yet support\n\
153 multi-part archives.)\n";
154 # else
155 static ZCONST char Far MaybePakBug[] = "warning [%s]:\
156 zipfile claims to be last disk of a multi-part archive;\n\
157 attempting to process anyway, assuming all parts have been concatenated\n\
158 together in order. Expect \"errors\" and warnings...true multi-part support\
159 \n doesn't exist yet (coming soon).\n";
160 # endif
161 static ZCONST char Far ExtraBytesAtStart[] =
162 "warning [%s]: %s extra byte%s at beginning or within zipfile\n\
163 (attempting to process anyway)\n";
164 #endif /* ?SFX */
166 #if ((!defined(WINDLL) && !defined(SFX)) || !defined(NO_ZIPINFO))
167 static ZCONST char Far LogInitline[] = "Archive: %s\n";
168 #endif
170 static ZCONST char Far MissingBytes[] =
171 "error [%s]: missing %s bytes in zipfile\n\
172 (attempting to process anyway)\n";
173 static ZCONST char Far NullCentDirOffset[] =
174 "error [%s]: NULL central directory offset\n\
175 (attempting to process anyway)\n";
176 static ZCONST char Far ZipfileEmpty[] = "warning [%s]: zipfile is empty\n";
177 static ZCONST char Far CentDirStartNotFound[] =
178 "error [%s]: start of central directory not found;\n\
179 zipfile corrupt.\n%s";
180 static ZCONST char Far Cent64EndSigSearchErr[] =
181 "fatal error: read failure while seeking for End-of-centdir-64 signature.\n\
182 This zipfile is corrupt.\n";
183 static ZCONST char Far Cent64EndSigSearchOff[] =
184 "error: End-of-centdir-64 signature not where expected (prepended bytes?)\n\
185 (attempting to process anyway)\n";
186 #ifndef SFX
187 static ZCONST char Far CentDirTooLong[] =
188 "error [%s]: reported length of central directory is\n\
189 %s bytes too long (Atari STZip zipfile? J.H.Holm ZIPSPLIT 1.1\n\
190 zipfile?). Compensating...\n";
191 static ZCONST char Far CentDirEndSigNotFound[] = "\
192 End-of-central-directory signature not found. Either this file is not\n\
193 a zipfile, or it constitutes one disk of a multi-part archive. In the\n\
194 latter case the central directory and zipfile comment will be found on\n\
195 the last disk(s) of this archive.\n";
196 #else /* SFX */
197 static ZCONST char Far CentDirEndSigNotFound[] =
198 " End-of-central-directory signature not found.\n";
199 #endif /* ?SFX */
200 #ifdef TIMESTAMP
201 static ZCONST char Far ZipTimeStampFailed[] =
202 "warning: cannot set time for %s\n";
203 static ZCONST char Far ZipTimeStampSuccess[] =
204 "Updated time stamp for %s.\n";
205 #endif
206 static ZCONST char Far ZipfileCommTrunc1[] =
207 "\ncaution: zipfile comment truncated\n";
208 #ifndef NO_ZIPINFO
209 static ZCONST char Far NoZipfileComment[] =
210 "There is no zipfile comment.\n";
211 static ZCONST char Far ZipfileCommentDesc[] =
212 "The zipfile comment is %u bytes long and contains the following text:\n";
213 static ZCONST char Far ZipfileCommBegin[] =
214 "======================== zipfile comment begins\
215 ==========================\n";
216 static ZCONST char Far ZipfileCommEnd[] =
217 "========================= zipfile comment ends\
218 ===========================\n";
219 static ZCONST char Far ZipfileCommTrunc2[] =
220 "\n The zipfile comment is truncated.\n";
221 #endif /* !NO_ZIPINFO */
222 #ifdef UNICODE_SUPPORT
223 static ZCONST char Far UnicodeVersionError[] =
224 "\nwarning: Unicode Path version > 1\n";
225 static ZCONST char Far UnicodeMismatchError[] =
226 "\nwarning: Unicode Path checksum invalid\n";
227 #endif
232 /*******************************/
233 /* Function process_zipfiles() */
234 /*******************************/
236 int process_zipfiles(__G) /* return PK-type error code */
237 __GDEF
239 #ifndef SFX
240 char *lastzipfn = (char *)NULL;
241 int NumWinFiles, NumLoseFiles, NumWarnFiles;
242 int NumMissDirs, NumMissFiles;
243 #endif
244 int error=0, error_in_archive=0;
247 /*---------------------------------------------------------------------------
248 Start by allocating buffers and (re)constructing the various PK signature
249 strings.
250 ---------------------------------------------------------------------------*/
252 G.inbuf = (uch *)malloc(INBUFSIZ + 4); /* 4 extra for hold[] (below) */
253 G.outbuf = (uch *)malloc(OUTBUFSIZ + 1); /* 1 extra for string term. */
255 if ((G.inbuf == (uch *)NULL) || (G.outbuf == (uch *)NULL)) {
256 Info(slide, 0x401, ((char *)slide,
257 LoadFarString(CannotAllocateBuffers)));
258 return(PK_MEM);
260 G.hold = G.inbuf + INBUFSIZ; /* to check for boundary-spanning sigs */
261 #ifndef VMS /* VMS uses its own buffer scheme for textmode flush(). */
262 #ifdef SMALL_MEM
263 G.outbuf2 = G.outbuf+RAWBUFSIZ; /* never changes */
264 #endif
265 #endif /* !VMS */
267 #if 0 /* CRC_32_TAB has been NULLified by CONSTRUCTGLOBALS !!!! */
268 /* allocate the CRC table later when we know we can read zipfile data */
269 CRC_32_TAB = NULL;
270 #endif /* 0 */
272 /* finish up initialization of magic signature strings */
273 local_hdr_sig[0] /* = extd_local_sig[0] */ = /* ASCII 'P', */
274 central_hdr_sig[0] = end_central_sig[0] = /* not EBCDIC */
275 end_centloc64_sig[0] = end_central64_sig[0] = 0x50;
277 local_hdr_sig[1] /* = extd_local_sig[1] */ = /* ASCII 'K', */
278 central_hdr_sig[1] = end_central_sig[1] = /* not EBCDIC */
279 end_centloc64_sig[1] = end_central64_sig[1] = 0x4B;
281 /*---------------------------------------------------------------------------
282 Make sure timezone info is set correctly; localtime() returns GMT on some
283 OSes (e.g., Solaris 2.x) if this isn't done first. The ifdefs around
284 tzset() were initially copied from dos_to_unix_time() in fileio.c. They
285 may still be too strict; any listed OS that supplies tzset(), regardless
286 of whether the function does anything, should be removed from the ifdefs.
287 ---------------------------------------------------------------------------*/
289 #if (defined(WIN32) && defined(USE_EF_UT_TIME))
290 /* For the Win32 environment, we may have to "prepare" the environment
291 prior to the tzset() call, to work around tzset() implementation bugs.
293 iz_w32_prepareTZenv();
294 #endif
296 #if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
297 # ifndef VALID_TIMEZONE
298 # define VALID_TIMEZONE(tmp) \
299 (((tmp = getenv("TZ")) != NULL) && (*tmp != '\0'))
300 # endif
302 char *p;
303 G.tz_is_valid = VALID_TIMEZONE(p);
304 # ifndef SFX
305 if (!G.tz_is_valid) {
306 Info(slide, 0x401, ((char *)slide, LoadFarString(WarnInvalidTZ)));
307 error_in_archive = error = PK_WARN;
309 # endif /* !SFX */
311 #endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
313 /* For systems that do not have tzset() but supply this function using another
314 name (_tzset() or something similar), an appropiate "#define tzset ..."
315 should be added to the system specifc configuration section. */
316 #if (!defined(T20_VMS) && !defined(MACOS) && !defined(RISCOS) && !defined(QDOS))
317 #if (!defined(BSD) && !defined(MTS) && !defined(CMS_MVS) && !defined(TANDEM))
318 tzset();
319 #endif
320 #endif
322 /* Initialize UnZip's built-in pseudo hard-coded "ISO <--> OEM" translation,
323 depending on the detected codepage setup. */
324 #ifdef NEED_ISO_OEM_INIT
325 prepare_ISO_OEM_translat(__G);
326 #endif
328 /*---------------------------------------------------------------------------
329 Initialize the internal flag holding the mode of processing "overwrite
330 existing file" cases. We do not use the calling interface flags directly
331 because the overwrite mode may be changed by user interaction while
332 processing archive files. Such a change should not affect the option
333 settings as passed through the DLL calling interface.
334 In case of conflicting options, the 'safer' flag uO.overwrite_none takes
335 precedence.
336 ---------------------------------------------------------------------------*/
337 G.overwrite_mode = (uO.overwrite_none ? OVERWRT_NEVER :
338 (uO.overwrite_all ? OVERWRT_ALWAYS : OVERWRT_QUERY));
340 /*---------------------------------------------------------------------------
341 Match (possible) wildcard zipfile specification with existing files and
342 attempt to process each. If no hits, try again after appending ".zip"
343 suffix. If still no luck, give up.
344 ---------------------------------------------------------------------------*/
346 #ifdef SFX
347 if ((error = do_seekable(__G__ 0)) == PK_NOZIP) {
348 #ifdef EXE_EXTENSION
349 int len=strlen(G.argv0);
351 /* append .exe if appropriate; also .sfx? */
352 if ( (G.zipfn = (char *)malloc(len+sizeof(EXE_EXTENSION))) !=
353 (char *)NULL ) {
354 strcpy(G.zipfn, G.argv0);
355 strcpy(G.zipfn+len, EXE_EXTENSION);
356 error = do_seekable(__G__ 0);
357 free(G.zipfn);
358 G.zipfn = G.argv0; /* for "cannot find myself" message only */
360 #endif /* EXE_EXTENSION */
361 #ifdef WIN32
362 G.zipfn = G.argv0; /* for "cannot find myself" message only */
363 #endif
365 if (error) {
366 if (error == IZ_DIR)
367 error_in_archive = PK_NOZIP;
368 else
369 error_in_archive = error;
370 if (error == PK_NOZIP)
371 Info(slide, 1, ((char *)slide, LoadFarString(CannotFindMyself),
372 G.zipfn));
374 #ifdef CHEAP_SFX_AUTORUN
375 if (G.autorun_command[0] && !uO.qflag) { /* NO autorun without prompt! */
376 Info(slide, 0x81, ((char *)slide, LoadFarString(AutorunPrompt),
377 FnFilter1(G.autorun_command)));
378 if (fgets(G.answerbuf, 9, stdin) != (char *)NULL
379 && toupper(*G.answerbuf) == 'Y')
380 system(G.autorun_command);
381 else
382 Info(slide, 1, ((char *)slide, LoadFarString(NotAutoRunning)));
384 #endif /* CHEAP_SFX_AUTORUN */
386 int sfx_app_ret = sfx_app_autorun_now();
388 #else /* !SFX */
389 NumWinFiles = NumLoseFiles = NumWarnFiles = 0;
390 NumMissDirs = NumMissFiles = 0;
392 while ((G.zipfn = do_wild(__G__ G.wildzipfn)) != (char *)NULL) {
393 Trace((stderr, "do_wild( %s ) returns %s\n", G.wildzipfn, G.zipfn));
395 lastzipfn = G.zipfn;
397 /* print a blank line between the output of different zipfiles */
398 if (!uO.qflag && error != PK_NOZIP && error != IZ_DIR
399 #ifdef TIMESTAMP
400 && (!uO.T_flag || uO.zipinfo_mode)
401 #endif
402 && (NumWinFiles+NumLoseFiles+NumWarnFiles+NumMissFiles) > 0)
403 (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0);
405 if ((error = do_seekable(__G__ 0)) == PK_WARN)
406 ++NumWarnFiles;
407 else if (error == IZ_DIR)
408 ++NumMissDirs;
409 else if (error == PK_NOZIP)
410 ++NumMissFiles;
411 else if (error != PK_OK)
412 ++NumLoseFiles;
413 else
414 ++NumWinFiles;
416 Trace((stderr, "do_seekable(0) returns %d\n", error));
417 if (error != IZ_DIR && error > error_in_archive)
418 error_in_archive = error;
419 #ifdef WINDLL
420 if (error == IZ_CTRLC) {
421 free_G_buffers(__G);
422 return error;
424 #endif
426 } /* end while-loop (wildcard zipfiles) */
428 if ((NumWinFiles + NumWarnFiles + NumLoseFiles) == 0 &&
429 (NumMissDirs + NumMissFiles) == 1 && lastzipfn != (char *)NULL)
431 #if (!defined(UNIX) && !defined(AMIGA)) /* filenames with wildcard characters */
432 if (iswild(G.wildzipfn)) {
433 if (iswild(lastzipfn)) {
434 NumMissDirs = NumMissFiles = 0;
435 error_in_archive = PK_COOL;
436 if (uO.qflag < 3)
437 Info(slide, 0x401, ((char *)slide,
438 LoadFarString(CannotFindWildcardMatch),
439 LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)),
440 G.wildzipfn));
442 } else
443 #endif
445 #ifndef VMS
446 /* 2004-11-24 SMS.
447 * VMS has already tried a default file type of ".zip" in
448 * do_wild(), so adding ZSUFX here only causes confusion by
449 * corrupting some valid (though nonexistent) file names.
450 * Complaining below about "fred;4.zip" is unlikely to be
451 * helpful to the victim.
453 /* 2005-08-14 Chr. Spieler
454 * Although we already "know" the failure result, we call
455 * do_seekable() again with the same zipfile name (and the
456 * lastchance flag set), just to trigger the error report...
458 #if defined(UNIX) || defined(QDOS)
459 char *p =
460 #endif
461 strcpy(lastzipfn + strlen(lastzipfn), ZSUFX);
462 #endif /* !VMS */
464 G.zipfn = lastzipfn;
466 NumMissDirs = NumMissFiles = 0;
467 error_in_archive = PK_COOL;
469 #if defined(UNIX) || defined(QDOS)
470 /* only Unix has case-sensitive filesystems */
471 /* Well FlexOS (sometimes) also has them, but support is per media */
472 /* and a pig to code for, so treat as case insensitive for now */
473 /* we do this under QDOS to check for .zip as well as _zip */
474 if ((error = do_seekable(__G__ 0)) == PK_NOZIP || error == IZ_DIR) {
475 if (error == IZ_DIR)
476 ++NumMissDirs;
477 strcpy(p, ALT_ZSUFX);
478 error = do_seekable(__G__ 1);
480 #else
481 error = do_seekable(__G__ 1);
482 #endif
483 Trace((stderr, "do_seekable(1) returns %d\n", error));
484 switch (error) {
485 case PK_WARN:
486 ++NumWarnFiles;
487 break;
488 case IZ_DIR:
489 ++NumMissDirs;
490 error = PK_NOZIP;
491 break;
492 case PK_NOZIP:
493 /* increment again => bug:
494 "1 file had no zipfile directory." */
495 /* ++NumMissFiles */ ;
496 break;
497 default:
498 if (error)
499 ++NumLoseFiles;
500 else
501 ++NumWinFiles;
502 break;
505 if (error > error_in_archive)
506 error_in_archive = error;
507 #ifdef WINDLL
508 if (error == IZ_CTRLC) {
509 free_G_buffers(__G);
510 return error;
512 #endif
515 #endif /* ?SFX */
517 /*---------------------------------------------------------------------------
518 Print summary of all zipfiles, assuming zipfile spec was a wildcard (no
519 need for a summary if just one zipfile).
520 ---------------------------------------------------------------------------*/
522 #ifndef SFX
523 if (iswild(G.wildzipfn) && uO.qflag < 3
524 #ifdef TIMESTAMP
525 && !(uO.T_flag && !uO.zipinfo_mode && uO.qflag > 1)
526 #endif
529 if ((NumMissFiles + NumLoseFiles + NumWarnFiles > 0 || NumWinFiles != 1)
530 #ifdef TIMESTAMP
531 && !(uO.T_flag && !uO.zipinfo_mode && uO.qflag)
532 #endif
533 && !(uO.tflag && uO.qflag > 1))
534 (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0x401);
535 if ((NumWinFiles > 1) ||
536 (NumWinFiles == 1 &&
537 NumMissDirs + NumMissFiles + NumLoseFiles + NumWarnFiles > 0))
538 Info(slide, 0x401, ((char *)slide, LoadFarString(FilesProcessOK),
539 NumWinFiles, (NumWinFiles == 1)? " was" : "s were"));
540 if (NumWarnFiles > 0)
541 Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveWarning),
542 NumWarnFiles, (NumWarnFiles == 1)? "" : "s"));
543 if (NumLoseFiles > 0)
544 Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveFatalError),
545 NumLoseFiles, (NumLoseFiles == 1)? "" : "s"));
546 if (NumMissFiles > 0)
547 Info(slide, 0x401, ((char *)slide,
548 LoadFarString(FileHadNoZipfileDir), NumMissFiles,
549 (NumMissFiles == 1)? "" : "s"));
550 if (NumMissDirs == 1)
551 Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileWasDir)));
552 else if (NumMissDirs > 0)
553 Info(slide, 0x401, ((char *)slide,
554 LoadFarString(ManyZipfilesWereDir), NumMissDirs));
555 if (NumWinFiles + NumLoseFiles + NumWarnFiles == 0)
556 Info(slide, 0x401, ((char *)slide, LoadFarString(NoZipfileFound)));
558 #endif /* !SFX */
560 /* free allocated memory */
561 free_G_buffers(__G);
563 return sfx_app_ret;
565 } /* end function process_zipfiles() */
571 /*****************************/
572 /* Function free_G_buffers() */
573 /*****************************/
575 void free_G_buffers(__G) /* releases all memory allocated in global vars */
576 __GDEF
578 #ifndef SFX
579 unsigned i;
580 #endif
582 #ifdef SYSTEM_SPECIFIC_DTOR
583 SYSTEM_SPECIFIC_DTOR(__G);
584 #endif
586 inflate_free(__G);
587 checkdir(__G__ (char *)NULL, END);
589 #ifdef DYNALLOC_CRCTAB
590 if (CRC_32_TAB) {
591 free_crc_table();
592 CRC_32_TAB = NULL;
594 #endif
596 if (G.key != (char *)NULL) {
597 free(G.key);
598 G.key = (char *)NULL;
601 if (G.extra_field != (uch *)NULL) {
602 free(G.extra_field);
603 G.extra_field = (uch *)NULL;
606 #if (!defined(VMS) && !defined(SMALL_MEM))
607 /* VMS uses its own buffer scheme for textmode flush() */
608 if (G.outbuf2) {
609 free(G.outbuf2); /* malloc'd ONLY if unshrink and -a */
610 G.outbuf2 = (uch *)NULL;
612 #endif
614 if (G.outbuf)
615 free(G.outbuf);
616 if (G.inbuf)
617 free(G.inbuf);
618 G.inbuf = G.outbuf = (uch *)NULL;
620 #ifdef UNICODE_SUPPORT
621 if (G.filename_full) {
622 free(G.filename_full);
623 G.filename_full = (char *)NULL;
624 G.fnfull_bufsize = 0;
626 #endif /* UNICODE_SUPPORT */
628 #ifndef SFX
629 for (i = 0; i < DIR_BLKSIZ; i++) {
630 if (G.info[i].cfilname != (char Far *)NULL) {
631 zffree(G.info[i].cfilname);
632 G.info[i].cfilname = (char Far *)NULL;
635 #endif
637 #ifdef MALLOC_WORK
638 if (G.area.Slide) {
639 free(G.area.Slide);
640 G.area.Slide = (uch *)NULL;
642 #endif
644 } /* end function free_G_buffers() */
650 /**************************/
651 /* Function do_seekable() */
652 /**************************/
654 static int do_seekable(__G__ lastchance) /* return PK-type error code */
655 __GDEF
656 int lastchance;
658 #ifndef SFX
659 /* static int no_ecrec = FALSE; SKM: moved to globals.h */
660 int maybe_exe=FALSE;
661 int too_weird_to_continue=FALSE;
662 #ifdef TIMESTAMP
663 time_t uxstamp;
664 ulg nmember = 0L;
665 #endif
666 #endif
667 int error=0, error_in_archive;
670 /*---------------------------------------------------------------------------
671 Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
672 which would corrupt the bit streams.
673 ---------------------------------------------------------------------------*/
675 if (SSTAT(G.zipfn, &G.statbuf) ||
676 #ifdef THEOS
677 (error = S_ISLIB(G.statbuf.st_mode)) != 0 ||
678 #endif
679 (error = S_ISDIR(G.statbuf.st_mode)) != 0)
681 #ifndef SFX
682 if (lastchance && (uO.qflag < 3)) {
683 #if defined(UNIX) || defined(QDOS)
684 if (G.no_ecrec)
685 Info(slide, 1, ((char *)slide,
686 LoadFarString(CannotFindZipfileDirMsg),
687 LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)),
688 G.wildzipfn, uO.zipinfo_mode? " " : "", G.wildzipfn,
689 G.zipfn));
690 else
691 Info(slide, 1, ((char *)slide,
692 LoadFarString(CannotFindEitherZipfile),
693 LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)),
694 G.wildzipfn, G.wildzipfn, G.zipfn));
695 #else /* !(UNIX || QDOS) */
696 if (G.no_ecrec)
697 Info(slide, 0x401, ((char *)slide,
698 LoadFarString(CannotFindZipfileDirMsg),
699 LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)),
700 G.wildzipfn, uO.zipinfo_mode? " " : "", G.zipfn));
701 else
702 #ifdef VMS
703 Info(slide, 0x401, ((char *)slide,
704 LoadFarString(CannotFindEitherZipfile),
705 LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)),
706 G.wildzipfn,
707 (*G.zipfn ? G.zipfn : vms_msg_text())));
708 #else /* !VMS */
709 Info(slide, 0x401, ((char *)slide,
710 LoadFarString(CannotFindEitherZipfile),
711 LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)),
712 G.wildzipfn, G.zipfn));
713 #endif /* ?VMS */
714 #endif /* ?(UNIX || QDOS) */
716 #endif /* !SFX */
717 return error? IZ_DIR : PK_NOZIP;
719 G.ziplen = G.statbuf.st_size;
721 #ifndef SFX
722 #if defined(UNIX) || defined(DOS_OS2_W32) || defined(THEOS)
723 if (G.statbuf.st_mode & S_IEXEC) /* no extension on Unix exes: might */
724 maybe_exe = TRUE; /* find unzip, not unzip.zip; etc. */
725 #endif
726 #endif /* !SFX */
728 #ifdef VMS
729 if (check_format(__G)) /* check for variable-length format */
730 return PK_ERR;
731 #endif
733 if (open_input_file(__G)) /* this should never happen, given */
734 return PK_NOZIP; /* the stat() test above, but... */
736 #ifdef DO_SAFECHECK_2GB
737 /* Need more care: Do not trust the size returned by stat() but
738 determine it by reading beyond the end of the file. */
739 G.ziplen = file_size(G.zipfd);
741 if (G.ziplen == EOF) {
742 Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileTooBig)));
744 printf(
745 " We need a better error message for: 64-bit file, 32-bit program.\n");
747 CLOSE_INFILE();
748 return IZ_ERRBF;
750 #endif /* DO_SAFECHECK_2GB */
752 /*---------------------------------------------------------------------------
753 Find and process the end-of-central-directory header. UnZip need only
754 check last 65557 bytes of zipfile: comment may be up to 65535, end-of-
755 central-directory record is 18 bytes, and signature itself is 4 bytes;
756 add some to allow for appended garbage. Since ZipInfo is often used as
757 a debugging tool, search the whole zipfile if zipinfo_mode is true.
758 ---------------------------------------------------------------------------*/
760 G.cur_zipfile_bufstart = 0;
761 G.inptr = G.inbuf;
763 #if ((!defined(WINDLL) && !defined(SFX)) || !defined(NO_ZIPINFO))
764 # if (!defined(WINDLL) && !defined(SFX))
765 if ( (!uO.zipinfo_mode && !uO.qflag
766 # ifdef TIMESTAMP
767 && !uO.T_flag
768 # endif
770 # ifndef NO_ZIPINFO
771 || (uO.zipinfo_mode && uO.hflag)
772 # endif
774 # else /* not (!WINDLL && !SFX) ==> !NO_ZIPINFO !! */
775 if (uO.zipinfo_mode && uO.hflag)
776 # endif /* if..else..: (!WINDLL && !SFX) */
777 # ifdef WIN32 /* Win32 console may require codepage conversion for G.zipfn */
778 Info(slide, 0, ((char *)slide, LoadFarString(LogInitline),
779 FnFilter1(G.zipfn)));
780 # else
781 Info(slide, 0, ((char *)slide, LoadFarString(LogInitline), G.zipfn));
782 # endif
783 #endif /* (!WINDLL && !SFX) || !NO_ZIPINFO */
785 if ( (error_in_archive = find_ecrec(__G__
786 #ifndef NO_ZIPINFO
787 uO.zipinfo_mode ? G.ziplen :
788 #endif
789 MIN(G.ziplen, 66000L)))
790 > PK_WARN )
792 CLOSE_INFILE();
794 #ifdef SFX
795 ++lastchance; /* avoid picky compiler warnings */
796 return error_in_archive;
797 #else
798 if (maybe_exe)
799 Info(slide, 0x401, ((char *)slide, LoadFarString(MaybeExe),
800 G.zipfn));
801 if (lastchance)
802 return error_in_archive;
803 else {
804 G.no_ecrec = TRUE; /* assume we found wrong file: e.g., */
805 return PK_NOZIP; /* unzip instead of unzip.zip */
807 #endif /* ?SFX */
810 if ((uO.zflag > 0) && !uO.zipinfo_mode) { /* unzip: zflag = comment ONLY */
811 CLOSE_INFILE();
812 return error_in_archive;
815 /*---------------------------------------------------------------------------
816 Test the end-of-central-directory info for incompatibilities (multi-disk
817 archives) or inconsistencies (missing or extra bytes in zipfile).
818 ---------------------------------------------------------------------------*/
820 #ifdef NO_MULTIPART
821 error = !uO.zipinfo_mode && (G.ecrec.number_this_disk == 1) &&
822 (G.ecrec.num_disk_start_cdir == 1);
823 #else
824 error = !uO.zipinfo_mode && (G.ecrec.number_this_disk != 0);
825 #endif
827 #ifndef SFX
828 if (uO.zipinfo_mode &&
829 G.ecrec.number_this_disk != G.ecrec.num_disk_start_cdir)
831 if (G.ecrec.number_this_disk > G.ecrec.num_disk_start_cdir) {
832 Info(slide, 0x401, ((char *)slide,
833 LoadFarString(CentDirNotInZipMsg), G.zipfn,
834 (ulg)G.ecrec.number_this_disk,
835 (ulg)G.ecrec.num_disk_start_cdir));
836 error_in_archive = PK_FIND;
837 too_weird_to_continue = TRUE;
838 } else {
839 Info(slide, 0x401, ((char *)slide,
840 LoadFarString(EndCentDirBogus), G.zipfn,
841 (ulg)G.ecrec.number_this_disk,
842 (ulg)G.ecrec.num_disk_start_cdir));
843 error_in_archive = PK_WARN;
845 #ifdef NO_MULTIPART /* concatenation of multiple parts works in some cases */
846 } else if (!uO.zipinfo_mode && !error && G.ecrec.number_this_disk != 0) {
847 Info(slide, 0x401, ((char *)slide, LoadFarString(NoMultiDiskArcSupport),
848 G.zipfn));
849 error_in_archive = PK_FIND;
850 too_weird_to_continue = TRUE;
851 #endif
854 if (!too_weird_to_continue) { /* (relatively) normal zipfile: go for it */
855 if (error) {
856 Info(slide, 0x401, ((char *)slide, LoadFarString(MaybePakBug),
857 G.zipfn));
858 error_in_archive = PK_WARN;
860 #endif /* !SFX */
861 if ((G.extra_bytes = G.real_ecrec_offset-G.expect_ecrec_offset) <
862 (zoff_t)0)
864 Info(slide, 0x401, ((char *)slide, LoadFarString(MissingBytes),
865 G.zipfn, FmZofft((-G.extra_bytes), NULL, NULL)));
866 error_in_archive = PK_ERR;
867 } else if (G.extra_bytes > 0) {
868 if ((G.ecrec.offset_start_central_directory == 0) &&
869 (G.ecrec.size_central_directory != 0)) /* zip 1.5 -go bug */
871 Info(slide, 0x401, ((char *)slide,
872 LoadFarString(NullCentDirOffset), G.zipfn));
873 G.ecrec.offset_start_central_directory = G.extra_bytes;
874 G.extra_bytes = 0;
875 error_in_archive = PK_ERR;
877 #ifndef SFX
878 else {
879 Info(slide, 0x401, ((char *)slide,
880 LoadFarString(ExtraBytesAtStart), G.zipfn,
881 FmZofft(G.extra_bytes, NULL, NULL),
882 (G.extra_bytes == 1)? "":"s"));
883 error_in_archive = PK_WARN;
885 #endif /* !SFX */
888 /*-----------------------------------------------------------------------
889 Check for empty zipfile and exit now if so.
890 -----------------------------------------------------------------------*/
892 if (G.expect_ecrec_offset==0L && G.ecrec.size_central_directory==0) {
893 if (uO.zipinfo_mode)
894 Info(slide, 0, ((char *)slide, "%sEmpty zipfile.\n",
895 uO.lflag>9? "\n " : ""));
896 else
897 Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileEmpty),
898 G.zipfn));
899 CLOSE_INFILE();
900 return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN;
903 /*-----------------------------------------------------------------------
904 Compensate for missing or extra bytes, and seek to where the start
905 of central directory should be. If header not found, uncompensate
906 and try again (necessary for at least some Atari archives created
907 with STZip, as well as archives created by J.H. Holm's ZIPSPLIT 1.1).
908 -----------------------------------------------------------------------*/
910 error = seek_zipf(__G__ G.ecrec.offset_start_central_directory);
911 if (error == PK_BADERR) {
912 CLOSE_INFILE();
913 return PK_BADERR;
915 #ifdef OLD_SEEK_TEST
916 if (error != PK_OK || readbuf(__G__ G.sig, 4) == 0) {
917 CLOSE_INFILE();
918 return PK_ERR; /* file may be locked, or possibly disk error(?) */
920 if (memcmp(G.sig, central_hdr_sig, 4))
921 #else
922 if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) ||
923 memcmp(G.sig, central_hdr_sig, 4))
924 #endif
926 #ifndef SFX
927 zoff_t tmp = G.extra_bytes;
928 #endif
930 G.extra_bytes = 0;
931 error = seek_zipf(__G__ G.ecrec.offset_start_central_directory);
932 if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) ||
933 memcmp(G.sig, central_hdr_sig, 4))
935 if (error != PK_BADERR)
936 Info(slide, 0x401, ((char *)slide,
937 LoadFarString(CentDirStartNotFound), G.zipfn,
938 LoadFarStringSmall(ReportMsg)));
939 CLOSE_INFILE();
940 return (error != PK_OK ? error : PK_BADERR);
942 #ifndef SFX
943 Info(slide, 0x401, ((char *)slide, LoadFarString(CentDirTooLong),
944 G.zipfn, FmZofft((-tmp), NULL, NULL)));
945 #endif
946 error_in_archive = PK_ERR;
949 /*-----------------------------------------------------------------------
950 Seek to the start of the central directory one last time, since we
951 have just read the first entry's signature bytes; then list, extract
952 or test member files as instructed, and close the zipfile.
953 -----------------------------------------------------------------------*/
955 error = seek_zipf(__G__ G.ecrec.offset_start_central_directory);
956 if (error != PK_OK) {
957 CLOSE_INFILE();
958 return error;
961 Trace((stderr, "about to extract/list files (error = %d)\n",
962 error_in_archive));
964 #ifdef DLL
965 /* G.fValidate is used only to look at an archive to see if
966 it appears to be a valid archive. There is no interest
967 in what the archive contains, nor in validating that the
968 entries in the archive are in good condition. This is
969 currently used only in the Windows DLLs for purposes of
970 checking archives within an archive to determine whether
971 or not to display the inner archives.
973 if (!G.fValidate)
974 #endif
976 #ifndef NO_ZIPINFO
977 if (uO.zipinfo_mode)
978 error = zipinfo(__G); /* ZIPINFO 'EM */
979 else
980 #endif
981 #ifndef SFX
982 #ifdef TIMESTAMP
983 if (uO.T_flag)
984 error = get_time_stamp(__G__ &uxstamp, &nmember);
985 else
986 #endif
987 if (uO.vflag && !uO.tflag && !uO.cflag)
988 error = list_files(__G); /* LIST 'EM */
989 else
990 #endif /* !SFX */
991 error = extract_or_test_files(__G); /* EXTRACT OR TEST 'EM */
993 Trace((stderr, "done with extract/list files (error = %d)\n",
994 error));
997 if (error > error_in_archive) /* don't overwrite stronger error */
998 error_in_archive = error; /* with (for example) a warning */
999 #ifndef SFX
1000 } /* end if (!too_weird_to_continue) */
1001 #endif
1003 CLOSE_INFILE();
1005 #ifdef TIMESTAMP
1006 if (uO.T_flag && !uO.zipinfo_mode && (nmember > 0L)) {
1007 # ifdef WIN32
1008 if (stamp_file(__G__ G.zipfn, uxstamp)) { /* TIME-STAMP 'EM */
1009 # else
1010 if (stamp_file(G.zipfn, uxstamp)) { /* TIME-STAMP 'EM */
1011 # endif
1012 if (uO.qflag < 3)
1013 Info(slide, 0x201, ((char *)slide,
1014 LoadFarString(ZipTimeStampFailed), G.zipfn));
1015 if (error_in_archive < PK_WARN)
1016 error_in_archive = PK_WARN;
1017 } else {
1018 if (!uO.qflag)
1019 Info(slide, 0, ((char *)slide,
1020 LoadFarString(ZipTimeStampSuccess), G.zipfn));
1023 #endif
1024 return error_in_archive;
1026 } /* end function do_seekable() */
1031 #ifdef DO_SAFECHECK_2GB
1032 /************************/
1033 /* Function file_size() */
1034 /************************/
1035 /* File size determination which does not mislead for large files in a
1036 small-file program. Probably should be somewhere else.
1037 The file has to be opened previously
1039 #ifdef USE_STRM_INPUT
1040 static zoff_t file_size(file)
1041 FILE *file;
1043 int sts;
1044 size_t siz;
1045 #else /* !USE_STRM_INPUT */
1046 static zoff_t file_size(fh)
1047 int fh;
1049 int siz;
1050 #endif /* ?USE_STRM_INPUT */
1051 zoff_t ofs;
1052 char waste[4];
1054 #ifdef USE_STRM_INPUT
1055 /* Seek to actual EOF. */
1056 sts = zfseeko(file, 0, SEEK_END);
1057 if (sts != 0) {
1058 /* fseeko() failed. (Unlikely.) */
1059 ofs = EOF;
1060 } else {
1061 /* Get apparent offset at EOF. */
1062 ofs = zftello(file);
1063 if (ofs < 0) {
1064 /* Offset negative (overflow). File too big. */
1065 ofs = EOF;
1066 } else {
1067 /* Seek to apparent EOF offset.
1068 Won't be at actual EOF if offset was truncated.
1070 sts = zfseeko(file, ofs, SEEK_SET);
1071 if (sts != 0) {
1072 /* fseeko() failed. (Unlikely.) */
1073 ofs = EOF;
1074 } else {
1075 /* Read a byte at apparent EOF. Should set EOF flag. */
1076 siz = fread(waste, 1, 1, file);
1077 if (feof(file) == 0) {
1078 /* Not at EOF, but should be. File too big. */
1079 ofs = EOF;
1084 #else /* !USE_STRM_INPUT */
1085 /* Seek to actual EOF. */
1086 ofs = zlseek(fh, 0, SEEK_END);
1087 if (ofs == (zoff_t) -1) {
1088 /* zlseek() failed. (Unlikely.) */
1089 ofs = EOF;
1090 } else if (ofs < 0) {
1091 /* Offset negative (overflow). File too big. */
1092 ofs = EOF;
1093 } else {
1094 /* Seek to apparent EOF offset.
1095 Won't be at actual EOF if offset was truncated.
1097 ofs = zlseek(fh, ofs, SEEK_SET);
1098 if (ofs == (zoff_t) -1) {
1099 /* zlseek() failed. (Unlikely.) */
1100 ofs = EOF;
1101 } else {
1102 /* Read a byte at apparent EOF. Should set EOF flag. */
1103 siz = read(fh, waste, 1);
1104 if (siz != 0) {
1105 /* Not at EOF, but should be. File too big. */
1106 ofs = EOF;
1110 #endif /* ?USE_STRM_INPUT */
1111 return ofs;
1112 } /* end function file_size() */
1113 #endif /* DO_SAFECHECK_2GB */
1118 /***********************/
1119 /* Function rec_find() */
1120 /***********************/
1122 static int rec_find(__G__ searchlen, signature, rec_size)
1123 /* return 0 when rec found, 1 when not found, 2 in case of read error */
1124 __GDEF
1125 zoff_t searchlen;
1126 char* signature;
1127 int rec_size;
1129 int i, numblks, found=FALSE;
1130 zoff_t tail_len;
1132 /*---------------------------------------------------------------------------
1133 Zipfile is longer than INBUFSIZ: may need to loop. Start with short
1134 block at end of zipfile (if not TOO short).
1135 ---------------------------------------------------------------------------*/
1137 if ((tail_len = G.ziplen % INBUFSIZ) > rec_size) {
1138 #ifdef USE_STRM_INPUT
1139 zfseeko(G.zipfd, G.ziplen-tail_len, SEEK_SET);
1140 G.cur_zipfile_bufstart = zftello(G.zipfd);
1141 #else /* !USE_STRM_INPUT */
1142 G.cur_zipfile_bufstart = zlseek(G.zipfd, G.ziplen-tail_len, SEEK_SET);
1143 #endif /* ?USE_STRM_INPUT */
1144 if ((G.incnt = read(G.zipfd, (char *)G.inbuf,
1145 (unsigned int)tail_len)) != (int)tail_len)
1146 return 2; /* it's expedient... */
1148 /* 'P' must be at least (rec_size+4) bytes from end of zipfile */
1149 for (G.inptr = G.inbuf+(int)tail_len-(rec_size+4);
1150 G.inptr >= G.inbuf;
1151 --G.inptr) {
1152 if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */
1153 !memcmp((char *)G.inptr, signature, 4) ) {
1154 G.incnt -= (int)(G.inptr - G.inbuf);
1155 found = TRUE;
1156 break;
1159 /* sig may span block boundary: */
1160 memcpy((char *)G.hold, (char *)G.inbuf, 3);
1161 } else
1162 G.cur_zipfile_bufstart = G.ziplen - tail_len;
1164 /*-----------------------------------------------------------------------
1165 Loop through blocks of zipfile data, starting at the end and going
1166 toward the beginning. In general, need not check whole zipfile for
1167 signature, but may want to do so if testing.
1168 -----------------------------------------------------------------------*/
1170 numblks = (int)((searchlen - tail_len + (INBUFSIZ-1)) / INBUFSIZ);
1171 /* ==amount= ==done== ==rounding== =blksiz= */
1173 for (i = 1; !found && (i <= numblks); ++i) {
1174 G.cur_zipfile_bufstart -= INBUFSIZ;
1175 #ifdef USE_STRM_INPUT
1176 zfseeko(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET);
1177 #else /* !USE_STRM_INPUT */
1178 zlseek(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET);
1179 #endif /* ?USE_STRM_INPUT */
1180 if ((G.incnt = read(G.zipfd,(char *)G.inbuf,INBUFSIZ))
1181 != INBUFSIZ)
1182 return 2; /* read error is fatal failure */
1184 for (G.inptr = G.inbuf+INBUFSIZ-1; G.inptr >= G.inbuf; --G.inptr)
1185 if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */
1186 !memcmp((char *)G.inptr, signature, 4) ) {
1187 G.incnt -= (int)(G.inptr - G.inbuf);
1188 found = TRUE;
1189 break;
1191 /* sig may span block boundary: */
1192 memcpy((char *)G.hold, (char *)G.inbuf, 3);
1194 return (found ? 0 : 1);
1195 } /* end function rec_find() */
1200 #if 0
1201 /********************************/
1202 /* Function check_ecrec_zip64() */
1203 /********************************/
1205 static int check_ecrec_zip64(__G)
1206 __GDEF
1208 return G.ecrec.offset_start_central_directory == 0xFFFFFFFFL
1209 || G.ecrec.size_central_directory == 0xFFFFFFFFL
1210 || G.ecrec.total_entries_central_dir == 0xFFFF
1211 || G.ecrec.num_entries_centrl_dir_ths_disk == 0xFFFF
1212 || G.ecrec.num_disk_start_cdir == 0xFFFF
1213 || G.ecrec.number_this_disk == 0xFFFF;
1214 } /* end function check_ecrec_zip64() */
1215 #endif /* never */
1219 /***************************/
1220 /* Function find_ecrec64() */
1221 /***************************/
1223 static int find_ecrec64(__G__ searchlen) /* return PK-class error */
1224 __GDEF
1225 zoff_t searchlen;
1227 ec_byte_rec64 byterec; /* buf for ecrec64 */
1228 ec_byte_loc64 byterecL; /* buf for ecrec64 locator */
1229 zoff_t ecloc64_start_offset; /* start offset of ecrec64 locator */
1230 zusz_t ecrec64_start_offset; /* start offset of ecrec64 */
1231 zuvl_t ecrec64_start_disk; /* start disk of ecrec64 */
1232 zuvl_t ecloc64_total_disks; /* total disks */
1233 zuvl_t ecrec64_disk_cdstart; /* disk number of central dir start */
1234 zucn_t ecrec64_this_entries; /* entries on disk with ecrec64 */
1235 zucn_t ecrec64_tot_entries; /* total number of entries */
1236 zusz_t ecrec64_cdirsize; /* length of central dir */
1237 zusz_t ecrec64_offs_cdstart; /* offset of central dir start */
1239 /* First, find the ecrec64 locator. By definition, this must be before
1240 ecrec with nothing in between. We back up the size of the ecrec64
1241 locator and check. */
1243 ecloc64_start_offset = G.real_ecrec_offset - (ECLOC64_SIZE+4);
1244 if (ecloc64_start_offset < 0)
1245 /* Seeking would go past beginning, so probably empty archive */
1246 return PK_COOL;
1248 #ifdef USE_STRM_INPUT
1249 zfseeko(G.zipfd, ecloc64_start_offset, SEEK_SET);
1250 G.cur_zipfile_bufstart = zftello(G.zipfd);
1251 #else /* !USE_STRM_INPUT */
1252 G.cur_zipfile_bufstart = zlseek(G.zipfd, ecloc64_start_offset, SEEK_SET);
1253 #endif /* ?USE_STRM_INPUT */
1255 if ((G.incnt = read(G.zipfd, (char *)byterecL, ECLOC64_SIZE+4))
1256 != (ECLOC64_SIZE+4)) {
1257 if (uO.qflag || uO.zipinfo_mode)
1258 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
1259 Info(slide, 0x401, ((char *)slide,
1260 LoadFarString(Cent64EndSigSearchErr)));
1261 return PK_ERR;
1264 if (memcmp((char *)byterecL, end_centloc64_sig, 4) ) {
1265 /* not found */
1266 return PK_COOL;
1269 /* Read the locator. */
1270 ecrec64_start_disk = (zuvl_t)makelong(&byterecL[NUM_DISK_START_EOCDR64]);
1271 ecrec64_start_offset = (zusz_t)makeint64(&byterecL[OFFSET_START_EOCDR64]);
1272 ecloc64_total_disks = (zuvl_t)makelong(&byterecL[NUM_THIS_DISK_LOC64]);
1274 /* Check for consistency */
1275 #ifdef TEST
1276 fprintf(stdout,"\nnumber of disks (ECR) %u, (ECLOC64) %lu\n",
1277 G.ecrec.number_this_disk, ecloc64_total_disks); fflush(stdout);
1278 #endif
1279 if ((G.ecrec.number_this_disk != 0xFFFF) &&
1280 (G.ecrec.number_this_disk != ecloc64_total_disks - 1)) {
1281 /* Note: For some unknown reason, the developers at PKWARE decided to
1282 store the "zip64 total disks" value as a counter starting from 1,
1283 whereas all other "split/span volume" related fields use 0-based
1284 volume numbers. Sigh... */
1285 /* When the total number of disks as found in the traditional ecrec
1286 is not 0xFFFF, the disk numbers in ecrec and ecloc64 must match.
1287 When this is not the case, the found ecrec64 locator cannot be valid.
1288 -> This is not a Zip64 archive.
1290 Trace((stderr,
1291 "\ninvalid ECLOC64, differing disk# (ECR %u, ECL64 %lu)\n",
1292 G.ecrec.number_this_disk, ecloc64_total_disks - 1));
1293 return PK_COOL;
1296 /* If found locator, look for ecrec64 where the locator says it is. */
1298 /* For now assume that ecrec64 is on the same disk as ecloc64 and ecrec,
1299 which is usually the case and is how Zip writes it. To do this right,
1300 however, we should allow the ecrec64 to be on another disk since
1301 the AppNote allows it and the ecrec64 can be large, especially if
1302 Version 2 is used (AppNote uses 8 bytes for the size of this record). */
1304 /* FIX BELOW IF ADD SUPPORT FOR MULTIPLE DISKS */
1306 if (ecrec64_start_offset > (zusz_t)ecloc64_start_offset) {
1307 /* ecrec64 has to be before ecrec64 locator */
1308 if (uO.qflag || uO.zipinfo_mode)
1309 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
1310 Info(slide, 0x401, ((char *)slide,
1311 LoadFarString(Cent64EndSigSearchErr)));
1312 return PK_ERR;
1315 #ifdef USE_STRM_INPUT
1316 zfseeko(G.zipfd, ecrec64_start_offset, SEEK_SET);
1317 G.cur_zipfile_bufstart = zftello(G.zipfd);
1318 #else /* !USE_STRM_INPUT */
1319 G.cur_zipfile_bufstart = zlseek(G.zipfd, ecrec64_start_offset, SEEK_SET);
1320 #endif /* ?USE_STRM_INPUT */
1322 if ((G.incnt = read(G.zipfd, (char *)byterec, ECREC64_SIZE+4))
1323 != (ECREC64_SIZE+4)) {
1324 if (uO.qflag || uO.zipinfo_mode)
1325 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
1326 Info(slide, 0x401, ((char *)slide,
1327 LoadFarString(Cent64EndSigSearchErr)));
1328 return PK_ERR;
1331 if (memcmp((char *)byterec, end_central64_sig, 4) ) {
1332 /* Zip64 EOCD Record not found */
1333 /* Since we already have seen the Zip64 EOCD Locator, it's
1334 possible we got here because there are bytes prepended
1335 to the archive, like the sfx prefix. */
1337 /* Make a guess as to where the Zip64 EOCD Record might be */
1338 ecrec64_start_offset = ecloc64_start_offset - ECREC64_SIZE - 4;
1340 #ifdef USE_STRM_INPUT
1341 zfseeko(G.zipfd, ecrec64_start_offset, SEEK_SET);
1342 G.cur_zipfile_bufstart = zftello(G.zipfd);
1343 #else /* !USE_STRM_INPUT */
1344 G.cur_zipfile_bufstart = zlseek(G.zipfd, ecrec64_start_offset, SEEK_SET);
1345 #endif /* ?USE_STRM_INPUT */
1347 if ((G.incnt = read(G.zipfd, (char *)byterec, ECREC64_SIZE+4))
1348 != (ECREC64_SIZE+4)) {
1349 if (uO.qflag || uO.zipinfo_mode)
1350 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
1351 Info(slide, 0x401, ((char *)slide,
1352 LoadFarString(Cent64EndSigSearchErr)));
1353 return PK_ERR;
1356 if (memcmp((char *)byterec, end_central64_sig, 4) ) {
1357 /* Zip64 EOCD Record not found */
1358 /* Probably something not so easy to handle so exit */
1359 if (uO.qflag || uO.zipinfo_mode)
1360 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
1361 Info(slide, 0x401, ((char *)slide,
1362 LoadFarString(Cent64EndSigSearchErr)));
1363 return PK_ERR;
1366 if (uO.qflag || uO.zipinfo_mode)
1367 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
1368 Info(slide, 0x401, ((char *)slide,
1369 LoadFarString(Cent64EndSigSearchOff)));
1372 /* Check consistency of found ecrec64 with ecloc64 (and ecrec): */
1373 if ( (zuvl_t)makelong(&byterec[NUMBER_THIS_DSK_REC64])
1374 != ecrec64_start_disk )
1375 /* found ecrec64 does not match ecloc64 info -> no Zip64 archive */
1376 return PK_COOL;
1377 /* Read all relevant ecrec64 fields and compare them to the corresponding
1378 ecrec fields unless those are set to "all-ones".
1380 ecrec64_disk_cdstart =
1381 (zuvl_t)makelong(&byterec[NUM_DISK_START_CEN_DIR64]);
1382 if ( (G.ecrec.num_disk_start_cdir != 0xFFFF) &&
1383 (G.ecrec.num_disk_start_cdir != ecrec64_disk_cdstart) )
1384 return PK_COOL;
1385 ecrec64_this_entries
1386 = makeint64(&byterec[NUM_ENTRIES_CEN_DIR_THS_DISK64]);
1387 if ( (G.ecrec.num_entries_centrl_dir_ths_disk != 0xFFFF) &&
1388 (G.ecrec.num_entries_centrl_dir_ths_disk != ecrec64_this_entries) )
1389 return PK_COOL;
1390 ecrec64_tot_entries
1391 = makeint64(&byterec[TOTAL_ENTRIES_CENTRAL_DIR64]);
1392 if ( (G.ecrec.total_entries_central_dir != 0xFFFF) &&
1393 (G.ecrec.total_entries_central_dir != ecrec64_tot_entries) )
1394 return PK_COOL;
1395 ecrec64_cdirsize
1396 = makeint64(&byterec[SIZE_CENTRAL_DIRECTORY64]);
1397 if ( (G.ecrec.size_central_directory != 0xFFFFFFFFL) &&
1398 (G.ecrec.size_central_directory != ecrec64_cdirsize) )
1399 return PK_COOL;
1400 ecrec64_offs_cdstart
1401 = makeint64(&byterec[OFFSET_START_CENTRAL_DIRECT64]);
1402 if ( (G.ecrec.offset_start_central_directory != 0xFFFFFFFFL) &&
1403 (G.ecrec.offset_start_central_directory != ecrec64_offs_cdstart) )
1404 return PK_COOL;
1406 /* Now, we are (almost) sure that we have a Zip64 archive. */
1407 G.ecrec.have_ecr64 = 1;
1409 /* Update the "end-of-central-dir offset" for later checks. */
1410 G.real_ecrec_offset = ecrec64_start_offset;
1412 /* Update all ecdir_rec data that are flagged to be invalid
1413 in Zip64 mode. Set the ecrec64-mandatory flag when such a
1414 case is found. */
1415 if (G.ecrec.number_this_disk == 0xFFFF) {
1416 G.ecrec.number_this_disk = ecrec64_start_disk;
1417 if (ecrec64_start_disk != 0xFFFF) G.ecrec.is_zip64_archive = TRUE;
1419 if (G.ecrec.num_disk_start_cdir == 0xFFFF) {
1420 G.ecrec.num_disk_start_cdir = ecrec64_disk_cdstart;
1421 if (ecrec64_disk_cdstart != 0xFFFF) G.ecrec.is_zip64_archive = TRUE;
1423 if (G.ecrec.num_entries_centrl_dir_ths_disk == 0xFFFF) {
1424 G.ecrec.num_entries_centrl_dir_ths_disk = ecrec64_this_entries;
1425 if (ecrec64_this_entries != 0xFFFF) G.ecrec.is_zip64_archive = TRUE;
1427 if (G.ecrec.total_entries_central_dir == 0xFFFF) {
1428 G.ecrec.total_entries_central_dir = ecrec64_tot_entries;
1429 if (ecrec64_tot_entries != 0xFFFF) G.ecrec.is_zip64_archive = TRUE;
1431 if (G.ecrec.size_central_directory == 0xFFFFFFFFL) {
1432 G.ecrec.size_central_directory = ecrec64_cdirsize;
1433 if (ecrec64_cdirsize != 0xFFFFFFFF) G.ecrec.is_zip64_archive = TRUE;
1435 if (G.ecrec.offset_start_central_directory == 0xFFFFFFFFL) {
1436 G.ecrec.offset_start_central_directory = ecrec64_offs_cdstart;
1437 if (ecrec64_offs_cdstart != 0xFFFFFFFF) G.ecrec.is_zip64_archive = TRUE;
1440 return PK_COOL;
1441 } /* end function find_ecrec64() */
1445 /*************************/
1446 /* Function find_ecrec() */
1447 /*************************/
1449 static int find_ecrec(__G__ searchlen) /* return PK-class error */
1450 __GDEF
1451 zoff_t searchlen;
1453 int found = FALSE;
1454 int error_in_archive;
1455 int result;
1456 ec_byte_rec byterec;
1458 /*---------------------------------------------------------------------------
1459 Treat case of short zipfile separately.
1460 ---------------------------------------------------------------------------*/
1462 if (G.ziplen <= INBUFSIZ) {
1463 #ifdef USE_STRM_INPUT
1464 zfseeko(G.zipfd, 0L, SEEK_SET);
1465 #else /* !USE_STRM_INPUT */
1466 zlseek(G.zipfd, 0L, SEEK_SET);
1467 #endif /* ?USE_STRM_INPUT */
1468 if ((G.incnt = read(G.zipfd,(char *)G.inbuf,(unsigned int)G.ziplen))
1469 == (int)G.ziplen)
1471 /* 'P' must be at least (ECREC_SIZE+4) bytes from end of zipfile */
1472 for (G.inptr = G.inbuf+(int)G.ziplen-(ECREC_SIZE+4);
1473 G.inptr >= G.inbuf;
1474 --G.inptr) {
1475 if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */
1476 !memcmp((char *)G.inptr, end_central_sig, 4)) {
1477 G.incnt -= (int)(G.inptr - G.inbuf);
1478 found = TRUE;
1479 break;
1483 /*---------------------------------------------------------------------------
1484 Zipfile is longer than INBUFSIZ:
1486 MB - this next block of code moved to rec_find so that same code can be
1487 used to look for zip64 ec record. No need to include code above since
1488 a zip64 ec record will only be looked for if it is a BIG file.
1489 ---------------------------------------------------------------------------*/
1491 } else {
1492 found =
1493 (rec_find(__G__ searchlen, end_central_sig, ECREC_SIZE) == 0
1494 ? TRUE : FALSE);
1495 } /* end if (ziplen > INBUFSIZ) */
1497 /*---------------------------------------------------------------------------
1498 Searched through whole region where signature should be without finding
1499 it. Print informational message and die a horrible death.
1500 ---------------------------------------------------------------------------*/
1502 if (!found) {
1503 if (uO.qflag || uO.zipinfo_mode)
1504 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
1505 Info(slide, 0x401, ((char *)slide,
1506 LoadFarString(CentDirEndSigNotFound)));
1507 return PK_ERR; /* failed */
1510 /*---------------------------------------------------------------------------
1511 Found the signature, so get the end-central data before returning. Do
1512 any necessary machine-type conversions (byte ordering, structure padding
1513 compensation) by reading data into character array and copying to struct.
1514 ---------------------------------------------------------------------------*/
1516 G.real_ecrec_offset = G.cur_zipfile_bufstart + (G.inptr-G.inbuf);
1517 #ifdef TEST
1518 printf("\n found end-of-central-dir signature at offset %s (%sh)\n",
1519 FmZofft(G.real_ecrec_offset, NULL, NULL),
1520 FmZofft(G.real_ecrec_offset, FZOFFT_HEX_DOT_WID, "X"));
1521 printf(" from beginning of file; offset %d (%.4Xh) within block\n",
1522 G.inptr-G.inbuf, G.inptr-G.inbuf);
1523 #endif
1525 if (readbuf(__G__ (char *)byterec, ECREC_SIZE+4) == 0)
1526 return PK_EOF;
1528 G.ecrec.number_this_disk =
1529 makeword(&byterec[NUMBER_THIS_DISK]);
1530 G.ecrec.num_disk_start_cdir =
1531 makeword(&byterec[NUM_DISK_WITH_START_CEN_DIR]);
1532 G.ecrec.num_entries_centrl_dir_ths_disk =
1533 makeword(&byterec[NUM_ENTRIES_CEN_DIR_THS_DISK]);
1534 G.ecrec.total_entries_central_dir =
1535 makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]);
1536 G.ecrec.size_central_directory =
1537 makelong(&byterec[SIZE_CENTRAL_DIRECTORY]);
1538 G.ecrec.offset_start_central_directory =
1539 makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
1540 G.ecrec.zipfile_comment_length =
1541 makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
1543 /* Now, we have to read the archive comment, BEFORE the file pointer
1544 is moved away backwards to seek for a Zip64 ECLOC64 structure.
1546 if ( (error_in_archive = process_zip_cmmnt(__G)) > PK_WARN )
1547 return error_in_archive;
1549 /* Next: Check for existence of Zip64 end-of-cent-dir locator
1550 ECLOC64. This structure must reside on the same volume as the
1551 classic ECREC, at exactly (ECLOC64_SIZE+4) bytes in front
1552 of the ECREC.
1553 The ECLOC64 structure directs to the longer ECREC64 structure
1554 A ECREC64 will ALWAYS exist for a proper Zip64 archive, as
1555 the "Version Needed To Extract" field is required to be set
1556 to 4.5 or higher whenever any Zip64 features are used anywhere
1557 in the archive, so just check for that to see if this is a
1558 Zip64 archive.
1560 result = find_ecrec64(__G__ searchlen+76);
1561 /* 76 bytes for zip64ec & zip64 locator */
1562 if (result != PK_COOL) {
1563 if (error_in_archive < result)
1564 error_in_archive = result;
1565 return error_in_archive;
1568 G.expect_ecrec_offset = G.ecrec.offset_start_central_directory +
1569 G.ecrec.size_central_directory;
1571 #ifndef NO_ZIPINFO
1572 if (uO.zipinfo_mode) {
1573 /* In ZipInfo mode, additional info about the data found in the
1574 end-of-central-directory areas is printed out.
1576 zi_end_central(__G);
1578 #endif
1580 return error_in_archive;
1582 } /* end function find_ecrec() */
1588 /********************************/
1589 /* Function process_zip_cmmnt() */
1590 /********************************/
1592 static int process_zip_cmmnt(__G) /* return PK-type error code */
1593 __GDEF
1595 int error = PK_COOL;
1598 /*---------------------------------------------------------------------------
1599 Get the zipfile comment (up to 64KB long), if any, and print it out.
1600 ---------------------------------------------------------------------------*/
1602 #ifdef WINDLL
1603 /* for comment button: */
1604 if ((!G.fValidate) && (G.lpUserFunctions != NULL))
1605 G.lpUserFunctions->cchComment = G.ecrec.zipfile_comment_length;
1606 #endif /* WINDLL */
1608 #ifndef NO_ZIPINFO
1609 /* ZipInfo, verbose format */
1610 if (uO.zipinfo_mode && uO.lflag > 9) {
1611 /*-------------------------------------------------------------------
1612 Get the zipfile comment, if any, and print it out.
1613 (Comment may be up to 64KB long. May the fleas of a thousand
1614 camels infest the arm-pits of anyone who actually takes advantage
1615 of this fact.)
1616 -------------------------------------------------------------------*/
1618 if (!G.ecrec.zipfile_comment_length)
1619 Info(slide, 0, ((char *)slide, LoadFarString(NoZipfileComment)));
1620 else {
1621 Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommentDesc),
1622 G.ecrec.zipfile_comment_length));
1623 Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommBegin)));
1624 if (do_string(__G__ G.ecrec.zipfile_comment_length, DISPLAY))
1625 error = PK_WARN;
1626 Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommEnd)));
1627 if (error)
1628 Info(slide, 0, ((char *)slide,
1629 LoadFarString(ZipfileCommTrunc2)));
1630 } /* endif (comment exists) */
1632 /* ZipInfo, non-verbose mode: print zipfile comment only if requested */
1633 } else if (G.ecrec.zipfile_comment_length &&
1634 (uO.zflag > 0) && uO.zipinfo_mode) {
1635 if (do_string(__G__ G.ecrec.zipfile_comment_length, DISPLAY)) {
1636 Info(slide, 0x401, ((char *)slide,
1637 LoadFarString(ZipfileCommTrunc1)));
1638 error = PK_WARN;
1640 } else
1641 #endif /* !NO_ZIPINFO */
1642 if ( G.ecrec.zipfile_comment_length &&
1643 (uO.zflag > 0
1644 #ifndef WINDLL
1645 || (uO.zflag == 0
1646 # ifndef NO_ZIPINFO
1647 && !uO.zipinfo_mode
1648 # endif
1649 # ifdef TIMESTAMP
1650 && !uO.T_flag
1651 # endif
1652 && !uO.qflag)
1653 #endif /* !WINDLL */
1656 if (do_string(__G__ G.ecrec.zipfile_comment_length,
1657 #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN))
1658 # ifndef NO_ZIPINFO
1659 (oU.zipinfo_mode ? DISPLAY : CHECK_AUTORUN)
1660 # else
1661 CHECK_AUTORUN
1662 # endif
1663 #else
1664 DISPLAY
1665 #endif
1668 Info(slide, 0x401, ((char *)slide,
1669 LoadFarString(ZipfileCommTrunc1)));
1670 error = PK_WARN;
1673 #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN))
1674 else if (G.ecrec.zipfile_comment_length) {
1675 if (do_string(__G__ G.ecrec.zipfile_comment_length, CHECK_AUTORUN_Q))
1677 Info(slide, 0x401, ((char *)slide,
1678 LoadFarString(ZipfileCommTrunc1)));
1679 error = PK_WARN;
1682 #endif
1683 return error;
1685 } /* end function process_zip_cmmnt() */
1691 /************************************/
1692 /* Function process_cdir_file_hdr() */
1693 /************************************/
1695 int process_cdir_file_hdr(__G) /* return PK-type error code */
1696 __GDEF
1698 int error;
1701 /*---------------------------------------------------------------------------
1702 Get central directory info, save host and method numbers, and set flag
1703 for lowercase conversion of filename, depending on the OS from which the
1704 file is coming.
1705 ---------------------------------------------------------------------------*/
1707 if ((error = get_cdir_ent(__G)) != 0)
1708 return error;
1710 G.pInfo->hostver = G.crec.version_made_by[0];
1711 G.pInfo->hostnum = MIN(G.crec.version_made_by[1], NUM_HOSTS);
1712 /* extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */
1714 G.pInfo->lcflag = 0;
1715 if (uO.L_flag == 1) /* name conversion for monocase systems */
1716 switch (G.pInfo->hostnum) {
1717 case FS_FAT_: /* PKZIP and zip -k store in uppercase */
1718 case CPM_: /* like MS-DOS, right? */
1719 case VM_CMS_: /* all caps? */
1720 case MVS_: /* all caps? */
1721 case TANDEM_:
1722 case TOPS20_:
1723 case VMS_: /* our Zip uses lowercase, but ASi's doesn't */
1724 /* case Z_SYSTEM_: ? */
1725 /* case QDOS_: ? */
1726 G.pInfo->lcflag = 1; /* convert filename to lowercase */
1727 break;
1729 default: /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, ATARI_, */
1730 break; /* FS_VFAT_, ATHEOS_, BEOS_ (Z_SYSTEM_), THEOS_: */
1731 /* no conversion */
1733 else if (uO.L_flag > 1) /* let -LL force lower case for all names */
1734 G.pInfo->lcflag = 1;
1736 /* do Amigas (AMIGA_) also have volume labels? */
1737 if (IS_VOLID(G.crec.external_file_attributes) &&
1738 (G.pInfo->hostnum == FS_FAT_ || G.pInfo->hostnum == FS_HPFS_ ||
1739 G.pInfo->hostnum == FS_NTFS_ || G.pInfo->hostnum == ATARI_))
1741 G.pInfo->vollabel = TRUE;
1742 G.pInfo->lcflag = 0; /* preserve case of volume labels */
1743 } else
1744 G.pInfo->vollabel = FALSE;
1746 /* this flag is needed to detect archives made by "PKZIP for Unix" when
1747 deciding which kind of codepage conversion has to be applied to
1748 strings (see do_string() function in fileio.c) */
1749 G.pInfo->HasUxAtt = (G.crec.external_file_attributes & 0xffff0000L) != 0L;
1751 #ifdef UNICODE_SUPPORT
1752 /* remember the state of GPB11 (General Purpuse Bit 11) which indicates
1753 that the standard path and comment are UTF-8. */
1754 G.pInfo->GPFIsUTF8
1755 = (G.crec.general_purpose_bit_flag & (1 << 11)) == (1 << 11);
1756 #endif
1758 return PK_COOL;
1760 } /* end function process_cdir_file_hdr() */
1766 /***************************/
1767 /* Function get_cdir_ent() */
1768 /***************************/
1770 static int get_cdir_ent(__G) /* return PK-type error code */
1771 __GDEF
1773 cdir_byte_hdr byterec;
1776 /*---------------------------------------------------------------------------
1777 Read the next central directory entry and do any necessary machine-type
1778 conversions (byte ordering, structure padding compensation--do so by
1779 copying the data from the array into which it was read (byterec) to the
1780 usable struct (crec)).
1781 ---------------------------------------------------------------------------*/
1783 if (readbuf(__G__ (char *)byterec, CREC_SIZE) == 0)
1784 return PK_EOF;
1786 G.crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0];
1787 G.crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1];
1788 G.crec.version_needed_to_extract[0] =
1789 byterec[C_VERSION_NEEDED_TO_EXTRACT_0];
1790 G.crec.version_needed_to_extract[1] =
1791 byterec[C_VERSION_NEEDED_TO_EXTRACT_1];
1793 G.crec.general_purpose_bit_flag =
1794 makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]);
1795 G.crec.compression_method =
1796 makeword(&byterec[C_COMPRESSION_METHOD]);
1797 G.crec.last_mod_dos_datetime =
1798 makelong(&byterec[C_LAST_MOD_DOS_DATETIME]);
1799 G.crec.crc32 =
1800 makelong(&byterec[C_CRC32]);
1801 G.crec.csize =
1802 makelong(&byterec[C_COMPRESSED_SIZE]);
1803 G.crec.ucsize =
1804 makelong(&byterec[C_UNCOMPRESSED_SIZE]);
1805 G.crec.filename_length =
1806 makeword(&byterec[C_FILENAME_LENGTH]);
1807 G.crec.extra_field_length =
1808 makeword(&byterec[C_EXTRA_FIELD_LENGTH]);
1809 G.crec.file_comment_length =
1810 makeword(&byterec[C_FILE_COMMENT_LENGTH]);
1811 G.crec.disk_number_start =
1812 makeword(&byterec[C_DISK_NUMBER_START]);
1813 G.crec.internal_file_attributes =
1814 makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]);
1815 G.crec.external_file_attributes =
1816 makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]); /* LONG, not word! */
1817 G.crec.relative_offset_local_header =
1818 makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]);
1820 return PK_COOL;
1822 } /* end function get_cdir_ent() */
1828 /*************************************/
1829 /* Function process_local_file_hdr() */
1830 /*************************************/
1832 int process_local_file_hdr(__G) /* return PK-type error code */
1833 __GDEF
1835 local_byte_hdr byterec;
1838 /*---------------------------------------------------------------------------
1839 Read the next local file header and do any necessary machine-type con-
1840 versions (byte ordering, structure padding compensation--do so by copy-
1841 ing the data from the array into which it was read (byterec) to the
1842 usable struct (lrec)).
1843 ---------------------------------------------------------------------------*/
1845 if (readbuf(__G__ (char *)byterec, LREC_SIZE) == 0)
1846 return PK_EOF;
1848 G.lrec.version_needed_to_extract[0] =
1849 byterec[L_VERSION_NEEDED_TO_EXTRACT_0];
1850 G.lrec.version_needed_to_extract[1] =
1851 byterec[L_VERSION_NEEDED_TO_EXTRACT_1];
1853 G.lrec.general_purpose_bit_flag =
1854 makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]);
1855 G.lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]);
1856 G.lrec.last_mod_dos_datetime = makelong(&byterec[L_LAST_MOD_DOS_DATETIME]);
1857 G.lrec.crc32 = makelong(&byterec[L_CRC32]);
1858 G.lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]);
1859 G.lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]);
1860 G.lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]);
1861 G.lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]);
1863 if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
1864 /* can't trust local header, use central directory: */
1865 G.lrec.crc32 = G.pInfo->crc;
1866 G.lrec.csize = G.pInfo->compr_size;
1867 G.lrec.ucsize = G.pInfo->uncompr_size;
1870 G.csize = G.lrec.csize;
1872 return PK_COOL;
1874 } /* end function process_local_file_hdr() */
1877 /*******************************/
1878 /* Function getZip64Data() */
1879 /*******************************/
1881 int getZip64Data(__G__ ef_buf, ef_len)
1882 __GDEF
1883 ZCONST uch *ef_buf; /* buffer containing extra field */
1884 unsigned ef_len; /* total length of extra field */
1886 unsigned eb_id;
1887 unsigned eb_len;
1889 /*---------------------------------------------------------------------------
1890 This function scans the extra field for zip64 information, ie 8-byte
1891 versions of compressed file size, uncompressed file size, relative offset
1892 and a 4-byte version of disk start number.
1893 Sets both local header and central header fields. Not terribly clever,
1894 but it means that this procedure is only called in one place.
1895 ---------------------------------------------------------------------------*/
1897 if (ef_len == 0 || ef_buf == NULL)
1898 return PK_COOL;
1900 Trace((stderr,"\ngetZip64Data: scanning extra field of length %u\n",
1901 ef_len));
1903 while (ef_len >= EB_HEADSIZE) {
1904 eb_id = makeword(EB_ID + ef_buf);
1905 eb_len = makeword(EB_LEN + ef_buf);
1907 if (eb_len > (ef_len - EB_HEADSIZE)) {
1908 /* discovered some extra field inconsistency! */
1909 Trace((stderr,
1910 "getZip64Data: block length %u > rest ef_size %u\n", eb_len,
1911 ef_len - EB_HEADSIZE));
1912 break;
1914 if (eb_id == EF_PKSZ64) {
1916 int offset = EB_HEADSIZE;
1918 if (G.crec.ucsize == 0xffffffff || G.lrec.ucsize == 0xffffffff){
1919 G.lrec.ucsize = G.crec.ucsize = makeint64(offset + ef_buf);
1920 offset += sizeof(G.crec.ucsize);
1922 if (G.crec.csize == 0xffffffff || G.lrec.csize == 0xffffffff){
1923 G.csize = G.lrec.csize = G.crec.csize = makeint64(offset + ef_buf);
1924 offset += sizeof(G.crec.csize);
1926 if (G.crec.relative_offset_local_header == 0xffffffff){
1927 G.crec.relative_offset_local_header = makeint64(offset + ef_buf);
1928 offset += sizeof(G.crec.relative_offset_local_header);
1930 if (G.crec.disk_number_start == 0xffff){
1931 G.crec.disk_number_start = (zuvl_t)makelong(offset + ef_buf);
1932 offset += sizeof(G.crec.disk_number_start);
1936 /* Skip this extra field block */
1937 ef_buf += (eb_len + EB_HEADSIZE);
1938 ef_len -= (eb_len + EB_HEADSIZE);
1941 return PK_COOL;
1942 } /* end function getZip64Data() */
1945 #ifdef UNICODE_SUPPORT
1947 /*******************************/
1948 /* Function getUnicodeData() */
1949 /*******************************/
1951 int getUnicodeData(__G__ ef_buf, ef_len)
1952 __GDEF
1953 ZCONST uch *ef_buf; /* buffer containing extra field */
1954 unsigned ef_len; /* total length of extra field */
1956 unsigned eb_id;
1957 unsigned eb_len;
1959 /*---------------------------------------------------------------------------
1960 This function scans the extra field for Unicode information, ie UTF-8
1961 path extra fields.
1963 On return, G.unipath_filename =
1964 NULL, if no Unicode path extra field or error
1965 "", if the standard path is UTF-8 (free when done)
1966 null-terminated UTF-8 path (free when done)
1967 Return PK_COOL if no error.
1968 ---------------------------------------------------------------------------*/
1970 G.unipath_filename = NULL;
1972 if (ef_len == 0 || ef_buf == NULL)
1973 return PK_COOL;
1975 Trace((stderr,"\ngetUnicodeData: scanning extra field of length %u\n",
1976 ef_len));
1978 while (ef_len >= EB_HEADSIZE) {
1979 eb_id = makeword(EB_ID + ef_buf);
1980 eb_len = makeword(EB_LEN + ef_buf);
1982 if (eb_len > (ef_len - EB_HEADSIZE)) {
1983 /* discovered some extra field inconsistency! */
1984 Trace((stderr,
1985 "getUnicodeData: block length %u > rest ef_size %u\n", eb_len,
1986 ef_len - EB_HEADSIZE));
1987 break;
1989 if (eb_id == EF_UNIPATH) {
1991 int offset = EB_HEADSIZE;
1992 ush ULen = eb_len - 5;
1993 ulg chksum = CRCVAL_INITIAL;
1995 /* version */
1996 G.unipath_version = (uch) *(offset + ef_buf);
1997 offset += 1;
1998 if (G.unipath_version > 1) {
1999 /* can do only version 1 */
2000 Info(slide, 0x401, ((char *)slide,
2001 LoadFarString(UnicodeVersionError)));
2002 return PK_ERR;
2005 /* filename CRC */
2006 G.unipath_checksum = makelong(offset + ef_buf);
2007 offset += 4;
2010 * Compute 32-bit crc
2013 chksum = crc32(chksum, (uch *)(G.filename_full),
2014 strlen(G.filename_full));
2016 /* If the checksums's don't match then likely filename has been
2017 * modified and the Unicode Path is no longer valid.
2019 if (chksum != G.unipath_checksum) {
2020 Info(slide, 0x401, ((char *)slide,
2021 LoadFarString(UnicodeMismatchError)));
2022 if (G.unicode_mismatch == 1) {
2023 /* warn and continue */
2024 } else if (G.unicode_mismatch == 2) {
2025 /* ignore and continue */
2026 } else if (G.unicode_mismatch == 0) {
2028 return PK_ERR;
2031 /* UTF-8 Path */
2032 if ((G.unipath_filename = malloc(ULen + 1)) == NULL) {
2033 return PK_ERR;
2035 if (ULen == 0) {
2036 /* standard path is UTF-8 so use that */
2037 G.unipath_filename[0] = '\0';
2038 } else {
2039 /* UTF-8 path */
2040 strncpy(G.unipath_filename,
2041 (ZCONST char *)(offset + ef_buf), ULen);
2042 G.unipath_filename[ULen] = '\0';
2046 /* Skip this extra field block */
2047 ef_buf += (eb_len + EB_HEADSIZE);
2048 ef_len -= (eb_len + EB_HEADSIZE);
2051 return PK_COOL;
2052 } /* end function getUnicodeData() */
2057 #ifdef UNICODE_WCHAR
2058 /*---------------------------------------------
2059 * Unicode conversion functions
2061 * Based on functions provided by Paul Kienitz
2063 *---------------------------------------------
2067 NOTES APPLICABLE TO ALL STRING FUNCTIONS:
2069 All of the x_to_y functions take parameters for an output buffer and
2070 its available length, and return an int. The value returned is the
2071 length of the string that the input produces, which may be larger than
2072 the provided buffer length. If the returned value is less than the
2073 buffer length, then the contents of the buffer will be null-terminated;
2074 otherwise, it will not be terminated and may be invalid, possibly
2075 stopping in the middle of a multibyte sequence.
2077 In all cases you may pass NULL as the buffer and/or 0 as the length, if
2078 you just want to learn how much space the string is going to require.
2080 The functions will return -1 if the input is invalid UTF-8 or cannot be
2081 encoded as UTF-8.
2084 static int utf8_char_bytes OF((ZCONST char *utf8));
2085 static ulg ucs4_char_from_utf8 OF((ZCONST char **utf8));
2086 static int utf8_to_ucs4_string OF((ZCONST char *utf8, ulg *ucs4buf,
2087 int buflen));
2089 /* utility functions for managing UTF-8 and UCS-4 strings */
2092 /* utf8_char_bytes
2094 * Returns the number of bytes used by the first character in a UTF-8
2095 * string, or -1 if the UTF-8 is invalid or null.
2097 static int utf8_char_bytes(utf8)
2098 ZCONST char *utf8;
2100 int t, r;
2101 unsigned lead;
2103 if (!utf8)
2104 return -1; /* no input */
2105 lead = (unsigned char) *utf8;
2106 if (lead < 0x80)
2107 r = 1; /* an ascii-7 character */
2108 else if (lead < 0xC0)
2109 return -1; /* error: trailing byte without lead byte */
2110 else if (lead < 0xE0)
2111 r = 2; /* an 11 bit character */
2112 else if (lead < 0xF0)
2113 r = 3; /* a 16 bit character */
2114 else if (lead < 0xF8)
2115 r = 4; /* a 21 bit character (the most currently used) */
2116 else if (lead < 0xFC)
2117 r = 5; /* a 26 bit character (shouldn't happen) */
2118 else if (lead < 0xFE)
2119 r = 6; /* a 31 bit character (shouldn't happen) */
2120 else
2121 return -1; /* error: invalid lead byte */
2122 for (t = 1; t < r; t++)
2123 if ((unsigned char) utf8[t] < 0x80 || (unsigned char) utf8[t] >= 0xC0)
2124 return -1; /* error: not enough valid trailing bytes */
2125 return r;
2129 /* ucs4_char_from_utf8
2131 * Given a reference to a pointer into a UTF-8 string, returns the next
2132 * UCS-4 character and advances the pointer to the next character sequence.
2133 * Returns ~0 (= -1 in twos-complement notation) and does not advance the
2134 * pointer when input is ill-formed.
2136 static ulg ucs4_char_from_utf8(utf8)
2137 ZCONST char **utf8;
2139 ulg ret;
2140 int t, bytes;
2142 if (!utf8)
2143 return ~0L; /* no input */
2144 bytes = utf8_char_bytes(*utf8);
2145 if (bytes <= 0)
2146 return ~0L; /* invalid input */
2147 if (bytes == 1)
2148 ret = **utf8; /* ascii-7 */
2149 else
2150 ret = **utf8 & (0x7F >> bytes); /* lead byte of a multibyte sequence */
2151 (*utf8)++;
2152 for (t = 1; t < bytes; t++) /* consume trailing bytes */
2153 ret = (ret << 6) | (*((*utf8)++) & 0x3F);
2154 return (zwchar) ret;
2158 #if 0 /* currently unused */
2159 /* utf8_from_ucs4_char - Convert UCS char to UTF-8
2161 * Returns the number of bytes put into utf8buf to represent ch, from 1 to 6,
2162 * or -1 if ch is too large to represent. utf8buf must have room for 6 bytes.
2164 static int utf8_from_ucs4_char(utf8buf, ch)
2165 char *utf8buf;
2166 ulg ch;
2168 int trailing = 0;
2169 int leadmask = 0x80;
2170 int leadbits = 0x3F;
2171 int tch = ch;
2172 int ret;
2174 if (ch > 0x7FFFFFFFL)
2175 return -1; /* UTF-8 can represent 31 bits */
2176 if (ch < 0x7F)
2178 *utf8buf++ = (char) ch; /* ascii-7 */
2179 return 1;
2181 do {
2182 trailing++;
2183 leadmask = (leadmask >> 1) | 0x80;
2184 leadbits >>= 1;
2185 tch >>= 6;
2186 } while (tch & ~leadbits);
2187 ret = trailing + 1;
2188 /* produce lead byte */
2189 *utf8buf++ = (char) (leadmask | (ch >> (6 * trailing)));
2190 while (--trailing >= 0)
2191 /* produce trailing bytes */
2192 *utf8buf++ = (char) (0x80 | ((ch >> (6 * trailing)) & 0x3F));
2193 return ret;
2195 #endif /* unused */
2198 /*===================================================================*/
2200 /* utf8_to_ucs4_string - convert UTF-8 string to UCS string
2202 * Return UCS count. Now returns int so can return -1.
2204 static int utf8_to_ucs4_string(utf8, ucs4buf, buflen)
2205 ZCONST char *utf8;
2206 ulg *ucs4buf;
2207 int buflen;
2209 int count = 0;
2211 for (;;)
2213 ulg ch = ucs4_char_from_utf8(&utf8);
2214 if (ch == ~0L)
2215 return -1;
2216 else
2218 if (ucs4buf && count < buflen)
2219 ucs4buf[count] = ch;
2220 if (ch == 0)
2221 return count;
2222 count++;
2228 #if 0 /* currently unused */
2229 /* ucs4_string_to_utf8
2233 static int ucs4_string_to_utf8(ucs4, utf8buf, buflen)
2234 ZCONST ulg *ucs4;
2235 char *utf8buf;
2236 int buflen;
2238 char mb[6];
2239 int count = 0;
2241 if (!ucs4)
2242 return -1;
2243 for (;;)
2245 int mbl = utf8_from_ucs4_char(mb, *ucs4++);
2246 int c;
2247 if (mbl <= 0)
2248 return -1;
2249 /* We could optimize this a bit by passing utf8buf + count */
2250 /* directly to utf8_from_ucs4_char when buflen >= count + 6... */
2251 c = buflen - count;
2252 if (mbl < c)
2253 c = mbl;
2254 if (utf8buf && count < buflen)
2255 strncpy(utf8buf + count, mb, c);
2256 if (mbl == 1 && !mb[0])
2257 return count; /* terminating nul */
2258 count += mbl;
2263 /* utf8_chars
2265 * Wrapper: counts the actual unicode characters in a UTF-8 string.
2267 static int utf8_chars(utf8)
2268 ZCONST char *utf8;
2270 return utf8_to_ucs4_string(utf8, NULL, 0);
2272 #endif /* unused */
2274 /* --------------------------------------------------- */
2275 /* Unicode Support
2277 * These functions common for all Unicode ports.
2279 * These functions should allocate and return strings that can be
2280 * freed with free().
2282 * 8/27/05 EG
2284 * Use zwchar for wide char which is unsigned long
2285 * in zip.h and 32 bits. This avoids problems with
2286 * different sizes of wchar_t.
2289 #if 0 /* currently unused */
2290 /* is_ascii_string
2291 * Checks if a string is all ascii
2293 int is_ascii_string(mbstring)
2294 ZCONST char *mbstring;
2296 char *p;
2297 uch c;
2299 for (p = mbstring; c = (uch)*p; p++) {
2300 if (c > 0x7F) {
2301 return 0;
2304 return 1;
2307 /* local to UTF-8 */
2308 char *local_to_utf8_string(local_string)
2309 ZCONST char *local_string;
2311 return wide_to_utf8_string(local_to_wide_string(local_string));
2313 # endif /* unused */
2315 /* wide_to_escape_string
2316 provides a string that represents a wide char not in local char set
2318 An initial try at an algorithm. Suggestions welcome.
2320 According to the standard, Unicode character points are restricted to
2321 the number range from 0 to 0x10FFFF, respective 21 bits.
2322 For a hexadecimal notation, 2 octets are sufficient for the mostly
2323 used characters from the "Basic Multilingual Plane", all other
2324 Unicode characters can be represented by 3 octets (= 6 hex digits).
2325 The Unicode standard suggests to write Unicode character points
2326 as 4 resp. 6 hex digits, preprended by "U+".
2327 (e.g.: U+10FFFF for the highest character point, or U+0030 for the ASCII
2328 digit "0")
2330 However, for the purpose of escaping non-ASCII chars in an ASCII character
2331 stream, the "U" is not a very good escape initializer. Therefore, we
2332 use the following convention within our Info-ZIP code:
2334 If not an ASCII char probably need 2 bytes at least. So if
2335 a 2-byte wide encode it as 4 hex digits with a leading #U. If
2336 needs 3 bytes then prefix the string with #L. So
2337 #U1234
2338 is a 2-byte wide character with bytes 0x12 and 0x34 while
2339 #L123456
2340 is a 3-byte wide character with bytes 0x12, 0x34, 0x56.
2341 On Windows, wide that need two wide characters need to be converted
2342 to a single number.
2345 /* set this to the max bytes an escape can be */
2346 #define MAX_ESCAPE_BYTES 8
2348 char *wide_to_escape_string(wide_char)
2349 zwchar wide_char;
2351 int i;
2352 zwchar w = wide_char;
2353 uch b[sizeof(zwchar)];
2354 char d[3];
2355 char e[11];
2356 int len;
2357 char *r;
2359 /* fill byte array with zeros */
2360 memzero(b, sizeof(zwchar));
2361 /* get bytes in right to left order */
2362 for (len = 0; w; len++) {
2363 b[len] = (char)(w % 0x100);
2364 w /= 0x100;
2366 strcpy(e, "#");
2367 /* either 2 bytes or 3 bytes */
2368 if (len <= 2) {
2369 len = 2;
2370 strcat(e, "U");
2371 } else {
2372 strcat(e, "L");
2374 for (i = len - 1; i >= 0; i--) {
2375 sprintf(d, "%02x", b[i]);
2376 strcat(e, d);
2378 if ((r = malloc(strlen(e) + 1)) == NULL) {
2379 return NULL;
2381 strcpy(r, e);
2382 return r;
2385 #if 0 /* currently unused */
2386 /* returns the wide character represented by the escape string */
2387 zwchar escape_string_to_wide(escape_string)
2388 ZCONST char *escape_string;
2390 int i;
2391 zwchar w;
2392 char c;
2393 int len;
2394 ZCONST char *e = escape_string;
2396 if (e == NULL) {
2397 return 0;
2399 if (e[0] != '#') {
2400 /* no leading # */
2401 return 0;
2403 len = strlen(e);
2404 /* either #U1234 or #L123456 format */
2405 if (len != 6 && len != 8) {
2406 return 0;
2408 w = 0;
2409 if (e[1] == 'L') {
2410 if (len != 8) {
2411 return 0;
2413 /* 3 bytes */
2414 for (i = 2; i < 8; i++) {
2415 c = e[i];
2416 if (c < '0' || c > '9') {
2417 return 0;
2419 w = w * 0x10 + (zwchar)(c - '0');
2421 } else if (e[1] == 'U') {
2422 /* 2 bytes */
2423 for (i = 2; i < 6; i++) {
2424 c = e[i];
2425 if (c < '0' || c > '9') {
2426 return 0;
2428 w = w * 0x10 + (zwchar)(c - '0');
2431 return w;
2433 #endif /* unused */
2435 #ifndef WIN32 /* WIN32 supplies a special variant of this function */
2436 /* convert wide character string to multi-byte character string */
2437 char *wide_to_local_string(wide_string, escape_all)
2438 ZCONST zwchar *wide_string;
2439 int escape_all;
2441 int i;
2442 wchar_t wc;
2443 int b;
2444 int state_dependent;
2445 int wsize = 0;
2446 int max_bytes = MB_CUR_MAX;
2447 char buf[9];
2448 char *buffer = NULL;
2449 char *local_string = NULL;
2451 for (wsize = 0; wide_string[wsize]; wsize++) ;
2453 if (max_bytes < MAX_ESCAPE_BYTES)
2454 max_bytes = MAX_ESCAPE_BYTES;
2456 if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
2457 return NULL;
2460 /* convert it */
2461 buffer[0] = '\0';
2462 /* set initial state if state-dependent encoding */
2463 wc = (wchar_t)'a';
2464 b = wctomb(NULL, wc);
2465 if (b == 0)
2466 state_dependent = 0;
2467 else
2468 state_dependent = 1;
2469 for (i = 0; i < wsize; i++) {
2470 if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) {
2471 /* wchar_t probably 2 bytes */
2472 /* could do surrogates if state_dependent and wctomb can do */
2473 wc = zwchar_to_wchar_t_default_char;
2474 } else {
2475 wc = (wchar_t)wide_string[i];
2477 b = wctomb(buf, wc);
2478 if (escape_all) {
2479 if (b == 1 && (uch)buf[0] <= 0x7f) {
2480 /* ASCII */
2481 strncat(buffer, buf, b);
2482 } else {
2483 /* use escape for wide character */
2484 char *escape_string = wide_to_escape_string(wide_string[i]);
2485 strcat(buffer, escape_string);
2486 free(escape_string);
2488 } else if (b > 0) {
2489 /* multi-byte char */
2490 strncat(buffer, buf, b);
2491 } else {
2492 /* no MB for this wide */
2493 /* use escape for wide character */
2494 char *escape_string = wide_to_escape_string(wide_string[i]);
2495 strcat(buffer, escape_string);
2496 free(escape_string);
2499 if ((local_string = (char *)malloc(strlen(buffer) + 1)) != NULL) {
2500 strcpy(local_string, buffer);
2502 free(buffer);
2504 return local_string;
2506 #endif /* !WIN32 */
2508 #if 0 /* currently unused */
2509 /* convert local string to display character set string */
2510 char *local_to_display_string(local_string)
2511 ZCONST char *local_string;
2513 char *display_string;
2515 /* For Windows, OEM string should never be bigger than ANSI string, says
2516 CharToOem description.
2517 For all other ports, just make a copy of local_string.
2519 if ((display_string = (char *)malloc(strlen(local_string) + 1)) == NULL) {
2520 return NULL;
2523 strcpy(display_string, local_string);
2525 #ifdef EBCDIC
2527 char *ebc;
2529 if ((ebc = malloc(strlen(display_string) + 1)) == NULL) {
2530 return NULL;
2532 strtoebc(ebc, display_string);
2533 free(display_string);
2534 display_string = ebc;
2536 #endif
2538 return display_string;
2540 #endif /* unused */
2542 /* UTF-8 to local */
2543 char *utf8_to_local_string(utf8_string, escape_all)
2544 ZCONST char *utf8_string;
2545 int escape_all;
2547 zwchar *wide = utf8_to_wide_string(utf8_string);
2548 char *loc = wide_to_local_string(wide, escape_all);
2549 free(wide);
2550 return loc;
2553 #if 0 /* currently unused */
2554 /* convert multi-byte character string to wide character string */
2555 zwchar *local_to_wide_string(local_string)
2556 ZCONST char *local_string;
2558 int wsize;
2559 wchar_t *wc_string;
2560 zwchar *wide_string;
2562 /* for now try to convert as string - fails if a bad char in string */
2563 wsize = mbstowcs(NULL, local_string, strlen(local_string) + 1);
2564 if (wsize == (size_t)-1) {
2565 /* could not convert */
2566 return NULL;
2569 /* convert it */
2570 if ((wc_string = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t))) == NULL) {
2571 return NULL;
2573 wsize = mbstowcs(wc_string, local_string, strlen(local_string) + 1);
2574 wc_string[wsize] = (wchar_t) 0;
2576 /* in case wchar_t is not zwchar */
2577 if ((wide_string = (zwchar *)malloc((wsize + 1) * sizeof(zwchar))) == NULL) {
2578 return NULL;
2580 for (wsize = 0; wide_string[wsize] = (zwchar)wc_string[wsize]; wsize++) ;
2581 wide_string[wsize] = (zwchar) 0;
2582 free(wc_string);
2584 return wide_string;
2588 /* convert wide string to UTF-8 */
2589 char *wide_to_utf8_string(wide_string)
2590 ZCONST zwchar *wide_string;
2592 int mbcount;
2593 char *utf8_string;
2595 /* get size of utf8 string */
2596 mbcount = ucs4_string_to_utf8(wide_string, NULL, 0);
2597 if (mbcount == -1)
2598 return NULL;
2599 if ((utf8_string = (char *) malloc(mbcount + 1)) == NULL) {
2600 return NULL;
2602 mbcount = ucs4_string_to_utf8(wide_string, utf8_string, mbcount + 1);
2603 if (mbcount == -1)
2604 return NULL;
2606 return utf8_string;
2608 #endif /* unused */
2610 /* convert UTF-8 string to wide string */
2611 zwchar *utf8_to_wide_string(utf8_string)
2612 ZCONST char *utf8_string;
2614 int wcount;
2615 zwchar *wide_string;
2617 wcount = utf8_to_ucs4_string(utf8_string, NULL, 0);
2618 if (wcount == -1)
2619 return NULL;
2620 if ((wide_string = (zwchar *) malloc((wcount + 1) * sizeof(zwchar)))
2621 == NULL) {
2622 return NULL;
2624 wcount = utf8_to_ucs4_string(utf8_string, wide_string, wcount + 1);
2626 return wide_string;
2629 #endif /* UNICODE_WCHAR */
2630 #endif /* UNICODE_SUPPORT */
2636 #ifdef USE_EF_UT_TIME
2638 #ifdef IZ_HAVE_UXUIDGID
2639 static int read_ux3_value(dbuf, uidgid_sz, p_uidgid)
2640 ZCONST uch *dbuf; /* buffer a uid or gid value */
2641 unsigned uidgid_sz; /* size of uid/gid value */
2642 ulg *p_uidgid; /* return storage: uid or gid value */
2644 zusz_t uidgid64;
2646 switch (uidgid_sz) {
2647 case 2:
2648 *p_uidgid = (ulg)makeword(dbuf);
2649 break;
2650 case 4:
2651 *p_uidgid = (ulg)makelong(dbuf);
2652 break;
2653 case 8:
2654 uidgid64 = makeint64(dbuf);
2655 #ifndef LARGE_FILE_SUPPORT
2656 if (uidgid64 == (zusz_t)0xffffffffL)
2657 return FALSE;
2658 #endif
2659 *p_uidgid = (ulg)uidgid64;
2660 if ((zusz_t)(*p_uidgid) != uidgid64)
2661 return FALSE;
2662 break;
2664 return TRUE;
2666 #endif /* IZ_HAVE_UXUIDGID */
2669 /*******************************/
2670 /* Function ef_scan_for_izux() */
2671 /*******************************/
2673 unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos_mdatetime,
2674 z_utim, z_uidgid)
2675 ZCONST uch *ef_buf; /* buffer containing extra field */
2676 unsigned ef_len; /* total length of extra field */
2677 int ef_is_c; /* flag indicating "is central extra field" */
2678 ulg dos_mdatetime; /* last_mod_file_date_time in DOS format */
2679 iztimes *z_utim; /* return storage: atime, mtime, ctime */
2680 ulg *z_uidgid; /* return storage: uid and gid */
2682 unsigned flags = 0;
2683 unsigned eb_id;
2684 unsigned eb_len;
2685 int have_new_type_eb = 0;
2686 long i_time; /* buffer for Unix style 32-bit integer time value */
2687 #ifdef TIME_T_TYPE_DOUBLE
2688 int ut_in_archive_sgn = 0;
2689 #else
2690 int ut_zip_unzip_compatible = FALSE;
2691 #endif
2693 /*---------------------------------------------------------------------------
2694 This function scans the extra field for EF_TIME, EF_IZUNIX2, EF_IZUNIX, or
2695 EF_PKUNIX blocks containing Unix-style time_t (GMT) values for the entry's
2696 access, creation, and modification time.
2697 If a valid block is found, the time stamps are copied to the iztimes
2698 structure (provided the z_utim pointer is not NULL).
2699 If a IZUNIX2 block is found or the IZUNIX block contains UID/GID fields,
2700 and the z_uidgid array pointer is valid (!= NULL), the owner info is
2701 transfered as well.
2702 The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring all
2703 data from probably present obsolete EF_IZUNIX blocks.
2704 If multiple blocks of the same type are found, only the information from
2705 the last block is used.
2706 The return value is a combination of the EF_TIME Flags field with an
2707 additional flag bit indicating the presence of valid UID/GID info,
2708 or 0 in case of failure.
2709 ---------------------------------------------------------------------------*/
2711 if (ef_len == 0 || ef_buf == NULL || (z_utim == 0 && z_uidgid == NULL))
2712 return 0;
2714 TTrace((stderr,"\nef_scan_for_izux: scanning extra field of length %u\n",
2715 ef_len));
2717 while (ef_len >= EB_HEADSIZE) {
2718 eb_id = makeword(EB_ID + ef_buf);
2719 eb_len = makeword(EB_LEN + ef_buf);
2721 if (eb_len > (ef_len - EB_HEADSIZE)) {
2722 /* discovered some extra field inconsistency! */
2723 TTrace((stderr,
2724 "ef_scan_for_izux: block length %u > rest ef_size %u\n", eb_len,
2725 ef_len - EB_HEADSIZE));
2726 break;
2729 switch (eb_id) {
2730 case EF_TIME:
2731 flags &= ~0x0ff; /* ignore previous IZUNIX or EF_TIME fields */
2732 have_new_type_eb = 1;
2733 if ( eb_len >= EB_UT_MINLEN && z_utim != NULL) {
2734 unsigned eb_idx = EB_UT_TIME1;
2735 TTrace((stderr,"ef_scan_for_izux: found TIME extra field\n"));
2736 flags |= (ef_buf[EB_HEADSIZE+EB_UT_FLAGS] & 0x0ff);
2737 if ((flags & EB_UT_FL_MTIME)) {
2738 if ((eb_idx+4) <= eb_len) {
2739 i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf);
2740 eb_idx += 4;
2741 TTrace((stderr," UT e.f. modification time = %ld\n",
2742 i_time));
2744 #ifdef TIME_T_TYPE_DOUBLE
2745 if ((ulg)(i_time) & (ulg)(0x80000000L)) {
2746 if (dos_mdatetime == DOSTIME_MINIMUM) {
2747 ut_in_archive_sgn = -1;
2748 z_utim->mtime =
2749 (time_t)((long)i_time | (~(long)0x7fffffffL));
2750 } else if (dos_mdatetime >= DOSTIME_2038_01_18) {
2751 ut_in_archive_sgn = 1;
2752 z_utim->mtime =
2753 (time_t)((ulg)i_time & (ulg)0xffffffffL);
2754 } else {
2755 ut_in_archive_sgn = 0;
2756 /* cannot determine sign of mtime;
2757 without modtime: ignore complete UT field */
2758 flags &= ~0x0ff; /* no time_t times available */
2759 TTrace((stderr,
2760 " UT modtime range error; ignore e.f.!\n"));
2761 break; /* stop scanning this field */
2763 } else {
2764 /* cannot determine, safe assumption is FALSE */
2765 ut_in_archive_sgn = 0;
2766 z_utim->mtime = (time_t)i_time;
2768 #else /* !TIME_T_TYPE_DOUBLE */
2769 if ((ulg)(i_time) & (ulg)(0x80000000L)) {
2770 ut_zip_unzip_compatible =
2771 ((time_t)0x80000000L < (time_t)0L)
2772 ? (dos_mdatetime == DOSTIME_MINIMUM)
2773 : (dos_mdatetime >= DOSTIME_2038_01_18);
2774 if (!ut_zip_unzip_compatible) {
2775 /* UnZip interprets mtime differently than Zip;
2776 without modtime: ignore complete UT field */
2777 flags &= ~0x0ff; /* no time_t times available */
2778 TTrace((stderr,
2779 " UT modtime range error; ignore e.f.!\n"));
2780 break; /* stop scanning this field */
2782 } else {
2783 /* cannot determine, safe assumption is FALSE */
2784 ut_zip_unzip_compatible = FALSE;
2786 z_utim->mtime = (time_t)i_time;
2787 #endif /* ?TIME_T_TYPE_DOUBLE */
2788 } else {
2789 flags &= ~EB_UT_FL_MTIME;
2790 TTrace((stderr," UT e.f. truncated; no modtime\n"));
2793 if (ef_is_c) {
2794 break; /* central version of TIME field ends here */
2797 if (flags & EB_UT_FL_ATIME) {
2798 if ((eb_idx+4) <= eb_len) {
2799 i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf);
2800 eb_idx += 4;
2801 TTrace((stderr," UT e.f. access time = %ld\n",
2802 i_time));
2803 #ifdef TIME_T_TYPE_DOUBLE
2804 if ((ulg)(i_time) & (ulg)(0x80000000L)) {
2805 if (ut_in_archive_sgn == -1)
2806 z_utim->atime =
2807 (time_t)((long)i_time | (~(long)0x7fffffffL));
2808 } else if (ut_in_archive_sgn == 1) {
2809 z_utim->atime =
2810 (time_t)((ulg)i_time & (ulg)0xffffffffL);
2811 } else {
2812 /* sign of 32-bit time is unknown -> ignore it */
2813 flags &= ~EB_UT_FL_ATIME;
2814 TTrace((stderr,
2815 " UT access time range error: skip time!\n"));
2817 } else {
2818 z_utim->atime = (time_t)i_time;
2820 #else /* !TIME_T_TYPE_DOUBLE */
2821 if (((ulg)(i_time) & (ulg)(0x80000000L)) &&
2822 !ut_zip_unzip_compatible) {
2823 flags &= ~EB_UT_FL_ATIME;
2824 TTrace((stderr,
2825 " UT access time range error: skip time!\n"));
2826 } else {
2827 z_utim->atime = (time_t)i_time;
2829 #endif /* ?TIME_T_TYPE_DOUBLE */
2830 } else {
2831 flags &= ~EB_UT_FL_ATIME;
2834 if (flags & EB_UT_FL_CTIME) {
2835 if ((eb_idx+4) <= eb_len) {
2836 i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf);
2837 TTrace((stderr," UT e.f. creation time = %ld\n",
2838 i_time));
2839 #ifdef TIME_T_TYPE_DOUBLE
2840 if ((ulg)(i_time) & (ulg)(0x80000000L)) {
2841 if (ut_in_archive_sgn == -1)
2842 z_utim->ctime =
2843 (time_t)((long)i_time | (~(long)0x7fffffffL));
2844 } else if (ut_in_archive_sgn == 1) {
2845 z_utim->ctime =
2846 (time_t)((ulg)i_time & (ulg)0xffffffffL);
2847 } else {
2848 /* sign of 32-bit time is unknown -> ignore it */
2849 flags &= ~EB_UT_FL_CTIME;
2850 TTrace((stderr,
2851 " UT creation time range error: skip time!\n"));
2853 } else {
2854 z_utim->ctime = (time_t)i_time;
2856 #else /* !TIME_T_TYPE_DOUBLE */
2857 if (((ulg)(i_time) & (ulg)(0x80000000L)) &&
2858 !ut_zip_unzip_compatible) {
2859 flags &= ~EB_UT_FL_CTIME;
2860 TTrace((stderr,
2861 " UT creation time range error: skip time!\n"));
2862 } else {
2863 z_utim->ctime = (time_t)i_time;
2865 #endif /* ?TIME_T_TYPE_DOUBLE */
2866 } else {
2867 flags &= ~EB_UT_FL_CTIME;
2871 break;
2873 case EF_IZUNIX2:
2874 if (have_new_type_eb == 0) {
2875 flags &= ~0x0ff; /* ignore any previous IZUNIX field */
2876 have_new_type_eb = 1;
2878 #ifdef IZ_HAVE_UXUIDGID
2879 if (have_new_type_eb > 1)
2880 break; /* IZUNIX3 overrides IZUNIX2 e.f. block ! */
2881 if (eb_len == EB_UX2_MINLEN && z_uidgid != NULL) {
2882 z_uidgid[0] = (ulg)makeword((EB_HEADSIZE+EB_UX2_UID) + ef_buf);
2883 z_uidgid[1] = (ulg)makeword((EB_HEADSIZE+EB_UX2_GID) + ef_buf);
2884 flags |= EB_UX2_VALID; /* signal success */
2886 #endif
2887 break;
2889 case EF_IZUNIX3:
2890 /* new 3rd generation Unix ef */
2891 have_new_type_eb = 2;
2894 Version 1 byte version of this extra field, currently 1
2895 UIDSize 1 byte Size of UID field
2896 UID Variable UID for this entry
2897 GIDSize 1 byte Size of GID field
2898 GID Variable GID for this entry
2901 #ifdef IZ_HAVE_UXUIDGID
2902 if (eb_len >= EB_UX3_MINLEN
2903 && z_uidgid != NULL
2904 && (*((EB_HEADSIZE + 0) + ef_buf) == 1)
2905 /* only know about version 1 */
2907 uch uid_size;
2908 uch gid_size;
2910 uid_size = *((EB_HEADSIZE + 1) + ef_buf);
2911 gid_size = *((EB_HEADSIZE + uid_size + 2) + ef_buf);
2913 flags &= ~0x0ff; /* ignore any previous UNIX field */
2915 if ( read_ux3_value((EB_HEADSIZE + 2) + ef_buf,
2916 uid_size, z_uidgid[0])
2918 read_ux3_value((EB_HEADSIZE + uid_size + 3) + ef_buf,
2919 gid_size, z_uidgid[1]) )
2921 flags |= EB_UX2_VALID; /* signal success */
2924 #endif /* IZ_HAVE_UXUIDGID */
2925 break;
2927 case EF_IZUNIX:
2928 case EF_PKUNIX: /* PKUNIX e.f. layout is identical to IZUNIX */
2929 if (eb_len >= EB_UX_MINLEN) {
2930 TTrace((stderr,"ef_scan_for_izux: found %s extra field\n",
2931 (eb_id == EF_IZUNIX ? "IZUNIX" : "PKUNIX")));
2932 if (have_new_type_eb > 0) {
2933 break; /* Ignore IZUNIX extra field block ! */
2935 if (z_utim != NULL) {
2936 flags |= (EB_UT_FL_MTIME | EB_UT_FL_ATIME);
2937 i_time = (long)makelong((EB_HEADSIZE+EB_UX_MTIME)+ef_buf);
2938 TTrace((stderr," Unix EF modtime = %ld\n", i_time));
2939 #ifdef TIME_T_TYPE_DOUBLE
2940 if ((ulg)(i_time) & (ulg)(0x80000000L)) {
2941 if (dos_mdatetime == DOSTIME_MINIMUM) {
2942 ut_in_archive_sgn = -1;
2943 z_utim->mtime =
2944 (time_t)((long)i_time | (~(long)0x7fffffffL));
2945 } else if (dos_mdatetime >= DOSTIME_2038_01_18) {
2946 ut_in_archive_sgn = 1;
2947 z_utim->mtime =
2948 (time_t)((ulg)i_time & (ulg)0xffffffffL);
2949 } else {
2950 ut_in_archive_sgn = 0;
2951 /* cannot determine sign of mtime;
2952 without modtime: ignore complete UT field */
2953 flags &= ~0x0ff; /* no time_t times available */
2954 TTrace((stderr,
2955 " UX modtime range error: ignore e.f.!\n"));
2957 } else {
2958 /* cannot determine, safe assumption is FALSE */
2959 ut_in_archive_sgn = 0;
2960 z_utim->mtime = (time_t)i_time;
2962 #else /* !TIME_T_TYPE_DOUBLE */
2963 if ((ulg)(i_time) & (ulg)(0x80000000L)) {
2964 ut_zip_unzip_compatible =
2965 ((time_t)0x80000000L < (time_t)0L)
2966 ? (dos_mdatetime == DOSTIME_MINIMUM)
2967 : (dos_mdatetime >= DOSTIME_2038_01_18);
2968 if (!ut_zip_unzip_compatible) {
2969 /* UnZip interpretes mtime differently than Zip;
2970 without modtime: ignore complete UT field */
2971 flags &= ~0x0ff; /* no time_t times available */
2972 TTrace((stderr,
2973 " UX modtime range error: ignore e.f.!\n"));
2975 } else {
2976 /* cannot determine, safe assumption is FALSE */
2977 ut_zip_unzip_compatible = FALSE;
2979 z_utim->mtime = (time_t)i_time;
2980 #endif /* ?TIME_T_TYPE_DOUBLE */
2981 i_time = (long)makelong((EB_HEADSIZE+EB_UX_ATIME)+ef_buf);
2982 TTrace((stderr," Unix EF actime = %ld\n", i_time));
2983 #ifdef TIME_T_TYPE_DOUBLE
2984 if ((ulg)(i_time) & (ulg)(0x80000000L)) {
2985 if (ut_in_archive_sgn == -1)
2986 z_utim->atime =
2987 (time_t)((long)i_time | (~(long)0x7fffffffL));
2988 } else if (ut_in_archive_sgn == 1) {
2989 z_utim->atime =
2990 (time_t)((ulg)i_time & (ulg)0xffffffffL);
2991 } else if (flags & 0x0ff) {
2992 /* sign of 32-bit time is unknown -> ignore it */
2993 flags &= ~EB_UT_FL_ATIME;
2994 TTrace((stderr,
2995 " UX access time range error: skip time!\n"));
2997 } else {
2998 z_utim->atime = (time_t)i_time;
3000 #else /* !TIME_T_TYPE_DOUBLE */
3001 if (((ulg)(i_time) & (ulg)(0x80000000L)) &&
3002 !ut_zip_unzip_compatible && (flags & 0x0ff)) {
3003 /* atime not in range of UnZip's time_t */
3004 flags &= ~EB_UT_FL_ATIME;
3005 TTrace((stderr,
3006 " UX access time range error: skip time!\n"));
3007 } else {
3008 z_utim->atime = (time_t)i_time;
3010 #endif /* ?TIME_T_TYPE_DOUBLE */
3012 #ifdef IZ_HAVE_UXUIDGID
3013 if (eb_len >= EB_UX_FULLSIZE && z_uidgid != NULL) {
3014 z_uidgid[0] = makeword((EB_HEADSIZE+EB_UX_UID) + ef_buf);
3015 z_uidgid[1] = makeword((EB_HEADSIZE+EB_UX_GID) + ef_buf);
3016 flags |= EB_UX2_VALID;
3018 #endif /* IZ_HAVE_UXUIDGID */
3020 break;
3022 default:
3023 break;
3026 /* Skip this extra field block */
3027 ef_buf += (eb_len + EB_HEADSIZE);
3028 ef_len -= (eb_len + EB_HEADSIZE);
3031 return flags;
3034 #endif /* USE_EF_UT_TIME */
3037 #if (defined(RISCOS) || defined(ACORN_FTYPE_NFS))
3039 #define SPARKID_2 0x30435241 /* = "ARC0" */
3041 /*******************************/
3042 /* Function getRISCOSexfield() */
3043 /*******************************/
3045 zvoid *getRISCOSexfield(ef_buf, ef_len)
3046 ZCONST uch *ef_buf; /* buffer containing extra field */
3047 unsigned ef_len; /* total length of extra field */
3049 unsigned eb_id;
3050 unsigned eb_len;
3052 /*---------------------------------------------------------------------------
3053 This function scans the extra field for a Acorn SPARK filetype ef-block.
3054 If a valid block is found, the function returns a pointer to the start
3055 of the SPARK_EF block in the extra field buffer. Otherwise, a NULL
3056 pointer is returned.
3057 ---------------------------------------------------------------------------*/
3059 if (ef_len == 0 || ef_buf == NULL)
3060 return NULL;
3062 Trace((stderr,"\ngetRISCOSexfield: scanning extra field of length %u\n",
3063 ef_len));
3065 while (ef_len >= EB_HEADSIZE) {
3066 eb_id = makeword(EB_ID + ef_buf);
3067 eb_len = makeword(EB_LEN + ef_buf);
3069 if (eb_len > (ef_len - EB_HEADSIZE)) {
3070 /* discovered some extra field inconsistency! */
3071 Trace((stderr,
3072 "getRISCOSexfield: block length %u > rest ef_size %u\n", eb_len,
3073 ef_len - EB_HEADSIZE));
3074 break;
3077 if (eb_id == EF_SPARK && (eb_len == 24 || eb_len == 20)) {
3078 if (makelong(EB_HEADSIZE + ef_buf) == SPARKID_2) {
3079 /* Return a pointer to the valid SPARK filetype ef block */
3080 return (zvoid *)ef_buf;
3084 /* Skip this extra field block */
3085 ef_buf += (eb_len + EB_HEADSIZE);
3086 ef_len -= (eb_len + EB_HEADSIZE);
3089 return NULL;
3092 #endif /* (RISCOS || ACORN_FTYPE_NFS) */