1/*
2  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
3
4  See the accompanying file LICENSE, version 2000-Apr-09 or later
5  (the contents of which are also included in unzip.h) for terms of use.
6  If, for some reason, all these files are missing, the Info-ZIP license
7  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
8*/
9/*---------------------------------------------------------------------------
10
11  extract.c
12
13  This file contains the high-level routines ("driver routines") for extrac-
14  ting and testing zipfile members.  It calls the low-level routines in files
15  explode.c, inflate.c, unreduce.c and unshrink.c.
16
17  Contains:  extract_or_test_files()
18             store_info()
19             extract_or_test_entrylist()
20             extract_or_test_member()
21             TestExtraField()
22             test_compr_eb()
23             memextract()
24             memflush()
25             extract_izvms_block()    (VMS or VMS_TEXT_CONV)
26             fnfilter()
27
28  ---------------------------------------------------------------------------*/
29
30
31#define __EXTRACT_C     /* identifies this source module */
32#define UNZIP_INTERNAL
33#include "unzip.h"
34#ifdef WINDLL
35#  ifdef POCKET_UNZIP
36#    include "wince/intrface.h"
37#  else
38#    include "windll/windll.h"
39#  endif
40#endif
41#include "crypt.h"
42
43#define GRRDUMP(buf,len) { \
44    int i, j; \
45 \
46    for (j = 0;  j < (len)/16;  ++j) { \
47        printf("        "); \
48        for (i = 0;  i < 16;  ++i) \
49            printf("%02x ", (uch)(buf)[i+(j<<4)]); \
50        printf("\n        "); \
51        for (i = 0;  i < 16;  ++i) { \
52            char c = (char)(buf)[i+(j<<4)]; \
53 \
54            if (c == '\n') \
55                printf("\\n "); \
56            else if (c == '\r') \
57                printf("\\r "); \
58            else \
59                printf(" %c ", c); \
60        } \
61        printf("\n"); \
62    } \
63    if ((len) % 16) { \
64        printf("        "); \
65        for (i = j<<4;  i < (len);  ++i) \
66            printf("%02x ", (uch)(buf)[i]); \
67        printf("\n        "); \
68        for (i = j<<4;  i < (len);  ++i) { \
69            char c = (char)(buf)[i]; \
70 \
71            if (c == '\n') \
72                printf("\\n "); \
73            else if (c == '\r') \
74                printf("\\r "); \
75            else \
76                printf(" %c ", c); \
77        } \
78        printf("\n"); \
79    } \
80}
81
82static int store_info OF((__GPRO));
83#ifdef SET_DIR_ATTRIB
84static int extract_or_test_entrylist OF((__GPRO__ unsigned numchunk,
85                ulg *pfilnum, ulg *pnum_bad_pwd, LONGINT *pold_extra_bytes,
86                unsigned *pnum_dirs, dirtime **pdirlist,
87                int error_in_archive));
88#else
89static int extract_or_test_entrylist OF((__GPRO__ unsigned numchunk,
90                ulg *pfilnum, ulg *pnum_bad_pwd, LONGINT *pold_extra_bytes,
91                int error_in_archive));
92#endif
93static int extract_or_test_member OF((__GPRO));
94#ifndef SFX
95   static int TestExtraField OF((__GPRO__ uch *ef, unsigned ef_len));
96   static int test_compr_eb OF((__GPRO__ uch *eb, unsigned eb_size,
97        unsigned compr_offset,
98        int (*test_uc_ebdata)(__GPRO__ uch *eb, unsigned eb_size,
99                              uch *eb_ucptr, ulg eb_ucsize)));
100#endif
101#if (defined(VMS) || defined(VMS_TEXT_CONV))
102   static void decompress_bits OF((uch *outptr, unsigned needlen,
103                                   ZCONST uch *bitptr));
104#endif
105#ifdef SET_DIR_ATTRIB
106   static int dircomp OF((ZCONST zvoid *a, ZCONST zvoid *b));
107#endif
108
109
110
111/*******************************/
112/*  Strings used in extract.c  */
113/*******************************/
114
115static ZCONST char Far VersionMsg[] =
116  "   skipping: %-22s  need %s compat. v%u.%u (can do v%u.%u)\n";
117static ZCONST char Far ComprMsgNum[] =
118  "   skipping: %-22s  unsupported compression method %u\n";
119#ifndef SFX
120   static ZCONST char Far ComprMsgName[] =
121     "   skipping: %-22s  `%s' method not supported\n";
122   static ZCONST char Far CmprNone[]       = "store";
123   static ZCONST char Far CmprShrink[]     = "shrink";
124   static ZCONST char Far CmprReduce[]     = "reduce";
125   static ZCONST char Far CmprImplode[]    = "implode";
126   static ZCONST char Far CmprTokenize[]   = "tokenize";
127   static ZCONST char Far CmprDeflate[]    = "deflate";
128   static ZCONST char Far CmprDeflat64[]   = "deflate64";
129   static ZCONST char Far CmprDCLImplode[] = "DCL implode";
130   static ZCONST char Far *ComprNames[NUM_METHODS] = {
131     CmprNone, CmprShrink, CmprReduce, CmprReduce, CmprReduce, CmprReduce,
132     CmprImplode, CmprTokenize, CmprDeflate, CmprDeflat64, CmprDCLImplode
133   };
134#endif /* !SFX */
135static ZCONST char Far FilNamMsg[] =
136  "%s:  bad filename length (%s)\n";
137static ZCONST char Far ExtFieldMsg[] =
138  "%s:  bad extra field length (%s)\n";
139static ZCONST char Far OffsetMsg[] =
140  "file #%lu:  bad zipfile offset (%s):  %ld\n";
141static ZCONST char Far ExtractMsg[] =
142  "%8sing: %-22s  %s%s";
143#ifndef SFX
144   static ZCONST char Far LengthMsg[] =
145     "%s  %s:  %ld bytes required to uncompress to %lu bytes;\n    %s\
146      supposed to require %lu bytes%s%s%s\n";
147#endif
148
149static ZCONST char Far BadFileCommLength[] = "%s:  bad file comment length\n";
150static ZCONST char Far LocalHdrSig[] = "local header sig";
151static ZCONST char Far BadLocalHdr[] = "file #%lu:  bad local header\n";
152static ZCONST char Far AttemptRecompensate[] =
153  "  (attempting to re-compensate)\n";
154#ifndef SFX
155   static ZCONST char Far BackslashPathSep[] =
156     "warning:  %s appears to use backslashes as path separators\n";
157#endif
158static ZCONST char Far AbsolutePathWarning[] =
159  "warning:  stripped absolute path spec from %s\n";
160static ZCONST char Far SkipVolumeLabel[] =
161  "   skipping: %-22s  %svolume label\n";
162
163#ifdef SET_DIR_ATTRIB  /* messages of code for setting directory attributes */
164   static ZCONST char Far DirlistEntryNoMem[] =
165     "warning:  cannot alloc memory for dir times/permissions/UID/GID\n";
166   static ZCONST char Far DirlistSortNoMem[] =
167     "warning:  cannot alloc memory to sort dir times/perms/etc.\n";
168   static ZCONST char Far DirlistSetAttrFailed[] =
169     "warning:  set times/attribs failed for %s\n";
170#endif
171
172#ifndef WINDLL
173   static ZCONST char Far ReplaceQuery[] =
174     "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ";
175   static ZCONST char Far AssumeNone[] = " NULL\n(assuming [N]one)\n";
176   static ZCONST char Far NewNameQuery[] = "new name: ";
177   static ZCONST char Far InvalidResponse[] = "error:  invalid response [%c]\n";
178#endif /* !WINDLL */
179
180static ZCONST char Far ErrorInArchive[] =
181  "At least one %serror was detected in %s.\n";
182static ZCONST char Far ZeroFilesTested[] =
183  "Caution:  zero files tested in %s.\n";
184
185#ifndef VMS
186   static ZCONST char Far VMSFormatQuery[] =
187     "\n%s:  stored in VMS format.  Extract anyway? (y/n) ";
188#endif
189
190#if CRYPT
191   static ZCONST char Far SkipCannotGetPasswd[] =
192     "   skipping: %-22s  unable to get password\n";
193   static ZCONST char Far SkipIncorrectPasswd[] =
194     "   skipping: %-22s  incorrect password\n";
195   static ZCONST char Far FilesSkipBadPasswd[] =
196     "%lu file%s skipped because of incorrect password.\n";
197   static ZCONST char Far MaybeBadPasswd[] =
198     "    (may instead be incorrect password)\n";
199#else
200   static ZCONST char Far SkipEncrypted[] =
201     "   skipping: %-22s  encrypted (not supported)\n";
202#endif
203
204static ZCONST char Far NoErrInCompData[] =
205  "No errors detected in compressed data of %s.\n";
206static ZCONST char Far NoErrInTestedFiles[] =
207  "No errors detected in %s for the %lu file%s tested.\n";
208static ZCONST char Far FilesSkipped[] =
209  "%lu file%s skipped because of unsupported compression or encoding.\n";
210
211static ZCONST char Far ErrUnzipFile[] = "  error:  %s%s %s\n";
212static ZCONST char Far ErrUnzipNoFile[] = "\n  error:  %s%s\n";
213static ZCONST char Far NotEnoughMem[] = "not enough memory to ";
214static ZCONST char Far InvalidComprData[] = "invalid compressed data to ";
215static ZCONST char Far Inflate[] = "inflate";
216
217#ifndef SFX
218   static ZCONST char Far Explode[] = "explode";
219#ifndef LZW_CLEAN
220   static ZCONST char Far Unshrink[] = "unshrink";
221#endif
222#endif
223
224#if (!defined(DELETE_IF_FULL) || !defined(HAVE_UNLINK))
225   static ZCONST char Far FileTruncated[] =
226     "warning:  %s is probably truncated\n";
227#endif
228
229static ZCONST char Far FileUnknownCompMethod[] =
230  "%s:  unknown compression method\n";
231static ZCONST char Far BadCRC[] = " bad CRC %08lx  (should be %08lx)\n";
232
233      /* TruncEAs[] also used in OS/2 mapname(), close_outfile() */
234char ZCONST Far TruncEAs[] = " compressed EA data missing (%d bytes)%s";
235char ZCONST Far TruncNTSD[] =
236  " compressed WinNT security data missing (%d bytes)%s";
237
238#ifndef SFX
239   static ZCONST char Far InconsistEFlength[] = "bad extra-field entry:\n \
240     EF block length (%u bytes) exceeds remaining EF data (%u bytes)\n";
241   static ZCONST char Far InvalidComprDataEAs[] =
242     " invalid compressed data for EAs\n";
243#  if (defined(WIN32) && defined(NTSD_EAS))
244     static ZCONST char Far InvalidSecurityEAs[] =
245       " EAs fail security check\n";
246#  endif
247   static ZCONST char Far UnsuppNTSDVersEAs[] =
248     " unsupported NTSD EAs version %d\n";
249   static ZCONST char Far BadCRC_EAs[] = " bad CRC for extended attributes\n";
250   static ZCONST char Far UnknComprMethodEAs[] =
251     " unknown compression method for EAs (%u)\n";
252   static ZCONST char Far NotEnoughMemEAs[] =
253     " out of memory while inflating EAs\n";
254   static ZCONST char Far UnknErrorEAs[] =
255     " unknown error on extended attributes\n";
256#endif /* !SFX */
257
258static ZCONST char Far UnsupportedExtraField[] =
259  "\nerror:  unsupported extra-field compression type (%u)--skipping\n";
260static ZCONST char Far BadExtraFieldCRC[] =
261  "error [%s]:  bad extra-field CRC %08lx (should be %08lx)\n";
262
263
264
265
266
267/**************************************/
268/*  Function extract_or_test_files()  */
269/**************************************/
270
271int extract_or_test_files(__G)    /* return PK-type error code */
272     __GDEF
273{
274    unsigned i, j;
275    long cd_bufstart;
276    uch *cd_inptr;
277    int cd_incnt;
278    ulg filnum=0L, blknum=0L;
279    int reached_end, no_endsig_found;
280    int error, error_in_archive=PK_COOL;
281    int *fn_matched=NULL, *xn_matched=NULL;
282    unsigned members_processed;
283    ulg num_skipped=0L, num_bad_pwd=0L;
284    LONGINT old_extra_bytes = 0L;
285#ifdef SET_DIR_ATTRIB
286    unsigned num_dirs=0;
287    dirtime *dirlist=(dirtime *)NULL, **sorted_dirlist=(dirtime **)NULL;
288#endif
289
290/*---------------------------------------------------------------------------
291    The basic idea of this function is as follows.  Since the central di-
292    rectory lies at the end of the zipfile and the member files lie at the
293    beginning or middle or wherever, it is not very desirable to simply
294    read a central directory entry, jump to the member and extract it, and
295    then jump back to the central directory.  In the case of a large zipfile
296    this would lead to a whole lot of disk-grinding, especially if each mem-
297    ber file is small.  Instead, we read from the central directory the per-
298    tinent information for a block of files, then go extract/test the whole
299    block.  Thus this routine contains two small(er) loops within a very
300    large outer loop:  the first of the small ones reads a block of files
301    from the central directory; the second extracts or tests each file; and
302    the outer one loops over blocks.  There's some file-pointer positioning
303    stuff in between, but that's about it.  Btw, it's because of this jump-
304    ing around that we can afford to be lenient if an error occurs in one of
305    the member files:  we should still be able to go find the other members,
306    since we know the offset of each from the beginning of the zipfile.
307  ---------------------------------------------------------------------------*/
308
309    G.pInfo = G.info;
310
311#if CRYPT
312    G.newzip = TRUE;
313#endif
314#ifndef SFX
315    G.reported_backslash = FALSE;
316#endif
317
318    /* malloc space for check on unmatched filespecs (OK if one or both NULL) */
319    if (G.filespecs > 0  &&
320        (fn_matched=(int *)malloc(G.filespecs*sizeof(int))) != (int *)NULL)
321        for (i = 0;  i < G.filespecs;  ++i)
322            fn_matched[i] = FALSE;
323    if (G.xfilespecs > 0  &&
324        (xn_matched=(int *)malloc(G.xfilespecs*sizeof(int))) != (int *)NULL)
325        for (i = 0;  i < G.xfilespecs;  ++i)
326            xn_matched[i] = FALSE;
327
328/*---------------------------------------------------------------------------
329    Begin main loop over blocks of member files.  We know the entire central
330    directory is on this disk:  we would not have any of this information un-
331    less the end-of-central-directory record was on this disk, and we would
332    not have gotten to this routine unless this is also the disk on which
333    the central directory starts.  In practice, this had better be the ONLY
334    disk in the archive, but we'll add multi-disk support soon.
335  ---------------------------------------------------------------------------*/
336
337    members_processed = 0;
338    no_endsig_found = FALSE;
339    reached_end = FALSE;
340    while (!reached_end) {
341        j = 0;
342#ifdef AMIGA
343        memzero(G.filenotes, DIR_BLKSIZ * sizeof(char *));
344#endif
345
346        /*
347         * Loop through files in central directory, storing offsets, file
348         * attributes, case-conversion and text-conversion flags until block
349         * size is reached.
350         */
351
352        while ((j < DIR_BLKSIZ)) {
353            G.pInfo = &G.info[j];
354
355            if (readbuf(__G__ G.sig, 4) == 0) {
356                error_in_archive = PK_EOF;
357                reached_end = TRUE;     /* ...so no more left to do */
358                break;
359            }
360            if (strncmp(G.sig, central_hdr_sig, 4)) {  /* is it a new entry? */
361                /* no new central directory entry
362                 * -> is the number of processed entries compatible with the
363                 *    number of entries as stored in the end_central record?
364                 */
365                if ((members_processed & (unsigned)0xFFFF) ==
366                    (unsigned)G.ecrec.total_entries_central_dir) {
367                    /* yes, so look if we ARE back at the end_central record
368                     */
369                    no_endsig_found =
370                      (strncmp(G.sig, end_central_sig, 4) != 0);
371                } else {
372                    /* no; we have found an error in the central directory
373                     * -> report it and stop searching for more Zip entries
374                     */
375                    Info(slide, 0x401, ((char *)slide,
376                      LoadFarString(CentSigMsg), j + blknum*DIR_BLKSIZ + 1));
377                    Info(slide, 0x401, ((char *)slide,
378                      LoadFarString(ReportMsg)));
379                    error_in_archive = PK_BADERR;
380                }
381                reached_end = TRUE;     /* ...so no more left to do */
382                break;
383            }
384            /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag */
385            if ((error = process_cdir_file_hdr(__G)) != PK_COOL) {
386                error_in_archive = error;   /* only PK_EOF defined */
387                reached_end = TRUE;     /* ...so no more left to do */
388                break;
389            }
390            if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) !=
391                 PK_COOL)
392            {
393                if (error > error_in_archive)
394                    error_in_archive = error;
395                if (error > PK_WARN) {  /* fatal:  no more left to do */
396                    Info(slide, 0x401, ((char *)slide, LoadFarString(FilNamMsg),
397                      FnFilter1(G.filename), "central"));
398                    reached_end = TRUE;
399                    break;
400                }
401            }
402            if ((error = do_string(__G__ G.crec.extra_field_length,
403                EXTRA_FIELD)) != 0)
404            {
405                if (error > error_in_archive)
406                    error_in_archive = error;
407                if (error > PK_WARN) {  /* fatal */
408                    Info(slide, 0x401, ((char *)slide,
409                      LoadFarString(ExtFieldMsg),
410                      FnFilter1(G.filename), "central"));
411                    reached_end = TRUE;
412                    break;
413                }
414            }
415#ifdef AMIGA
416            G.filenote_slot = j;
417            if ((error = do_string(__G__ G.crec.file_comment_length,
418                                   uO.N_flag ? FILENOTE : SKIP)) != PK_COOL)
419#else
420            if ((error = do_string(__G__ G.crec.file_comment_length, SKIP))
421                != PK_COOL)
422#endif
423            {
424                if (error > error_in_archive)
425                    error_in_archive = error;
426                if (error > PK_WARN) {  /* fatal */
427                    Info(slide, 0x421, ((char *)slide,
428                      LoadFarString(BadFileCommLength),
429                      FnFilter1(G.filename)));
430                    reached_end = TRUE;
431                    break;
432                }
433            }
434            if (G.process_all_files) {
435                if (store_info(__G))
436                    ++j;  /* file is OK; info[] stored; continue with next */
437                else
438                    ++num_skipped;
439            } else {
440                int   do_this_file;
441
442                if (G.filespecs == 0)
443                    do_this_file = TRUE;
444                else {  /* check if this entry matches an `include' argument */
445                    do_this_file = FALSE;
446                    for (i = 0; i < G.filespecs; i++)
447                        if (match(G.filename, G.pfnames[i], uO.C_flag)) {
448                            do_this_file = TRUE;  /* ^-- ignore case or not? */
449                            if (fn_matched)
450                                fn_matched[i] = TRUE;
451                            break;       /* found match, so stop looping */
452                        }
453                }
454                if (do_this_file) {  /* check if this is an excluded file */
455                    for (i = 0; i < G.xfilespecs; i++)
456                        if (match(G.filename, G.pxnames[i], uO.C_flag)) {
457                            do_this_file = FALSE; /* ^-- ignore case or not? */
458                            if (xn_matched)
459                                xn_matched[i] = TRUE;
460                            break;
461                        }
462                }
463                if (do_this_file) {
464                    if (store_info(__G))
465                        ++j;            /* file is OK */
466                    else
467                        ++num_skipped;  /* unsupp. compression or encryption */
468                }
469            } /* end if (process_all_files) */
470
471            members_processed++;
472
473        } /* end while-loop (adding files to current block) */
474
475        /* save position in central directory so can come back later */
476        cd_bufstart = G.cur_zipfile_bufstart;
477        cd_inptr = G.inptr;
478        cd_incnt = G.incnt;
479
480    /*-----------------------------------------------------------------------
481        Second loop:  process files in current block, extracting or testing
482        each one.
483      -----------------------------------------------------------------------*/
484
485        error = extract_or_test_entrylist(__G__ j,
486                        &filnum, &num_bad_pwd, &old_extra_bytes,
487#ifdef SET_DIR_ATTRIB
488                        &num_dirs, &dirlist,
489#endif
490                        error_in_archive);
491        if (error != PK_COOL) {
492            if (error > error_in_archive)
493                error_in_archive = error;       /* ...and keep going */
494            if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
495                if (fn_matched)
496                    free((zvoid *)fn_matched);
497                if (xn_matched)
498                    free((zvoid *)xn_matched);
499                return error_in_archive;        /* (unless disk full) */
500            }
501        }
502
503
504        /*
505         * Jump back to where we were in the central directory, then go and do
506         * the next batch of files.
507         */
508
509#ifdef USE_STRM_INPUT
510        fseek((FILE *)G.zipfd, (LONGINT)cd_bufstart, SEEK_SET);
511        G.cur_zipfile_bufstart = ftell((FILE *)G.zipfd);
512#else /* !USE_STRM_INPUT */
513        G.cur_zipfile_bufstart =
514          lseek(G.zipfd, (LONGINT)cd_bufstart, SEEK_SET);
515#endif /* ?USE_STRM_INPUT */
516        read(G.zipfd, (char *)G.inbuf, INBUFSIZ);  /* been here before... */
517        G.inptr = cd_inptr;
518        G.incnt = cd_incnt;
519        ++blknum;
520
521#ifdef TEST
522        printf("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart, cd_bufstart);
523        printf("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart,
524          cur_zipfile_bufstart);
525        printf("inptr-inbuf = %d\n", G.inptr-G.inbuf);
526        printf("incnt = %d\n\n", G.incnt);
527#endif
528
529    } /* end while-loop (blocks of files in central directory) */
530
531/*---------------------------------------------------------------------------
532    Go back through saved list of directories, sort and set times/perms/UIDs
533    and GIDs from the deepest level on up.
534  ---------------------------------------------------------------------------*/
535
536#ifdef SET_DIR_ATTRIB
537    if (num_dirs > 0) {
538        sorted_dirlist = (dirtime **)malloc(num_dirs*sizeof(dirtime *));
539        if (sorted_dirlist == (dirtime **)NULL) {
540            Info(slide, 0x401, ((char *)slide,
541              LoadFarString(DirlistSortNoMem)));
542            while (dirlist != (dirtime *)NULL) {
543                dirtime *d = dirlist;
544
545                dirlist = dirlist->next;
546                free(d);
547            }
548        } else {
549            if (num_dirs == 1)
550                sorted_dirlist[0] = dirlist;
551            else {
552                for (i = 0;  i < num_dirs;  ++i) {
553                    sorted_dirlist[i] = dirlist;
554                    dirlist = dirlist->next;
555                }
556                qsort((char *)sorted_dirlist, num_dirs, sizeof(dirtime *),
557                  dircomp);
558            }
559
560            Trace((stderr, "setting directory times/perms/attributes\n"));
561            for (i = 0;  i < num_dirs;  ++i) {
562                dirtime *d = sorted_dirlist[i];
563
564                Trace((stderr, "dir = %s\n", d->fn));
565                if ((error = set_direc_attribs(__G__ d)) != PK_OK) {
566                    Info(slide, 0x201, ((char *)slide,
567                      LoadFarString(DirlistSetAttrFailed), d->fn));
568                    if (!error_in_archive)
569                        error_in_archive = error;
570                }
571                free(d->fn);
572                free(d);
573            }
574            free(sorted_dirlist);
575        }
576    }
577#endif /* SET_DIR_ATTRIB */
578
579#if (defined(WIN32) && defined(NTSD_EAS))
580    process_defer_NT(__G);  /* process any deferred items for this .zip file */
581#endif
582
583/*---------------------------------------------------------------------------
584    Check for unmatched filespecs on command line and print warning if any
585    found.  Free allocated memory.
586  ---------------------------------------------------------------------------*/
587
588    if (fn_matched) {
589        for (i = 0;  i < G.filespecs;  ++i)
590            if (!fn_matched[i]) {
591#ifdef DLL
592                if (!G.redirect_data && !G.redirect_text)
593                    Info(slide, 0x401, ((char *)slide,
594                      LoadFarString(FilenameNotMatched), G.pfnames[i]));
595                else
596                    setFileNotFound(__G);
597#else
598                Info(slide, 1, ((char *)slide,
599                  LoadFarString(FilenameNotMatched), G.pfnames[i]));
600#endif
601                if (error_in_archive <= PK_WARN)
602                    error_in_archive = PK_FIND;   /* some files not found */
603            }
604        free((zvoid *)fn_matched);
605    }
606    if (xn_matched) {
607        for (i = 0;  i < G.xfilespecs;  ++i)
608            if (!xn_matched[i])
609                Info(slide, 0x401, ((char *)slide,
610                  LoadFarString(ExclFilenameNotMatched), G.pxnames[i]));
611        free((zvoid *)xn_matched);
612    }
613
614/*---------------------------------------------------------------------------
615    Double-check that we're back at the end-of-central-directory record, and
616    print quick summary of results, if we were just testing the archive.  We
617    send the summary to stdout so that people doing the testing in the back-
618    ground and redirecting to a file can just do a "tail" on the output file.
619  ---------------------------------------------------------------------------*/
620
621#ifndef SFX
622    if (no_endsig_found) {                      /* just to make sure */
623        Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
624        Info(slide, 0x401, ((char *)slide, LoadFarString(ReportMsg)));
625        if (!error_in_archive)       /* don't overwrite stronger error */
626            error_in_archive = PK_WARN;
627    }
628#endif /* !SFX */
629    if (uO.tflag) {
630        ulg num = filnum - num_bad_pwd;
631
632        if (uO.qflag < 2) {        /* GRR 930710:  was (uO.qflag == 1) */
633            if (error_in_archive)
634                Info(slide, 0, ((char *)slide, LoadFarString(ErrorInArchive),
635                  (error_in_archive == PK_WARN)? "warning-" : "", G.zipfn));
636            else if (num == 0L)
637                Info(slide, 0, ((char *)slide, LoadFarString(ZeroFilesTested),
638                  G.zipfn));
639            else if (G.process_all_files && (num_skipped+num_bad_pwd == 0L))
640                Info(slide, 0, ((char *)slide, LoadFarString(NoErrInCompData),
641                  G.zipfn));
642            else
643                Info(slide, 0, ((char *)slide, LoadFarString(NoErrInTestedFiles)
644                  , G.zipfn, num, (num==1L)? "":"s"));
645            if (num_skipped > 0L)
646                Info(slide, 0, ((char *)slide, LoadFarString(FilesSkipped),
647                  num_skipped, (num_skipped==1L)? "":"s"));
648#if CRYPT
649            if (num_bad_pwd > 0L)
650                Info(slide, 0, ((char *)slide, LoadFarString(FilesSkipBadPasswd)
651                  , num_bad_pwd, (num_bad_pwd==1L)? "":"s"));
652#endif /* CRYPT */
653        } else if ((uO.qflag == 0) && !error_in_archive && (num == 0))
654            Info(slide, 0, ((char *)slide, LoadFarString(ZeroFilesTested),
655              G.zipfn));
656    }
657
658    /* give warning if files not tested or extracted (first condition can still
659     * happen if zipfile is empty and no files specified on command line) */
660
661    if ((filnum == 0) && error_in_archive <= PK_WARN) {
662        if (num_skipped > 0L)
663            error_in_archive = IZ_UNSUP; /* unsupport. compression/encryption */
664        else
665            error_in_archive = PK_FIND;  /* no files found at all */
666    }
667#if CRYPT
668    else if ((filnum == num_bad_pwd) && error_in_archive <= PK_WARN)
669        error_in_archive = IZ_BADPWD;    /* bad passwd => all files skipped */
670#endif
671    else if ((num_skipped > 0L) && error_in_archive <= PK_WARN)
672        error_in_archive = IZ_UNSUP;     /* was PK_WARN; Jean-loup complained */
673#if CRYPT
674    else if ((num_bad_pwd > 0L) && !error_in_archive)
675        error_in_archive = PK_WARN;
676#endif
677
678    return error_in_archive;
679
680} /* end function extract_or_test_files() */
681
682
683
684
685
686/***************************/
687/*  Function store_info()  */
688/***************************/
689
690static int store_info(__G)   /* return 0 if skipping, 1 if OK */
691    __GDEF
692{
693#ifdef SFX
694#  ifdef USE_DEFLATE64
695#    define UNKN_COMPR \
696     (G.crec.compression_method!=STORED && G.crec.compression_method<DEFLATED \
697      && G.crec.compression_method>ENHDEFLATED)
698#  else
699#    define UNKN_COMPR \
700     (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED)
701#  endif
702#else
703#  ifdef COPYRIGHT_CLEAN  /* no reduced files */
704#    define UNKN_RED (G.crec.compression_method >= REDUCED1 && \
705                      G.crec.compression_method <= REDUCED4)
706#  else
707#    define UNKN_RED  FALSE  /* reducing not unknown */
708#  endif
709#  ifdef LZW_CLEAN  /* no shrunk files */
710#    define UNKN_SHR (G.crec.compression_method == SHRUNK)
711#  else
712#    define UNKN_SHR  FALSE  /* unshrinking not unknown */
713#  endif
714#  ifdef USE_DEFLATE64
715#    define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
716     G.crec.compression_method==TOKENIZED || \
717     G.crec.compression_method>ENHDEFLATED)
718#  else
719#    define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
720     G.crec.compression_method==TOKENIZED || \
721     G.crec.compression_method>DEFLATED)
722#  endif
723#endif
724
725/*---------------------------------------------------------------------------
726    Check central directory info for version/compatibility requirements.
727  ---------------------------------------------------------------------------*/
728
729    G.pInfo->encrypted = G.crec.general_purpose_bit_flag & 1;   /* bit field */
730    G.pInfo->ExtLocHdr = (G.crec.general_purpose_bit_flag & 8) == 8;  /* bit */
731    G.pInfo->textfile = G.crec.internal_file_attributes & 1;    /* bit field */
732    G.pInfo->crc = G.crec.crc32;
733    G.pInfo->compr_size = G.crec.csize;
734    G.pInfo->uncompr_size = G.crec.ucsize;
735
736    switch (uO.aflag) {
737        case 0:
738            G.pInfo->textmode = FALSE;   /* bit field */
739            break;
740        case 1:
741            G.pInfo->textmode = G.pInfo->textfile;   /* auto-convert mode */
742            break;
743        default:  /* case 2: */
744            G.pInfo->textmode = TRUE;
745            break;
746    }
747
748    if (G.crec.version_needed_to_extract[1] == VMS_) {
749        if (G.crec.version_needed_to_extract[0] > VMS_UNZIP_VERSION) {
750            if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
751                Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
752                  FnFilter1(G.filename), "VMS",
753                  G.crec.version_needed_to_extract[0] / 10,
754                  G.crec.version_needed_to_extract[0] % 10,
755                  VMS_UNZIP_VERSION / 10, VMS_UNZIP_VERSION % 10));
756            return 0;
757        }
758#ifndef VMS   /* won't be able to use extra field, but still have data */
759        else if (!uO.tflag && !IS_OVERWRT_ALL) { /* if -o, extract anyway */
760            Info(slide, 0x481, ((char *)slide, LoadFarString(VMSFormatQuery),
761              FnFilter1(G.filename)));
762            fgets(G.answerbuf, 9, stdin);
763            if ((*G.answerbuf != 'y') && (*G.answerbuf != 'Y'))
764                return 0;
765        }
766#endif /* !VMS */
767    /* usual file type:  don't need VMS to extract */
768    } else if (G.crec.version_needed_to_extract[0] > UNZIP_VERSION) {
769        if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
770            Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
771              FnFilter1(G.filename), "PK",
772              G.crec.version_needed_to_extract[0] / 10,
773              G.crec.version_needed_to_extract[0] % 10,
774              UNZIP_VERSION / 10, UNZIP_VERSION % 10));
775        return 0;
776    }
777
778    if UNKN_COMPR {
779        if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) {
780#ifndef SFX
781            if (G.crec.compression_method < NUM_METHODS)
782                Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgName),
783                  FnFilter1(G.filename),
784                  LoadFarStringSmall(ComprNames[G.crec.compression_method])));
785            else
786#endif
787                Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgNum),
788                  FnFilter1(G.filename),
789                  G.crec.compression_method));
790        }
791        return 0;
792    }
793#if (!CRYPT)
794    if (G.pInfo->encrypted) {
795        if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
796            Info(slide, 0x401, ((char *)slide, LoadFarString(SkipEncrypted),
797              FnFilter1(G.filename)));
798        return 0;
799    }
800#endif /* !CRYPT */
801
802    /* map whatever file attributes we have into the local format */
803    mapattr(__G);   /* GRR:  worry about return value later */
804
805    G.pInfo->diskstart = G.crec.disk_number_start;
806    G.pInfo->offset = (long)G.crec.relative_offset_local_header;
807    return 1;
808
809} /* end function store_info() */
810
811
812
813
814
815/******************************************/
816/*  Function extract_or_test_entrylist()  */
817/******************************************/
818
819static int extract_or_test_entrylist(__G__ numchunk,
820                pfilnum, pnum_bad_pwd, pold_extra_bytes,
821#ifdef SET_DIR_ATTRIB
822                pnum_dirs, pdirlist,
823#endif
824                error_in_archive)    /* return PK-type error code */
825    __GDEF
826    unsigned numchunk;
827    ulg *pfilnum;
828    ulg *pnum_bad_pwd;
829    LONGINT *pold_extra_bytes;
830#ifdef SET_DIR_ATTRIB
831    unsigned *pnum_dirs;
832    dirtime **pdirlist;
833#endif
834    int error_in_archive;
835{
836    unsigned i;
837    int renamed, query;
838    int skip_entry;
839    long bufstart, inbuf_offset, request;
840    int error, errcode;
841
842/* possible values for local skip_entry flag: */
843#define SKIP_NO         0       /* do not skip this entry */
844#define SKIP_Y_EXISTING 1       /* skip this entry, do not overwrite file */
845#define SKIP_Y_NONEXIST 2       /* skip this entry, do not create new file */
846
847    /*-----------------------------------------------------------------------
848        Second loop:  process files in current block, extracting or testing
849        each one.
850      -----------------------------------------------------------------------*/
851
852    for (i = 0; i < numchunk; ++i) {
853        (*pfilnum)++;   /* *pfilnum = i + blknum*DIR_BLKSIZ + 1; */
854        G.pInfo = &G.info[i];
855#ifdef NOVELL_BUG_FAILSAFE
856        G.dne = FALSE;  /* assume file exists until stat() says otherwise */
857#endif
858
859        /* if the target position is not within the current input buffer
860         * (either haven't yet read far enough, or (maybe) skipping back-
861         * ward), skip to the target position and reset readbuf(). */
862
863        /* seek_zipf(__G__ pInfo->offset);  */
864        request = G.pInfo->offset + G.extra_bytes;
865        inbuf_offset = request % INBUFSIZ;
866        bufstart = request - inbuf_offset;
867
868        Trace((stderr, "\ndebug: request = %ld, inbuf_offset = %ld\n",
869          request, inbuf_offset));
870        Trace((stderr,
871          "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
872          bufstart, G.cur_zipfile_bufstart));
873        if (request < 0) {
874            Info(slide, 0x401, ((char *)slide, LoadFarStringSmall(SeekMsg),
875              G.zipfn, LoadFarString(ReportMsg)));
876            error_in_archive = PK_ERR;
877            if (*pfilnum == 1 && G.extra_bytes != 0L) {
878                Info(slide, 0x401, ((char *)slide,
879                  LoadFarString(AttemptRecompensate)));
880                *pold_extra_bytes = G.extra_bytes;
881                G.extra_bytes = 0L;
882                request = G.pInfo->offset;  /* could also check if != 0 */
883                inbuf_offset = request % INBUFSIZ;
884                bufstart = request - inbuf_offset;
885                Trace((stderr, "debug: request = %ld, inbuf_offset = %ld\n",
886                  request, inbuf_offset));
887                Trace((stderr,
888                  "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
889                  bufstart, G.cur_zipfile_bufstart));
890                /* try again */
891                if (request < 0) {
892                    Trace((stderr,
893                      "debug: recompensated request still < 0\n"));
894                    Info(slide, 0x401, ((char *)slide,
895                      LoadFarStringSmall(SeekMsg),
896                      G.zipfn, LoadFarString(ReportMsg)));
897                    error_in_archive = PK_BADERR;
898                    continue;
899                }
900            } else {
901                error_in_archive = PK_BADERR;
902                continue;  /* this one hosed; try next */
903            }
904        }
905
906        if (bufstart != G.cur_zipfile_bufstart) {
907            Trace((stderr, "debug: bufstart != cur_zipfile_bufstart\n"));
908#ifdef USE_STRM_INPUT
909            fseek((FILE *)G.zipfd, (LONGINT)bufstart, SEEK_SET);
910            G.cur_zipfile_bufstart = ftell((FILE *)G.zipfd);
911#else /* !USE_STRM_INPUT */
912            G.cur_zipfile_bufstart =
913              lseek(G.zipfd, (LONGINT)bufstart, SEEK_SET);
914#endif /* ?USE_STRM_INPUT */
915            if ((G.incnt = read(G.zipfd,(char *)G.inbuf,INBUFSIZ)) <= 0)
916            {
917                Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
918                  *pfilnum, "lseek", bufstart));
919                error_in_archive = PK_BADERR;
920                continue;   /* can still do next file */
921            }
922            G.inptr = G.inbuf + (int)inbuf_offset;
923            G.incnt -= (int)inbuf_offset;
924        } else {
925            G.incnt += (int)(G.inptr-G.inbuf) - (int)inbuf_offset;
926            G.inptr = G.inbuf + (int)inbuf_offset;
927        }
928
929        /* should be in proper position now, so check for sig */
930        if (readbuf(__G__ G.sig, 4) == 0) {  /* bad offset */
931            Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
932              *pfilnum, "EOF", request));
933            error_in_archive = PK_BADERR;
934            continue;   /* but can still try next one */
935        }
936        if (strncmp(G.sig, local_hdr_sig, 4)) {
937            Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
938              *pfilnum, LoadFarStringSmall(LocalHdrSig), request));
939            /*
940                GRRDUMP(G.sig, 4)
941                GRRDUMP(local_hdr_sig, 4)
942             */
943            error_in_archive = PK_ERR;
944            if ((*pfilnum == 1 && G.extra_bytes != 0L) ||
945                (G.extra_bytes == 0L && *pold_extra_bytes != 0L)) {
946                Info(slide, 0x401, ((char *)slide,
947                  LoadFarString(AttemptRecompensate)));
948                if (G.extra_bytes) {
949                    *pold_extra_bytes = G.extra_bytes;
950                    G.extra_bytes = 0L;
951                } else
952                    G.extra_bytes = *pold_extra_bytes; /* third attempt */
953                if (((error = seek_zipf(__G__ G.pInfo->offset)) != PK_OK) ||
954                    (readbuf(__G__ G.sig, 4) == 0)) {  /* bad offset */
955                    if (error != PK_BADERR)
956                      Info(slide, 0x401, ((char *)slide,
957                        LoadFarString(OffsetMsg), *pfilnum, "EOF", request));
958                    error_in_archive = PK_BADERR;
959                    continue;   /* but can still try next one */
960                }
961                if (strncmp(G.sig, local_hdr_sig, 4)) {
962                    Info(slide, 0x401, ((char *)slide,
963                      LoadFarString(OffsetMsg), *pfilnum,
964                      LoadFarStringSmall(LocalHdrSig), request));
965                    error_in_archive = PK_BADERR;
966                    continue;
967                }
968            } else
969                continue;  /* this one hosed; try next */
970        }
971        if ((error = process_local_file_hdr(__G)) != PK_COOL) {
972            Info(slide, 0x421, ((char *)slide, LoadFarString(BadLocalHdr),
973              *pfilnum));
974            error_in_archive = error;   /* only PK_EOF defined */
975            continue;   /* can still try next one */
976        }
977        if ((error = do_string(__G__ G.lrec.filename_length, DS_FN_L)) !=
978             PK_COOL)
979        {
980            if (error > error_in_archive)
981                error_in_archive = error;
982            if (error > PK_WARN) {
983                Info(slide, 0x401, ((char *)slide, LoadFarString(FilNamMsg),
984                  FnFilter1(G.filename), "local"));
985                continue;   /* go on to next one */
986            }
987        }
988        if (G.extra_field != (uch *)NULL) {
989            free(G.extra_field);
990            G.extra_field = (uch *)NULL;
991        }
992        if ((error =
993             do_string(__G__ G.lrec.extra_field_length, EXTRA_FIELD)) != 0)
994        {
995            if (error > error_in_archive)
996                error_in_archive = error;
997            if (error > PK_WARN) {
998                Info(slide, 0x401, ((char *)slide,
999                  LoadFarString(ExtFieldMsg),
1000                  FnFilter1(G.filename), "local"));
1001                continue;   /* go on */
1002            }
1003        }
1004
1005#if CRYPT
1006        if (G.pInfo->encrypted &&
1007            (error = decrypt(__G__ uO.pwdarg)) != PK_COOL) {
1008            if (error == PK_WARN) {
1009                if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
1010                    Info(slide, 0x401, ((char *)slide,
1011                      LoadFarString(SkipIncorrectPasswd),
1012                      FnFilter1(G.filename)));
1013                ++(*pnum_bad_pwd);
1014            } else {  /* (error > PK_WARN) */
1015                if (error > error_in_archive)
1016                    error_in_archive = error;
1017                Info(slide, 0x401, ((char *)slide,
1018                  LoadFarString(SkipCannotGetPasswd),
1019                  FnFilter1(G.filename)));
1020            }
1021            continue;   /* go on to next file */
1022        }
1023#endif /* CRYPT */
1024
1025        /*
1026         * just about to extract file:  if extracting to disk, check if
1027         * already exists, and if so, take appropriate action according to
1028         * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper
1029         * loop because we don't store the possibly renamed filename[] in
1030         * info[])
1031         */
1032#ifdef DLL
1033        if (!uO.tflag && !uO.cflag && !G.redirect_data)
1034#else
1035        if (!uO.tflag && !uO.cflag)
1036#endif
1037        {
1038            renamed = FALSE;   /* user hasn't renamed output file yet */
1039
1040startover:
1041            query = FALSE;
1042            skip_entry = SKIP_NO;
1043            /* for files from DOS FAT, check for use of backslash instead
1044             *  of slash as directory separator (bug in some zipper(s); so
1045             *  far, not a problem in HPFS, NTFS or VFAT systems)
1046             */
1047#ifndef SFX
1048            if (G.pInfo->hostnum == FS_FAT_ && !MBSCHR(G.filename, '/')) {
1049                char *p=G.filename;
1050
1051                if (*p) do {
1052                    if (*p == '\\') {
1053                        if (!G.reported_backslash) {
1054                            Info(slide, 0x21, ((char *)slide,
1055                              LoadFarString(BackslashPathSep), G.zipfn));
1056                            G.reported_backslash = TRUE;
1057                            if (!error_in_archive)
1058                                error_in_archive = PK_WARN;
1059                        }
1060                        *p = '/';
1061                    }
1062                } while (*PREINCSTR(p));
1063            }
1064#endif /* !SFX */
1065
1066            if (!renamed) {
1067               /* remove absolute path specs */
1068               if (G.filename[0] == '/') {
1069                   Info(slide, 0x401, ((char *)slide,
1070                        LoadFarString(AbsolutePathWarning),
1071                        FnFilter1(G.filename)));
1072                   if (!error_in_archive)
1073                       error_in_archive = PK_WARN;
1074                   do {
1075                       char *p = G.filename + 1;
1076                       do {
1077                           *(p-1) = *p;
1078                       } while (*p++ != '\0');
1079                   } while (G.filename[0] == '/');
1080               }
1081            }
1082
1083            /* mapname can create dirs if not freshening or if renamed */
1084            error = mapname(__G__ renamed);
1085            if ((errcode = error & ~MPN_MASK) != PK_OK &&
1086                error_in_archive < errcode)
1087                error_in_archive = errcode;
1088            if ((errcode = error & MPN_MASK) > MPN_INF_TRUNC) {
1089                if (errcode == MPN_CREATED_DIR) {
1090#ifdef SET_DIR_ATTRIB
1091                    dirtime *d_entry;
1092
1093                    d_entry = (dirtime *)malloc(sizeof(dirtime));
1094                    if (d_entry == (dirtime *)NULL) {
1095                        Info(slide, 0x401, ((char *)slide,
1096                             LoadFarString(DirlistEntryNoMem)));
1097                    } else {
1098                        unsigned eb_izux_flg;
1099
1100                        d_entry->next = (*pdirlist);
1101                        (*pdirlist) = d_entry;
1102                        (*pdirlist)->fn =
1103                          (char *)malloc(strlen(G.filename) + 1);
1104                        if ((*pdirlist)->fn == (char *)NULL) {
1105                            Info(slide, 0x401, ((char *)slide,
1106                              LoadFarString(DirlistEntryNoMem)));
1107                            (*pdirlist) = d_entry->next;
1108                            free(d_entry);
1109                            if (!error_in_archive)
1110                                error_in_archive = PK_WARN;
1111                            continue;
1112                        }
1113                        strcpy((*pdirlist)->fn, G.filename);
1114                        (*pdirlist)->perms = G.pInfo->file_attr;
1115#ifdef USE_EF_UT_TIME
1116                        eb_izux_flg = G.extra_field? ef_scan_for_izux(
1117                          G.extra_field, G.lrec.extra_field_length, 0,
1118                          G.lrec.last_mod_dos_datetime,
1119#ifdef IZ_CHECK_TZ
1120                          (G.tz_is_valid ? &((*pdirlist)->u.t3) : NULL),
1121#else
1122                          &((*pdirlist)->u.t3),
1123#endif
1124                          (*pdirlist)->uidgid)
1125                          : 0;
1126#else /* !USE_EF_UT_TIME */
1127                        eb_izux_flg = 0;
1128#endif /* ?USE_EF_UT_TIME */
1129                        if (eb_izux_flg & EB_UT_FL_MTIME) {
1130                            TTrace((stderr,
1131                              "\nextract:  Unix dir e.f. modtime = %ld\n",
1132                              (*pdirlist)->u.t3.mtime));
1133                        } else {
1134                            (*pdirlist)->u.t3.mtime = dos_to_unix_time(
1135                              G.lrec.last_mod_dos_datetime);
1136                        }
1137                        if (eb_izux_flg & EB_UT_FL_ATIME) {
1138                            TTrace((stderr,
1139                              "\nextract:  Unix dir e.f. actime = %ld\n",
1140                              (*pdirlist)->u.t3.atime));
1141                        } else {
1142                            (*pdirlist)->u.t3.atime =
1143                              (*pdirlist)->u.t3.mtime;
1144                        }
1145                        (*pdirlist)->have_uidgid =
1146#ifdef RESTORE_UIDGID
1147                            (uO.X_flag && (eb_izux_flg & EB_UX2_VALID));
1148#else
1149                            0;
1150#endif
1151                        ++(*pnum_dirs);
1152                    }
1153#endif /* SET_DIR_ATTRIB */
1154                } else if (errcode == MPN_VOL_LABEL) {
1155#ifdef DOS_OS2_W32
1156                    Info(slide, 0x401, ((char *)slide,
1157                      LoadFarString(SkipVolumeLabel),
1158                      FnFilter1(G.filename),
1159                      uO.volflag? "hard disk " : ""));
1160#else
1161                    Info(slide, 1, ((char *)slide,
1162                      LoadFarString(SkipVolumeLabel),
1163                      FnFilter1(G.filename), ""));
1164#endif
1165                } else if (errcode > MPN_INF_SKIP &&
1166                           error_in_archive < PK_ERR)
1167                    error_in_archive = PK_ERR;
1168                Trace((stderr, "mapname(%s) returns error code = %d\n",
1169                  FnFilter1(G.filename), error));
1170                continue;   /* go on to next file */
1171            }
1172
1173#ifdef QDOS
1174            QFilename(__G__ G.filename);
1175#endif
1176            switch (check_for_newer(__G__ G.filename)) {
1177                case DOES_NOT_EXIST:
1178#ifdef NOVELL_BUG_FAILSAFE
1179                    G.dne = TRUE;   /* stat() says file DOES NOT EXIST */
1180#endif
1181                    /* freshen (no new files): skip unless just renamed */
1182                    if (uO.fflag && !renamed)
1183                        skip_entry = SKIP_Y_NONEXIST;
1184                    break;
1185                case EXISTS_AND_OLDER:
1186#ifdef UNIXBACKUP
1187                    if (!uO.B_flag)
1188#endif
1189                    {
1190                        if (IS_OVERWRT_NONE)
1191                            /* never overwrite:  skip file */
1192                            skip_entry = SKIP_Y_EXISTING;
1193                        else if (!IS_OVERWRT_ALL)
1194                            query = TRUE;
1195                    }
1196                    break;
1197                case EXISTS_AND_NEWER:             /* (or equal) */
1198#ifdef UNIXBACKUP
1199                    if ((!uO.B_flag && IS_OVERWRT_NONE) ||
1200#else
1201                    if (IS_OVERWRT_NONE ||
1202#endif
1203                        (uO.uflag && !renamed)) {
1204                        /* skip if update/freshen & orig name */
1205                        skip_entry = SKIP_Y_EXISTING;
1206                    } else {
1207#ifdef UNIXBACKUP
1208                        if (!IS_OVERWRT_ALL && !uO.B_flag)
1209#else
1210                        if (!IS_OVERWRT_ALL)
1211#endif
1212                            query = TRUE;
1213                    }
1214                    break;
1215                }
1216            if (query) {
1217#ifdef WINDLL
1218                switch (G.lpUserFunctions->replace != NULL ?
1219                        (*G.lpUserFunctions->replace)(G.filename) :
1220                        IDM_REPLACE_NONE) {
1221                    case IDM_REPLACE_RENAME:
1222                        _ISO_INTERN(G.filename);
1223                        renamed = TRUE;
1224                        goto startover;
1225                    case IDM_REPLACE_ALL:
1226                        G.overwrite_mode = OVERWRT_ALWAYS;
1227                        /* FALL THROUGH, extract */
1228                    case IDM_REPLACE_YES:
1229                        break;
1230                    case IDM_REPLACE_NONE:
1231                        G.overwrite_mode = OVERWRT_NEVER;
1232                        /* FALL THROUGH, skip */
1233                    case IDM_REPLACE_NO:
1234                        skip_entry = SKIP_Y_EXISTING;
1235                        break;
1236                }
1237#else /* !WINDLL */
1238                extent fnlen;
1239reprompt:
1240                Info(slide, 0x81, ((char *)slide,
1241                  LoadFarString(ReplaceQuery),
1242                  FnFilter1(G.filename)));
1243                if (fgets(G.answerbuf, 9, stdin) == (char *)NULL) {
1244                    Info(slide, 1, ((char *)slide,
1245                      LoadFarString(AssumeNone)));
1246                    *G.answerbuf = 'N';
1247                    if (!error_in_archive)
1248                        error_in_archive = 1;  /* not extracted:  warning */
1249                }
1250                switch (*G.answerbuf) {
1251                    case 'r':
1252                    case 'R':
1253                        do {
1254                            Info(slide, 0x81, ((char *)slide,
1255                              LoadFarString(NewNameQuery)));
1256                            fgets(G.filename, FILNAMSIZ, stdin);
1257                            /* usually get \n here:  better check for it */
1258                            fnlen = strlen(G.filename);
1259                            if (lastchar(G.filename, fnlen) == '\n')
1260                                G.filename[--fnlen] = '\0';
1261                        } while (fnlen == 0);
1262#ifdef WIN32  /* WIN32 fgets( ... , stdin) returns OEM coded strings */
1263                        _OEM_INTERN(G.filename);
1264#endif
1265                        renamed = TRUE;
1266                        goto startover;   /* sorry for a goto */
1267                    case 'A':   /* dangerous option:  force caps */
1268                        G.overwrite_mode = OVERWRT_ALWAYS;
1269                        /* FALL THROUGH, extract */
1270                    case 'y':
1271                    case 'Y':
1272                        break;
1273                    case 'N':
1274                        G.overwrite_mode = OVERWRT_NEVER;
1275                        /* FALL THROUGH, skip */
1276                    case 'n':
1277                        /* skip file */
1278                        skip_entry = SKIP_Y_EXISTING;
1279                        break;
1280                    default:
1281                        Info(slide, 1, ((char *)slide,
1282                          LoadFarString(InvalidResponse), *G.answerbuf));
1283                        goto reprompt;   /* yet another goto? */
1284                } /* end switch (*answerbuf) */
1285#endif /* ?WINDLL */
1286            } /* end if (query) */
1287            if (skip_entry != SKIP_NO) {
1288#ifdef WINDLL
1289                if (skip_entry == SKIP_Y_EXISTING) {
1290                    /* report skipping of an existing entry */
1291                    Info(slide, 0, ((char *)slide,
1292                      ((IS_OVERWRT_NONE || !uO.uflag || renamed) ?
1293                       "Target file exists.\nSkipping %s\n" :
1294                       "Target file newer.\nSkipping %s\n"),
1295                      FnFilter1(G.filename)));
1296                }
1297#endif /* WINDLL */
1298                continue;
1299            }
1300        } /* end if (extracting to disk) */
1301
1302#ifdef DLL
1303        if ((G.statreportcb != NULL) &&
1304            (*G.statreportcb)(__G__ UZ_ST_START_EXTRACT, G.zipfn,
1305                              G.filename, NULL)) {
1306            return IZ_CTRLC;        /* cancel operation by user request */
1307        }
1308#endif
1309#ifdef MACOS  /* MacOS is no preemptive OS, thus call event-handling by hand */
1310        UserStop();
1311#endif
1312#ifdef AMIGA
1313        G.filenote_slot = i;
1314#endif
1315        G.disk_full = 0;
1316        if ((error = extract_or_test_member(__G)) != PK_COOL) {
1317            if (error > error_in_archive)
1318                error_in_archive = error;       /* ...and keep going */
1319#ifdef DLL
1320            if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
1321#else
1322            if (G.disk_full > 1) {
1323#endif
1324                return error_in_archive;        /* (unless disk full) */
1325            }
1326        }
1327#ifdef DLL
1328        if ((G.statreportcb != NULL) &&
1329            (*G.statreportcb)(__G__ UZ_ST_FINISH_MEMBER, G.zipfn,
1330                              G.filename, (zvoid *)&G.lrec.ucsize)) {
1331            return IZ_CTRLC;        /* cancel operation by user request */
1332        }
1333#endif
1334#ifdef MACOS  /* MacOS is no preemptive OS, thus call event-handling by hand */
1335        UserStop();
1336#endif
1337    } /* end for-loop (i:  files in current block) */
1338
1339    return error_in_archive;
1340
1341} /* end function extract_or_test_entrylist() */
1342
1343
1344
1345
1346
1347/***************************************/
1348/*  Function extract_or_test_member()  */
1349/***************************************/
1350
1351static int extract_or_test_member(__G)    /* return PK-type error code */
1352     __GDEF
1353{
1354    char *nul="[empty] ", *txt="[text]  ", *bin="[binary]";
1355#ifdef CMS_MVS
1356    char *ebc="[ebcdic]";
1357#endif
1358    register int b;
1359    int r, error=PK_COOL;
1360#if (defined(DLL) && !defined(NO_SLIDE_REDIR))
1361    ulg wsize;
1362#else
1363#   define wsize WSIZE
1364#endif
1365
1366
1367/*---------------------------------------------------------------------------
1368    Initialize variables, buffers, etc.
1369  ---------------------------------------------------------------------------*/
1370
1371    G.bits_left = 0;
1372    G.bitbuf = 0L;       /* unreduce and unshrink only */
1373    G.zipeof = 0;
1374    G.newfile = TRUE;
1375    G.crc32val = CRCVAL_INITIAL;
1376
1377#ifdef SYMLINKS
1378    /* if file came from Unix and is a symbolic link and we are extracting
1379     * to disk, prepare to restore the link */
1380    if (S_ISLNK(G.pInfo->file_attr) &&
1381        (G.pInfo->hostnum == UNIX_ || G.pInfo->hostnum == ATARI_ ||
1382         G.pInfo->hostnum == BEOS_) &&
1383        !uO.tflag && !uO.cflag && (G.lrec.ucsize > 0))
1384        G.symlnk = TRUE;
1385    else
1386        G.symlnk = FALSE;
1387#endif /* SYMLINKS */
1388
1389    if (uO.tflag) {
1390        if (!uO.qflag)
1391            Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), "test",
1392              FnFilter1(G.filename), "", ""));
1393    } else {
1394#ifdef DLL
1395        if (uO.cflag && !G.redirect_data)
1396#else
1397        if (uO.cflag)
1398#endif
1399        {
1400#if (defined(OS2) && defined(__IBMC__) && (__IBMC__ >= 200))
1401            G.outfile = freopen("", "wb", stdout);   /* VAC++ ignores setmode */
1402#else
1403            G.outfile = stdout;
1404#endif
1405#ifdef DOS_FLX_NLM_OS2_W32
1406#if (defined(__HIGHC__) && !defined(FLEXOS))
1407            setmode(G.outfile, _BINARY);
1408#else /* !(defined(__HIGHC__) && !defined(FLEXOS)) */
1409            setmode(fileno(G.outfile), O_BINARY);
1410#endif /* ?(defined(__HIGHC__) && !defined(FLEXOS)) */
1411#           define NEWLINE "\r\n"
1412#else /* !DOS_FLX_NLM_OS2_W32 */
1413#           define NEWLINE "\n"
1414#endif /* ?DOS_FLX_NLM_OS2_W32 */
1415#ifdef VMS
1416            if (open_outfile(__G))   /* VMS:  required even for stdout! */
1417                return PK_DISK;
1418#endif
1419        } else if (open_outfile(__G))
1420            return PK_DISK;
1421    }
1422
1423/*---------------------------------------------------------------------------
1424    Unpack the file.
1425  ---------------------------------------------------------------------------*/
1426
1427    defer_leftover_input(__G);    /* so NEXTBYTE bounds check will work */
1428    switch (G.lrec.compression_method) {
1429        case STORED:
1430            if (!uO.tflag && QCOND2) {
1431#ifdef SYMLINKS
1432                if (G.symlnk)   /* can also be deflated, but rarer... */
1433                    Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
1434                      "link", FnFilter1(G.filename), "", ""));
1435                else
1436#endif /* SYMLINKS */
1437                Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
1438                  "extract", FnFilter1(G.filename),
1439                  (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1440                  "" : (G.lrec.ucsize == 0L? nul : (G.pInfo->textfile? txt :
1441                  bin)), uO.cflag? NEWLINE : ""));
1442            }
1443#if (defined(DLL) && !defined(NO_SLIDE_REDIR))
1444            if (G.redirect_slide) {
1445                wsize = G.redirect_size; redirSlide = G.redirect_buffer;
1446            } else {
1447                wsize = WSIZE; redirSlide = slide;
1448            }
1449#endif
1450            G.outptr = redirSlide;
1451            G.outcnt = 0L;
1452            while ((b = NEXTBYTE) != EOF) {
1453                *G.outptr++ = (uch)b;
1454                if (++G.outcnt == wsize) {
1455                    error = flush(__G__ redirSlide, G.outcnt, 0);
1456                    G.outptr = redirSlide;
1457                    G.outcnt = 0L;
1458                    if (error != PK_COOL || G.disk_full) break;
1459                }
1460            }
1461            if (G.outcnt)          /* flush final (partial) buffer */
1462                flush(__G__ redirSlide, G.outcnt, 0);
1463            break;
1464
1465#ifndef SFX
1466#ifndef LZW_CLEAN
1467        case SHRUNK:
1468            if (!uO.tflag && QCOND2) {
1469                Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
1470                  LoadFarStringSmall(Unshrink), FnFilter1(G.filename),
1471                  (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1472                  "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
1473            }
1474            if ((r = unshrink(__G)) != PK_COOL) {
1475                if (r < PK_DISK) {
1476                    if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
1477                        Info(slide, 0x401, ((char *)slide,
1478                          LoadFarStringSmall(ErrUnzipFile),
1479                          LoadFarString(NotEnoughMem),
1480                          LoadFarStringSmall2(Unshrink),
1481                          FnFilter1(G.filename)));
1482                    else
1483                        Info(slide, 0x401, ((char *)slide,
1484                          LoadFarStringSmall(ErrUnzipNoFile),
1485                          LoadFarString(NotEnoughMem),
1486                          LoadFarStringSmall2(Unshrink)));
1487                }
1488                error = r;
1489            }
1490            break;
1491#endif /* !LZW_CLEAN */
1492
1493#ifndef COPYRIGHT_CLEAN
1494        case REDUCED1:
1495        case REDUCED2:
1496        case REDUCED3:
1497        case REDUCED4:
1498            if (!uO.tflag && QCOND2) {
1499                Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
1500                  "unreduc", FnFilter1(G.filename),
1501                  (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1502                  "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
1503            }
1504            if ((r = unreduce(__G)) != PK_COOL) {
1505                /* unreduce() returns only PK_COOL, PK_DISK, or IZ_CTRLC */
1506                error = r;
1507            }
1508            break;
1509#endif /* !COPYRIGHT_CLEAN */
1510
1511        case IMPLODED:
1512            if (!uO.tflag && QCOND2) {
1513                Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
1514                  "explod", FnFilter1(G.filename),
1515                  (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1516                  "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
1517            }
1518            if (((r = explode(__G)) != 0) && (r != 5)) { /* treat 5 specially */
1519                if (r < PK_DISK) {
1520                    if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
1521                        Info(slide, 0x401, ((char *)slide,
1522                          LoadFarStringSmall(ErrUnzipFile), r == 3?
1523                          LoadFarString(NotEnoughMem) :
1524                          LoadFarString(InvalidComprData),
1525                          LoadFarStringSmall2(Explode),
1526                          FnFilter1(G.filename)));
1527                    else
1528                        Info(slide, 0x401, ((char *)slide,
1529                          LoadFarStringSmall(ErrUnzipNoFile), r == 3?
1530                          LoadFarString(NotEnoughMem) :
1531                          LoadFarString(InvalidComprData),
1532                          LoadFarStringSmall2(Explode)));
1533                    error = (r == 3)? PK_MEM3 : PK_ERR;
1534                } else {
1535                    error = r;
1536                }
1537            }
1538            if (r == 5) {
1539                int warning = ((ulg)G.used_csize <= G.lrec.csize);
1540
1541                if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
1542                    Info(slide, 0x401, ((char *)slide, LoadFarString(LengthMsg),
1543                      "", warning?  "warning" : "error", G.used_csize,
1544                      G.lrec.ucsize, warning?  "  " : "", G.lrec.csize,
1545                      " [", FnFilter1(G.filename), "]"));
1546                else
1547                    Info(slide, 0x401, ((char *)slide, LoadFarString(LengthMsg),
1548                      "\n", warning? "warning" : "error", G.used_csize,
1549                      G.lrec.ucsize, warning? "  ":"", G.lrec.csize,
1550                      "", "", "."));
1551                error = warning? PK_WARN : PK_ERR;
1552            }
1553            break;
1554#endif /* !SFX */
1555
1556        case DEFLATED:
1557#ifdef USE_DEFLATE64
1558        case ENHDEFLATED:
1559#endif
1560            if (!uO.tflag && QCOND2) {
1561                Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
1562                  "inflat", FnFilter1(G.filename),
1563                  (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1564                  "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
1565            }
1566#ifndef USE_ZLIB  /* zlib's function is called inflate(), too */
1567#  define UZinflate inflate
1568#endif
1569            if ((r = UZinflate(__G__
1570                               (G.lrec.compression_method == ENHDEFLATED)))
1571                != 0) {
1572                if (r < PK_DISK) {
1573                    if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
1574                        Info(slide, 0x401, ((char *)slide,
1575                          LoadFarStringSmall(ErrUnzipFile), r == 3?
1576                          LoadFarString(NotEnoughMem) :
1577                          LoadFarString(InvalidComprData),
1578                          LoadFarStringSmall2(Inflate),
1579                          FnFilter1(G.filename)));
1580                    else
1581                        Info(slide, 0x401, ((char *)slide,
1582                          LoadFarStringSmall(ErrUnzipNoFile), r == 3?
1583                          LoadFarString(NotEnoughMem) :
1584                          LoadFarString(InvalidComprData),
1585                          LoadFarStringSmall2(Inflate)));
1586                    error = (r == 3)? PK_MEM3 : PK_ERR;
1587                } else {
1588                    error = r;
1589                }
1590            }
1591            break;
1592
1593        default:   /* should never get to this point */
1594            Info(slide, 0x401, ((char *)slide,
1595              LoadFarString(FileUnknownCompMethod), FnFilter1(G.filename)));
1596            /* close and delete file before return? */
1597            undefer_input(__G);
1598            return PK_WARN;
1599
1600    } /* end switch (compression method) */
1601
1602/*---------------------------------------------------------------------------
1603    Close the file and set its date and time (not necessarily in that order),
1604    and make sure the CRC checked out OK.  Logical-AND the CRC for 64-bit
1605    machines (redundant on 32-bit machines).
1606  ---------------------------------------------------------------------------*/
1607
1608#ifdef VMS                  /* VMS:  required even for stdout! (final flush) */
1609    if (!uO.tflag)           /* don't close NULL file */
1610        close_outfile(__G);
1611#else
1612#ifdef DLL
1613    if (!uO.tflag && (!uO.cflag || G.redirect_data)) {
1614        if (G.redirect_data)
1615            FINISH_REDIRECT();
1616        else
1617            close_outfile(__G);
1618    }
1619#else
1620    if (!uO.tflag && !uO.cflag)   /* don't close NULL file or stdout */
1621        close_outfile(__G);
1622#endif
1623#endif /* VMS */
1624
1625            /* GRR: CONVERT close_outfile() TO NON-VOID:  CHECK FOR ERRORS! */
1626
1627
1628    if (G.disk_full) {            /* set by flush() */
1629        if (G.disk_full > 1) {
1630#if (defined(DELETE_IF_FULL) && defined(HAVE_UNLINK))
1631            /* delete the incomplete file if we can */
1632            if (unlink(G.filename) != 0)
1633                Trace((stderr, "extract.c:  could not delete %s\n",
1634                  FnFilter1(G.filename)));
1635#else
1636            /* warn user about the incomplete file */
1637            Info(slide, 0x421, ((char *)slide, LoadFarString(FileTruncated),
1638              FnFilter1(G.filename)));
1639#endif
1640            error = PK_DISK;
1641        } else {
1642            error = PK_WARN;
1643        }
1644    }
1645
1646    if (error > PK_WARN) {/* don't print redundant CRC error if error already */
1647        undefer_input(__G);
1648        return error;
1649    }
1650    if (G.crc32val != G.lrec.crc32) {
1651        /* if quiet enough, we haven't output the filename yet:  do it */
1652        if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
1653            Info(slide, 0x401, ((char *)slide, "%-22s ",
1654              FnFilter1(G.filename)));
1655        Info(slide, 0x401, ((char *)slide, LoadFarString(BadCRC), G.crc32val,
1656          G.lrec.crc32));
1657#if CRYPT
1658        if (G.pInfo->encrypted)
1659            Info(slide, 0x401, ((char *)slide, LoadFarString(MaybeBadPasswd)));
1660#endif
1661        error = PK_ERR;
1662    } else if (uO.tflag) {
1663#ifndef SFX
1664        if (G.extra_field) {
1665            if ((r = TestExtraField(__G__ G.extra_field,
1666                                    G.lrec.extra_field_length)) > error)
1667                error = r;
1668        } else
1669#endif /* !SFX */
1670        if (!uO.qflag)
1671            Info(slide, 0, ((char *)slide, " OK\n"));
1672    } else {
1673        if (QCOND2 && !error)   /* GRR:  is stdout reset to text mode yet? */
1674            Info(slide, 0, ((char *)slide, "\n"));
1675    }
1676
1677    undefer_input(__G);
1678    return error;
1679
1680} /* end function extract_or_test_member() */
1681
1682
1683
1684
1685
1686#ifndef SFX
1687
1688/*******************************/
1689/*  Function TestExtraField()  */
1690/*******************************/
1691
1692static int TestExtraField(__G__ ef, ef_len)
1693    __GDEF
1694    uch *ef;
1695    unsigned ef_len;
1696{
1697    ush ebID;
1698    unsigned ebLen;
1699    unsigned eb_cmpr_offs = 0;
1700    int r;
1701
1702    /* we know the regular compressed file data tested out OK, or else we
1703     * wouldn't be here ==> print filename if any extra-field errors found
1704     */
1705    while (ef_len >= EB_HEADSIZE) {
1706        ebID = makeword(ef);
1707        ebLen = (unsigned)makeword(ef+EB_LEN);
1708
1709        if (ebLen > (ef_len - EB_HEADSIZE)) {
1710           /* Discovered some extra field inconsistency! */
1711            if (uO.qflag)
1712                Info(slide, 1, ((char *)slide, "%-22s ",
1713                  FnFilter1(G.filename)));
1714            Info(slide, 1, ((char *)slide, LoadFarString(InconsistEFlength),
1715              ebLen, (ef_len - EB_HEADSIZE)));
1716            return PK_ERR;
1717        }
1718
1719        switch (ebID) {
1720            case EF_OS2:
1721            case EF_ACL:
1722            case EF_MAC3:
1723            case EF_BEOS:
1724                switch (ebID) {
1725                  case EF_OS2:
1726                  case EF_ACL:
1727                    eb_cmpr_offs = EB_OS2_HLEN;
1728                    break;
1729                  case EF_MAC3:
1730                    if (ebLen >= EB_MAC3_HLEN &&
1731                        (makeword(ef+(EB_HEADSIZE+EB_FLGS_OFFS))
1732                         & EB_M3_FL_UNCMPR) &&
1733                        (makelong(ef+EB_HEADSIZE) == ebLen - EB_MAC3_HLEN))
1734                        eb_cmpr_offs = 0;
1735                    else
1736                        eb_cmpr_offs = EB_MAC3_HLEN;
1737                    break;
1738                  case EF_BEOS:
1739                    if (ebLen >= EB_BEOS_HLEN &&
1740                        (*(ef+(EB_HEADSIZE+EB_FLGS_OFFS)) & EB_BE_FL_UNCMPR) &&
1741                        (makelong(ef+EB_HEADSIZE) == ebLen - EB_BEOS_HLEN))
1742                        eb_cmpr_offs = 0;
1743                    else
1744                        eb_cmpr_offs = EB_BEOS_HLEN;
1745                    break;
1746                }
1747                if ((r = test_compr_eb(__G__ ef, ebLen, eb_cmpr_offs, NULL))
1748                    != PK_OK) {
1749                    if (uO.qflag)
1750                        Info(slide, 1, ((char *)slide, "%-22s ",
1751                          FnFilter1(G.filename)));
1752                    switch (r) {
1753                        case IZ_EF_TRUNC:
1754                            Info(slide, 1, ((char *)slide,
1755                              LoadFarString(TruncEAs),
1756                              ebLen-(eb_cmpr_offs+EB_CMPRHEADLEN), "\n"));
1757                            break;
1758                        case PK_ERR:
1759                            Info(slide, 1, ((char *)slide,
1760                              LoadFarString(InvalidComprDataEAs)));
1761                            break;
1762                        case PK_MEM3:
1763                        case PK_MEM4:
1764                            Info(slide, 1, ((char *)slide,
1765                              LoadFarString(NotEnoughMemEAs)));
1766                            break;
1767                        default:
1768                            if ((r & 0xff) != PK_ERR)
1769                                Info(slide, 1, ((char *)slide,
1770                                  LoadFarString(UnknErrorEAs)));
1771                            else {
1772                                ush m = (ush)(r >> 8);
1773                                if (m == DEFLATED)            /* GRR KLUDGE! */
1774                                    Info(slide, 1, ((char *)slide,
1775                                      LoadFarString(BadCRC_EAs)));
1776                                else
1777                                    Info(slide, 1, ((char *)slide,
1778                                      LoadFarString(UnknComprMethodEAs), m));
1779                            }
1780                            break;
1781                    }
1782                    return r;
1783                }
1784                break;
1785
1786            case EF_NTSD:
1787                Trace((stderr, "ebID: %i / ebLen: %u\n", ebID, ebLen));
1788                r = ebLen < EB_NTSD_L_LEN ? IZ_EF_TRUNC :
1789                    ((ef[EB_HEADSIZE+EB_NTSD_VERSION] > EB_NTSD_MAX_VER) ?
1790                     (PK_WARN | 0x4000) :
1791                     test_compr_eb(__G__ ef, ebLen, EB_NTSD_L_LEN, TEST_NTSD));
1792                if (r != PK_OK) {
1793                    if (uO.qflag)
1794                        Info(slide, 1, ((char *)slide, "%-22s ",
1795                          FnFilter1(G.filename)));
1796                    switch (r) {
1797                        case IZ_EF_TRUNC:
1798                            Info(slide, 1, ((char *)slide,
1799                              LoadFarString(TruncNTSD),
1800                              ebLen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), "\n"));
1801                            break;
1802#if (defined(WIN32) && defined(NTSD_EAS))
1803                        case PK_WARN:
1804                            Info(slide, 1, ((char *)slide,
1805                              LoadFarString(InvalidSecurityEAs)));
1806                            break;
1807#endif
1808                        case PK_ERR:
1809                            Info(slide, 1, ((char *)slide,
1810                              LoadFarString(InvalidComprDataEAs)));
1811                            break;
1812                        case PK_MEM3:
1813                        case PK_MEM4:
1814                            Info(slide, 1, ((char *)slide,
1815                              LoadFarString(NotEnoughMemEAs)));
1816                            break;
1817                        case (PK_WARN | 0x4000):
1818                            Info(slide, 1, ((char *)slide,
1819                              LoadFarString(UnsuppNTSDVersEAs),
1820                              (int)ef[EB_HEADSIZE+EB_NTSD_VERSION]));
1821                            r = PK_WARN;
1822                            break;
1823                        default:
1824                            if ((r & 0xff) != PK_ERR)
1825                                Info(slide, 1, ((char *)slide,
1826                                  LoadFarString(UnknErrorEAs)));
1827                            else {
1828                                ush m = (ush)(r >> 8);
1829                                if (m == DEFLATED)            /* GRR KLUDGE! */
1830                                    Info(slide, 1, ((char *)slide,
1831                                      LoadFarString(BadCRC_EAs)));
1832                                else
1833                                    Info(slide, 1, ((char *)slide,
1834                                      LoadFarString(UnknComprMethodEAs), m));
1835                            }
1836                            break;
1837                    }
1838                    return r;
1839                }
1840                break;
1841            case EF_PKVMS:
1842                if (makelong(ef+EB_HEADSIZE) !=
1843                    crc32(CRCVAL_INITIAL, ef+(EB_HEADSIZE+4),
1844                          (extent)(ebLen-4)))
1845                    Info(slide, 1, ((char *)slide,
1846                      LoadFarString(BadCRC_EAs)));
1847                break;
1848            case EF_PKW32:
1849            case EF_PKUNIX:
1850            case EF_ASIUNIX:
1851            case EF_IZVMS:
1852            case EF_IZUNIX:
1853            case EF_VMCMS:
1854            case EF_MVS:
1855            case EF_SPARK:
1856            case EF_TANDEM:
1857            case EF_THEOS:
1858            case EF_AV:
1859            default:
1860                break;
1861        }
1862        ef_len -= (ebLen + EB_HEADSIZE);
1863        ef += (ebLen + EB_HEADSIZE);
1864    }
1865
1866    if (!uO.qflag)
1867        Info(slide, 0, ((char *)slide, " OK\n"));
1868
1869    return PK_COOL;
1870
1871} /* end function TestExtraField() */
1872
1873
1874
1875
1876
1877/******************************/
1878/*  Function test_compr_eb()  */
1879/******************************/
1880
1881#ifdef PROTO
1882static int test_compr_eb(
1883    __GPRO__
1884    uch *eb,
1885    unsigned eb_size,
1886    unsigned compr_offset,
1887    int (*test_uc_ebdata)(__GPRO__ uch *eb, unsigned eb_size,
1888                          uch *eb_ucptr, ulg eb_ucsize))
1889#else /* !PROTO */
1890static int test_compr_eb(__G__ eb, eb_size, compr_offset, test_uc_ebdata)
1891    __GDEF
1892    uch *eb;
1893    unsigned eb_size;
1894    unsigned compr_offset;
1895    int (*test_uc_ebdata)();
1896#endif /* ?PROTO */
1897{
1898    ulg eb_ucsize;
1899    uch *eb_ucptr;
1900    int r;
1901
1902    if (compr_offset < 4)                /* field is not compressed: */
1903        return PK_OK;                    /* do nothing and signal OK */
1904
1905    if ((eb_size < (EB_UCSIZE_P + 4)) ||
1906        ((eb_ucsize = makelong(eb+(EB_HEADSIZE+EB_UCSIZE_P))) > 0L &&
1907         eb_size <= (compr_offset + EB_CMPRHEADLEN)))
1908        return IZ_EF_TRUNC;               /* no compressed data! */
1909
1910    if ((eb_ucptr = (uch *)malloc((extent)eb_ucsize)) == (uch *)NULL)
1911        return PK_MEM4;
1912
1913    r = memextract(__G__ eb_ucptr, eb_ucsize,
1914                   eb + (EB_HEADSIZE + compr_offset),
1915                   (ulg)(eb_size - compr_offset));
1916
1917    if (r == PK_OK && test_uc_ebdata != NULL)
1918        r = (*test_uc_ebdata)(__G__ eb, eb_size, eb_ucptr, eb_ucsize);
1919
1920    free(eb_ucptr);
1921    return r;
1922
1923} /* end function test_compr_eb() */
1924
1925#endif /* !SFX */
1926
1927
1928
1929
1930
1931/***************************/
1932/*  Function memextract()  */
1933/***************************/
1934
1935int memextract(__G__ tgt, tgtsize, src, srcsize)  /* extract compressed */
1936    __GDEF                                        /*  extra field block; */
1937    uch *tgt;                                     /*  return PK-type error */
1938    ulg tgtsize;                                  /*  level */
1939    ZCONST uch *src;
1940    ulg srcsize;
1941{
1942    long old_csize=G.csize;
1943    uch *old_inptr=G.inptr;
1944    int  old_incnt=G.incnt;
1945    int  r, error=PK_OK;
1946    ush  method;
1947    ulg  extra_field_crc;
1948
1949
1950    method = makeword(src);
1951    extra_field_crc = makelong(src+2);
1952
1953    /* compressed extra field exists completely in memory at this location: */
1954    G.inptr = (uch *)src + (2 + 4);     /* method and extra_field_crc */
1955    G.incnt = (int)(G.csize = (long)(srcsize - (2 + 4)));
1956    G.mem_mode = TRUE;
1957    G.outbufptr = tgt;
1958    G.outsize = tgtsize;
1959
1960    switch (method) {
1961        case STORED:
1962            memcpy((char *)tgt, (char *)G.inptr, (extent)G.incnt);
1963            G.outcnt = G.csize;   /* for CRC calculation */
1964            break;
1965        case DEFLATED:
1966#ifdef USE_DEFLATE64
1967        case ENHDEFLATED:
1968#endif
1969            G.outcnt = 0L;
1970            if ((r = UZinflate(__G__ (method == ENHDEFLATED))) != 0) {
1971                if (!uO.tflag)
1972                    Info(slide, 0x401, ((char *)slide,
1973                      LoadFarStringSmall(ErrUnzipNoFile), r == 3?
1974                      LoadFarString(NotEnoughMem) :
1975                      LoadFarString(InvalidComprData),
1976                      LoadFarStringSmall2(Inflate)));
1977                error = (r == 3)? PK_MEM3 : PK_ERR;
1978            }
1979            if (G.outcnt == 0L)   /* inflate's final FLUSH sets outcnt */
1980                break;
1981            break;
1982        default:
1983            if (uO.tflag)
1984                error = PK_ERR | ((int)method << 8);
1985            else {
1986                Info(slide, 0x401, ((char *)slide,
1987                  LoadFarString(UnsupportedExtraField), method));
1988                error = PK_ERR;  /* GRR:  should be passed on up via SetEAs() */
1989            }
1990            break;
1991    }
1992
1993    G.inptr = old_inptr;
1994    G.incnt = old_incnt;
1995    G.csize = old_csize;
1996    G.mem_mode = FALSE;
1997
1998    if (!error) {
1999        register ulg crcval = crc32(CRCVAL_INITIAL, tgt, (extent)G.outcnt);
2000
2001        if (crcval != extra_field_crc) {
2002            if (uO.tflag)
2003                error = PK_ERR | (DEFLATED << 8);  /* kludge for now */
2004            else {
2005                Info(slide, 0x401, ((char *)slide,
2006                  LoadFarString(BadExtraFieldCRC), G.zipfn, crcval,
2007                  extra_field_crc));
2008                error = PK_ERR;
2009            }
2010        }
2011    }
2012    return error;
2013
2014} /* end function memextract() */
2015
2016
2017
2018
2019
2020/*************************/
2021/*  Function memflush()  */
2022/*************************/
2023
2024int memflush(__G__ rawbuf, size)
2025    __GDEF
2026    ZCONST uch *rawbuf;
2027    ulg size;
2028{
2029    if (size > G.outsize)
2030        /* Here, PK_DISK is a bit off-topic, but in the sense of marking
2031           "overflow of output space", its use may be tolerated. */
2032        return PK_DISK;   /* more data than output buffer can hold */
2033
2034
2035
2036    memcpy((char *)G.outbufptr, (char *)rawbuf, (extent)size);
2037    G.outbufptr += (unsigned int)size;
2038    G.outsize -= size;
2039    G.outcnt += size;
2040
2041    return 0;
2042
2043} /* end function memflush() */
2044
2045
2046
2047
2048
2049#if (defined(VMS) || defined(VMS_TEXT_CONV))
2050
2051/************************************/
2052/*  Function extract_izvms_block()  */
2053/************************************/
2054
2055/*
2056 * Extracts block from p. If resulting length is less then needed, fill
2057 * extra space with corresponding bytes from 'init'.
2058 * Currently understands 3 formats of block compression:
2059 * - Simple storing
2060 * - Compression of zero bytes to zero bits
2061 * - Deflation (see memextract())
2062 * The IZVMS block data is returned in malloc'd space.
2063 */
2064uch *extract_izvms_block(__G__ ebdata, size, retlen, init, needlen)
2065    __GDEF
2066    ZCONST uch *ebdata;
2067    unsigned size;
2068    unsigned *retlen;
2069    ZCONST uch *init;
2070    unsigned needlen;
2071{
2072    uch *ucdata;       /* Pointer to block allocated */
2073    int cmptype;
2074    unsigned usiz, csiz;
2075
2076    cmptype = (makeword(ebdata+EB_IZVMS_FLGS) & EB_IZVMS_BCMASK);
2077    csiz = size - EB_IZVMS_HLEN;
2078    usiz = (cmptype == EB_IZVMS_BCSTOR ?
2079            csiz : makeword(ebdata+EB_IZVMS_UCSIZ));
2080
2081    if (retlen)
2082        *retlen = usiz;
2083
2084    if ((ucdata = (uch *)malloc(MAX(needlen, usiz))) == NULL)
2085        return NULL;
2086
2087    if (init && (usiz < needlen))
2088        memcpy((char *)ucdata, (ZCONST char *)init, needlen);
2089
2090    switch (cmptype)
2091    {
2092        case EB_IZVMS_BCSTOR: /* The simplest case */
2093            memcpy(ucdata, ebdata+EB_IZVMS_HLEN, usiz);
2094            break;
2095        case EB_IZVMS_BC00:
2096            decompress_bits(ucdata, usiz, ebdata+EB_IZVMS_HLEN);
2097            break;
2098        case EB_IZVMS_BCDEFL:
2099            memextract(__G__ ucdata, (ulg)usiz,
2100                       ebdata+EB_IZVMS_HLEN, (ulg)csiz);
2101            break;
2102        default:
2103            free(ucdata);
2104            ucdata = NULL;
2105    }
2106    return ucdata;
2107
2108} /* end of extract_izvms_block */
2109
2110
2111
2112
2113
2114/********************************/
2115/*  Function decompress_bits()  */
2116/********************************/
2117/*
2118 *  Simple uncompression routine. The compression uses bit stream.
2119 *  Compression scheme:
2120 *
2121 *  if (byte!=0)
2122 *      putbit(1),putbyte(byte)
2123 *  else
2124 *      putbit(0)
2125 */
2126static void decompress_bits(outptr, needlen, bitptr)
2127    uch *outptr;        /* Pointer into output block */
2128    unsigned needlen;   /* Size of uncompressed block */
2129    ZCONST uch *bitptr; /* Pointer into compressed data */
2130{
2131    ulg bitbuf = 0;
2132    int bitcnt = 0;
2133
2134#define _FILL   {       bitbuf |= (*bitptr++) << bitcnt;\
2135                        bitcnt += 8;                    \
2136                }
2137
2138    while (needlen--)
2139    {
2140        if (bitcnt <= 0)
2141            _FILL;
2142
2143        if (bitbuf & 1)
2144        {
2145            bitbuf >>= 1;
2146            if ((bitcnt -= 1) < 8)
2147                _FILL;
2148            *outptr++ = (uch)bitbuf;
2149            bitcnt -= 8;
2150            bitbuf >>= 8;
2151        }
2152        else
2153        {
2154            *outptr++ = '\0';
2155            bitcnt -= 1;
2156            bitbuf >>= 1;
2157        }
2158    }
2159} /* end function decompress_bits() */
2160
2161#endif /* VMS || VMS_TEXT_CONV */
2162
2163
2164
2165
2166
2167/*************************/
2168/*  Function fnfilter()  */        /* here instead of in list.c for SFX */
2169/*************************/
2170
2171char *fnfilter(raw, space)         /* convert name to safely printable form */
2172    ZCONST char *raw;
2173    uch *space;
2174{
2175#ifndef NATIVE   /* ASCII:  filter ANSI escape codes, etc. */
2176    ZCONST uch *r=(ZCONST uch *)raw;
2177    uch *s=space;
2178
2179    while (*r) {
2180#ifdef QDOS
2181        if (qlflag & 2) {
2182            if (*r == '/' || *r == '.') {
2183                ++r;
2184                *s++ = '_';
2185                continue;
2186            }
2187        } else
2188#endif
2189        if (*r < 32) {
2190            *s++ = '^', *s++ = (uch)(64 + *r++);
2191        } else {
2192#ifdef _MBCS
2193            unsigned i;
2194            for (i = CLEN(r); i > 0; i--)
2195                *s++ = *r++;
2196#else
2197            *s++ = *r++;
2198#endif
2199         }
2200    }
2201    *s = '\0';
2202
2203#ifdef WINDLL
2204    INTERN_TO_ISO((char *)space, (char *)space);  /* translate to ANSI */
2205#else
2206#ifdef WIN32
2207    /* Win9x console always uses OEM character coding, and
2208       WinNT console is set to OEM charset by default, too */
2209    INTERN_TO_OEM((char *)space, (char *)space);
2210#endif /* WIN32 */
2211#endif /* ?WINDLL */
2212
2213    return (char *)space;
2214
2215#else /* NATIVE:  EBCDIC or whatever */
2216    return (char *)raw;
2217#endif
2218
2219} /* end function fnfilter() */
2220
2221
2222
2223
2224
2225#ifdef SET_DIR_ATTRIB
2226/* must sort saved directories so can set perms from bottom up */
2227
2228/************************/
2229/*  Function dircomp()  */
2230/************************/
2231
2232static int dircomp(a, b)   /* used by qsort(); swiped from Zip */
2233    ZCONST zvoid *a, *b;
2234{
2235    /* order is significant:  this sorts in reverse order (deepest first) */
2236    return strcmp((*(dirtime **)b)->fn, (*(dirtime **)a)->fn);
2237 /* return namecmp((*(dirtime **)b)->fn, (*(dirtime **)a)->fn); */
2238}
2239
2240
2241
2242#if 0   /* not used in Unix, but maybe for future OSes? */
2243
2244/************************/
2245/*  Function namecmp()  */
2246/************************/
2247
2248static int namecmp(s1, s2)   /* [not] used by dircomp(); swiped from Zip */
2249    ZCONST char *s1, *s2;
2250{
2251    int d;
2252
2253    for (;;) {
2254        d = (int)(uch)case_map(*s1)
2255          - (int)(uch)case_map(*s2);
2256
2257        if (d || *s1 == 0 || *s2 == 0)
2258            return d;
2259
2260        s1++;
2261        s2++;
2262    }
2263}
2264
2265#endif /* 0 */
2266#endif /* SET_DIR_ATTRIB */
2267