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