Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6725 siemargl 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
 
46
static int    do_seekable        OF((__GPRO__ int lastchance));
47
#ifdef DO_SAFECHECK_2GB
48
# ifdef USE_STRM_INPUT
49
static zoff_t file_size          OF((FILE *file));
50
# else
51
static zoff_t file_size          OF((int fh));
52
# endif
53
#endif /* DO_SAFECHECK_2GB */
54
static int    rec_find           OF((__GPRO__ zoff_t, char *, int));
55
static int    find_ecrec64       OF((__GPRO__ zoff_t searchlen));
56
static int    find_ecrec         OF((__GPRO__ zoff_t searchlen));
57
static int    process_zip_cmmnt  OF((__GPRO));
58
static int    get_cdir_ent       OF((__GPRO));
59
#ifdef IZ_HAVE_UXUIDGID
60
static int    read_ux3_value     OF((ZCONST uch *dbuf, unsigned uidgid_sz,
61
                                     ulg *p_uidgid));
62
#endif /* IZ_HAVE_UXUIDGID */
63
 
64
 
65
static 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
 
168
static ZCONST char Far MissingBytes[] =
169
  "error [%s]:  missing %s bytes in zipfile\n\
170
  (attempting to process anyway)\n";
171
static ZCONST char Far NullCentDirOffset[] =
172
  "error [%s]:  NULL central directory offset\n\
173
  (attempting to process anyway)\n";
174
static ZCONST char Far ZipfileEmpty[] = "warning [%s]:  zipfile is empty\n";
175
static ZCONST char Far CentDirStartNotFound[] =
176
  "error [%s]:  start of central directory not found;\n\
177
  zipfile corrupt.\n%s";
178
static ZCONST char Far Cent64EndSigSearchErr[] =
179
  "fatal error: read failure while seeking for End-of-centdir-64 signature.\n\
180
  This zipfile is corrupt.\n";
181
static 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
204
static 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
 
234
int 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
 
571
void 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
 
650
static 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
1036
static zoff_t file_size(file)
1037
    FILE *file;
1038
{
1039
    int sts;
1040
    size_t siz;
1041
#else /* !USE_STRM_INPUT */
1042
static 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
 
1118
static 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
 
1201
static 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
 
1219
static 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
 
1445
static 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
 
1588
static 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
 
1691
int 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
 
1766
static 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
 
1828
int 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
 
1877
int 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
 
1947
int 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
 
2080
static int utf8_char_bytes OF((ZCONST char *utf8));
2081
static ulg ucs4_char_from_utf8 OF((ZCONST char **utf8));
2082
static 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
 */
2093
static 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
 */
2132
static 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
 */
2160
static 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
 */
2200
static 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
 */
2229
static 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
 */
2263
static 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
 */
2289
int 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 */
2304
char *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
 
2344
char *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 */
2383
zwchar 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 */
2433
char *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 */
2506
char *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 */
2539
char *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 */
2551
zwchar *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 */
2585
char *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 */
2607
zwchar *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
2635
static 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
 
2669
unsigned 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
 
3041
zvoid *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) */