diff options
Diffstat (limited to 'Build/source/libs/unzip/extract.c')
-rw-r--r-- | Build/source/libs/unzip/extract.c | 1985 |
1 files changed, 1985 insertions, 0 deletions
diff --git a/Build/source/libs/unzip/extract.c b/Build/source/libs/unzip/extract.c new file mode 100644 index 00000000000..75ed7e0fd0e --- /dev/null +++ b/Build/source/libs/unzip/extract.c @@ -0,0 +1,1985 @@ +/*--------------------------------------------------------------------------- + + extract.c + + This file contains the high-level routines ("driver routines") for extrac- + ting and testing zipfile members. It calls the low-level routines in files + explode.c, inflate.c, unreduce.c and unshrink.c. + + Contains: extract_or_test_files() + store_info() + extract_or_test_member() + TestExtraField() + test_compr_eb() + memextract() + memflush() + fnfilter() + + ---------------------------------------------------------------------------*/ + + +#define EXTRACT_C +#define UNZIP_INTERNAL +#include "unzip.h" +#include "crypt.h" +#ifdef WINDLL +# ifdef POCKET_UNZIP +# include "wince/intrface.h" +# else +# include "windll/windll.h" +# endif +#endif + +#define GRRDUMP(buf,len) { \ + int i, j; \ + \ + for (j = 0; j < (len)/16; ++j) { \ + printf(" "); \ + for (i = 0; i < 16; ++i) \ + printf("%02x ", (uch)(buf)[i+(j<<4)]); \ + printf("\n "); \ + for (i = 0; i < 16; ++i) { \ + char c = (char)(buf)[i+(j<<4)]; \ + \ + if (c == '\n') \ + printf("\\n "); \ + else if (c == '\r') \ + printf("\\r "); \ + else \ + printf(" %c ", c); \ + } \ + printf("\n"); \ + } \ + if ((len) % 16) { \ + printf(" "); \ + for (i = j<<4; i < (len); ++i) \ + printf("%02x ", (uch)(buf)[i]); \ + printf("\n "); \ + for (i = j<<4; i < (len); ++i) { \ + char c = (char)(buf)[i]; \ + \ + if (c == '\n') \ + printf("\\n "); \ + else if (c == '\r') \ + printf("\\r "); \ + else \ + printf(" %c ", c); \ + } \ + printf("\n"); \ + } \ +} + +static int store_info OF((__GPRO)); +static int extract_or_test_member OF((__GPRO)); +#ifndef SFX + static int TestExtraField OF((__GPRO__ uch *ef, unsigned ef_len)); + static int test_compr_eb OF((__GPRO__ uch *eb, unsigned eb_size, + unsigned compr_offset, + int (*test_uc_ebdata)(__GPRO__ uch *eb, unsigned eb_size, + uch *eb_ucptr, ulg eb_ucsize))); +#endif +#ifdef SET_DIR_ATTRIB + static int dircomp OF((ZCONST zvoid *a, ZCONST zvoid *b)); +#endif + + + +/*******************************/ +/* Strings used in extract.c */ +/*******************************/ + +static ZCONST char Far VersionMsg[] = + " skipping: %-22s need %s compat. v%u.%u (can do v%u.%u)\n"; +static ZCONST char Far ComprMsgNum[] = + " skipping: %-22s unsupported compression method %u\n"; +#ifndef SFX + static ZCONST char Far ComprMsgName[] = + " skipping: %-22s `%s' method not supported\n"; + static ZCONST char Far CmprNone[] = "store"; + static ZCONST char Far CmprShrink[] = "shrink"; + static ZCONST char Far CmprReduce[] = "reduce"; + static ZCONST char Far CmprImplode[] = "implode"; + static ZCONST char Far CmprTokenize[] = "tokenize"; + static ZCONST char Far CmprDeflate[] = "deflate"; + static ZCONST char Far CmprEnDeflate[] = "enhanced deflate"; + static ZCONST char Far CmprDCLImplode[] = "DCL implode"; + static ZCONST char Far *ComprNames[NUM_METHODS] = { + CmprNone, CmprShrink, CmprReduce, CmprReduce, CmprReduce, CmprReduce, + CmprImplode, CmprTokenize, CmprDeflate, CmprEnDeflate, CmprDCLImplode + }; +#endif /* !SFX */ +static ZCONST char Far FilNamMsg[] = + "%s: bad filename length (%s)\n"; +static ZCONST char Far ExtFieldMsg[] = + "%s: bad extra field length (%s)\n"; +static ZCONST char Far OffsetMsg[] = + "file #%u: bad zipfile offset (%s): %ld\n"; +static ZCONST char Far ExtractMsg[] = + "%8sing: %-22s %s%s"; +#ifndef SFX + static ZCONST char Far LengthMsg[] = + "%s %s: %ld bytes required to uncompress to %lu bytes;\n %s\ + supposed to require %lu bytes%s%s%s\n"; +#endif + +static ZCONST char Far BadFileCommLength[] = "%s: bad file comment length\n"; +static ZCONST char Far LocalHdrSig[] = "local header sig"; +static ZCONST char Far BadLocalHdr[] = "file #%u: bad local header\n"; +static ZCONST char Far AttemptRecompensate[] = + " (attempting to re-compensate)\n"; +#ifndef SFX + static ZCONST char Far BackslashPathSep[] = + "warning: %s appears to use backslashes as path separators\n"; +#endif +static ZCONST char Far SkipVolumeLabel[] = + " skipping: %-22s %svolume label\n"; + +#ifdef SET_DIR_ATTRIB /* messages of code for setting directory attributes */ + static ZCONST char Far DirlistEntryNoMem[] = + "warning: cannot alloc memory for dir times/permissions/UID/GID\n"; + static ZCONST char Far DirlistSortNoMem[] = + "warning: cannot alloc memory to sort dir times/perms/etc.\n"; + static ZCONST char Far DirlistSetAttrFailed[] = + "warning: set times/attribs failed for %s\n"; +#endif + +#ifndef WINDLL + static ZCONST char Far ReplaceQuery[] = + "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: "; + static ZCONST char Far AssumeNone[] = " NULL\n(assuming [N]one)\n"; + static ZCONST char Far NewNameQuery[] = "new name: "; + static ZCONST char Far InvalidResponse[] = "error: invalid response [%c]\n"; +#endif /* !WINDLL */ + +static ZCONST char Far ErrorInArchive[] = + "At least one %serror was detected in %s.\n"; +static ZCONST char Far ZeroFilesTested[] = + "Caution: zero files tested in %s.\n"; + +#ifndef VMS + static ZCONST char Far VMSFormatQuery[] = + "\n%s: stored in VMS format. Extract anyway? (y/n) "; +#endif + +#if CRYPT + static ZCONST char Far SkipCannotGetPasswd[] = + " skipping: %-22s unable to get password\n"; + static ZCONST char Far SkipIncorrectPasswd[] = + " skipping: %-22s incorrect password\n"; + static ZCONST char Far FilesSkipBadPasswd[] = + "%u file%s skipped because of incorrect password.\n"; + static ZCONST char Far MaybeBadPasswd[] = + " (may instead be incorrect password)\n"; +#else + static ZCONST char Far SkipEncrypted[] = + " skipping: %-22s encrypted (not supported)\n"; +#endif + +static ZCONST char Far NoErrInCompData[] = + "No errors detected in compressed data of %s.\n"; +static ZCONST char Far NoErrInTestedFiles[] = + "No errors detected in %s for the %u file%s tested.\n"; +static ZCONST char Far FilesSkipped[] = + "%u file%s skipped because of unsupported compression or encoding.\n"; + +static ZCONST char Far ErrUnzipFile[] = " error: %s%s %s\n"; +static ZCONST char Far ErrUnzipNoFile[] = "\n error: %s%s\n"; +static ZCONST char Far NotEnoughMem[] = "not enough memory to "; +static ZCONST char Far InvalidComprData[] = "invalid compressed data to "; +static ZCONST char Far Inflate[] = "inflate"; + +#ifndef SFX + static ZCONST char Far Explode[] = "explode"; +#ifndef LZW_CLEAN + static ZCONST char Far Unshrink[] = "unshrink"; +#endif +#endif + +#if (!defined(DELETE_IF_FULL) || !defined(HAVE_UNLINK)) + static ZCONST char Far FileTruncated[] = + "warning: %s is probably truncated\n"; +#endif + +static ZCONST char Far FileUnknownCompMethod[] = + "%s: unknown compression method\n"; +static ZCONST char Far BadCRC[] = " bad CRC %08lx (should be %08lx)\n"; + + /* TruncEAs[] also used in OS/2 mapname(), close_outfile() */ +char ZCONST Far TruncEAs[] = " compressed EA data missing (%d bytes)%s"; +char ZCONST Far TruncNTSD[] = + " compressed WinNT security data missing (%d bytes)%s"; + +#ifndef SFX + static ZCONST char Far InconsistEFlength[] = "bad extra-field entry:\n \ + EF block length (%u bytes) exceeds remaining EF data (%u bytes)\n"; + static ZCONST char Far InvalidComprDataEAs[] = + " invalid compressed data for EAs\n"; +# if (defined(WIN32) && defined(NTSD_EAS)) + static ZCONST char Far InvalidSecurityEAs[] = + " EAs fail security check\n"; +# endif + static ZCONST char Far UnsuppNTSDVersEAs[] = + " unsupported NTSD EAs version %d\n"; + static ZCONST char Far BadCRC_EAs[] = " bad CRC for extended attributes\n"; + static ZCONST char Far UnknComprMethodEAs[] = + " unknown compression method for EAs (%u)\n"; + static ZCONST char Far NotEnoughMemEAs[] = + " out of memory while inflating EAs\n"; + static ZCONST char Far UnknErrorEAs[] = + " unknown error on extended attributes\n"; +#endif /* !SFX */ + +static ZCONST char Far UnsupportedExtraField[] = + "\nerror: unsupported extra-field compression type (%u)--skipping\n"; +static ZCONST char Far BadExtraFieldCRC[] = + "error [%s]: bad extra-field CRC %08lx (should be %08lx)\n"; + + + + + +/**************************************/ +/* Function extract_or_test_files() */ +/**************************************/ + +int extract_or_test_files(__G) /* return PK-type error code */ + __GDEF +{ + uch *cd_inptr; + unsigned i, j, filnum=0, blknum=0; + int cd_incnt, renamed, query; + int error, error_in_archive=PK_COOL, *fn_matched=NULL, *xn_matched=NULL; +#ifdef WINDLL + int done_once = 0; +#else + extent len; +#endif + unsigned members_remaining, num_skipped=0, num_bad_pwd=0; + long cd_bufstart, bufstart, inbuf_offset, request; + LONGINT old_extra_bytes = 0L; +#ifdef SET_DIR_ATTRIB + unsigned num_dirs=0; + dirtime *dirlist=(dirtime *)NULL, **sorted_dirlist=(dirtime **)NULL; +#endif + + +/*--------------------------------------------------------------------------- + The basic idea of this function is as follows. Since the central di- + rectory lies at the end of the zipfile and the member files lie at the + beginning or middle or wherever, it is not very desirable to simply + read a central directory entry, jump to the member and extract it, and + then jump back to the central directory. In the case of a large zipfile + this would lead to a whole lot of disk-grinding, especially if each mem- + ber file is small. Instead, we read from the central directory the per- + tinent information for a block of files, then go extract/test the whole + block. Thus this routine contains two small(er) loops within a very + large outer loop: the first of the small ones reads a block of files + from the central directory; the second extracts or tests each file; and + the outer one loops over blocks. There's some file-pointer positioning + stuff in between, but that's about it. Btw, it's because of this jump- + ing around that we can afford to be lenient if an error occurs in one of + the member files: we should still be able to go find the other members, + since we know the offset of each from the beginning of the zipfile. + ---------------------------------------------------------------------------*/ + + G.pInfo = G.info; + members_remaining = (unsigned)G.ecrec.total_entries_central_dir; + +#if CRYPT + G.newzip = TRUE; +#endif +#ifndef SFX + G.reported_backslash = FALSE; +#endif + + /* malloc space for check on unmatched filespecs (OK if one or both NULL) */ + if (G.filespecs > 0 && + (fn_matched=(int *)malloc(G.filespecs*sizeof(int))) != (int *)NULL) + for (i = 0; i < G.filespecs; ++i) + fn_matched[i] = FALSE; + if (G.xfilespecs > 0 && + (xn_matched=(int *)malloc(G.xfilespecs*sizeof(int))) != (int *)NULL) + for (i = 0; i < G.xfilespecs; ++i) + xn_matched[i] = FALSE; + +/*--------------------------------------------------------------------------- + Begin main loop over blocks of member files. We know the entire central + directory is on this disk: we would not have any of this information un- + less the end-of-central-directory record was on this disk, and we would + not have gotten to this routine unless this is also the disk on which + the central directory starts. In practice, this had better be the ONLY + disk in the archive, but we'll add multi-disk support soon. + ---------------------------------------------------------------------------*/ + + while (members_remaining) { + j = 0; +#ifdef AMIGA + memzero(G.filenotes, DIR_BLKSIZ * sizeof(char *)); +#endif + + /* + * Loop through files in central directory, storing offsets, file + * attributes, case-conversion and text-conversion flags until block + * size is reached. + */ + + while (members_remaining && (j < DIR_BLKSIZ)) { + --members_remaining; + G.pInfo = &G.info[j]; + + if (readbuf(__G__ G.sig, 4) == 0) { + error_in_archive = PK_EOF; + members_remaining = 0; /* ...so no more left to do */ + break; + } + if (strncmp(G.sig, central_hdr_sig, 4)) { /* just to make sure */ + Info(slide, 0x401, ((char *)slide, LoadFarString(CentSigMsg), + j + blknum*DIR_BLKSIZ + 1)); + Info(slide, 0x401, ((char *)slide, LoadFarString(ReportMsg))); + error_in_archive = PK_BADERR; + members_remaining = 0; /* ...so no more left to do */ + break; + } + /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag */ + if ((error = process_cdir_file_hdr(__G)) != PK_COOL) { + error_in_archive = error; /* only PK_EOF defined */ + members_remaining = 0; /* ...so no more left to do */ + break; + } + if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) != + PK_COOL) + { + if (error > error_in_archive) + error_in_archive = error; + if (error > PK_WARN) { /* fatal: no more left to do */ + Info(slide, 0x401, ((char *)slide, LoadFarString(FilNamMsg), + FnFilter1(G.filename), "central")); + members_remaining = 0; + break; + } + } + if ((error = do_string(__G__ G.crec.extra_field_length, + EXTRA_FIELD)) != 0) + { + if (error > error_in_archive) + error_in_archive = error; + if (error > PK_WARN) { /* fatal */ + Info(slide, 0x401, ((char *)slide, + LoadFarString(ExtFieldMsg), + FnFilter1(G.filename), "central")); + members_remaining = 0; + break; + } + } +#ifdef AMIGA + G.filenote_slot = j; + if ((error = do_string(__G__ G.crec.file_comment_length, + uO.N_flag ? FILENOTE : SKIP)) != PK_COOL) +#else + if ((error = do_string(__G__ G.crec.file_comment_length, SKIP)) + != PK_COOL) +#endif + { + if (error > error_in_archive) + error_in_archive = error; + if (error > PK_WARN) { /* fatal */ + Info(slide, 0x421, ((char *)slide, + LoadFarString(BadFileCommLength), + FnFilter1(G.filename))); + members_remaining = 0; + break; + } + } + if (G.process_all_files) { + if (store_info(__G)) + ++j; /* file is OK; info[] stored; continue with next */ + else + ++num_skipped; + } else { + int do_this_file; + + if (G.filespecs == 0) + do_this_file = TRUE; + else { /* check if this entry matches an `include' argument */ + do_this_file = FALSE; + for (i = 0; i < G.filespecs; i++) + if (match(G.filename, G.pfnames[i], uO.C_flag)) { + do_this_file = TRUE; /* ^-- ignore case or not? */ + if (fn_matched) + fn_matched[i] = TRUE; + break; /* found match, so stop looping */ + } + } + if (do_this_file) { /* check if this is an excluded file */ + for (i = 0; i < G.xfilespecs; i++) + if (match(G.filename, G.pxnames[i], uO.C_flag)) { + do_this_file = FALSE; /* ^-- ignore case or not? */ + if (xn_matched) + xn_matched[i] = TRUE; + break; + } + } + if (do_this_file) { + if (store_info(__G)) + ++j; /* file is OK */ + else + ++num_skipped; /* unsupp. compression or encryption */ + } + } /* end if (process_all_files) */ + + + } /* end while-loop (adding files to current block) */ + + /* save position in central directory so can come back later */ + cd_bufstart = G.cur_zipfile_bufstart; + cd_inptr = G.inptr; + cd_incnt = G.incnt; + + /*----------------------------------------------------------------------- + Second loop: process files in current block, extracting or testing + each one. + -----------------------------------------------------------------------*/ + + for (i = 0; i < j; ++i) { + filnum++; /* filnum = i + blknum*DIR_BLKSIZ + 1; */ + G.pInfo = &G.info[i]; +#ifdef NOVELL_BUG_FAILSAFE + G.dne = FALSE; /* assume file exists until stat() says otherwise */ +#endif + + /* if the target position is not within the current input buffer + * (either haven't yet read far enough, or (maybe) skipping back- + * ward), skip to the target position and reset readbuf(). */ + + /* ZLSEEK(pInfo->offset): */ + request = G.pInfo->offset + G.extra_bytes; + inbuf_offset = request % INBUFSIZ; + bufstart = request - inbuf_offset; + + Trace((stderr, "\ndebug: request = %ld, inbuf_offset = %ld\n", + request, inbuf_offset)); + Trace((stderr, + "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n", + bufstart, G.cur_zipfile_bufstart)); + if (request < 0) { + Info(slide, 0x401, ((char *)slide, LoadFarStringSmall(SeekMsg), + G.zipfn, LoadFarString(ReportMsg))); + error_in_archive = PK_ERR; + if (filnum == 1 && G.extra_bytes != 0L) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(AttemptRecompensate))); + old_extra_bytes = G.extra_bytes; + G.extra_bytes = 0L; + request = G.pInfo->offset; /* could also check if != 0 */ + inbuf_offset = request % INBUFSIZ; + bufstart = request - inbuf_offset; + Trace((stderr, "debug: request = %ld, inbuf_offset = %ld\n", + request, inbuf_offset)); + Trace((stderr, + "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n", + bufstart, G.cur_zipfile_bufstart)); + } else { + error_in_archive = PK_BADERR; + continue; /* this one hosed; try next */ + } + } + /* try again */ + if (request < 0) { + Trace((stderr, "debug: recompensated request still < 0\n")); + Info(slide, 0x401, ((char *)slide, LoadFarStringSmall(SeekMsg), + G.zipfn, LoadFarString(ReportMsg))); + error_in_archive = PK_BADERR; + continue; + } else if (bufstart != G.cur_zipfile_bufstart) { + Trace((stderr, "debug: bufstart != cur_zipfile_bufstart\n")); +#ifdef USE_STRM_INPUT + fseek((FILE *)G.zipfd,(LONGINT)bufstart,SEEK_SET); + G.cur_zipfile_bufstart = ftell((FILE *)G.zipfd); +#else /* !USE_STRM_INPUT */ + G.cur_zipfile_bufstart = + lseek(G.zipfd,(LONGINT)bufstart,SEEK_SET); +#endif /* ?USE_STRM_INPUT */ + if ((G.incnt = read(G.zipfd,(char *)G.inbuf,INBUFSIZ)) <= 0) + { + Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg), + filnum, "lseek", bufstart)); + error_in_archive = PK_BADERR; + continue; /* can still do next file */ + } + G.inptr = G.inbuf + (int)inbuf_offset; + G.incnt -= (int)inbuf_offset; + } else { + G.incnt += (int)(G.inptr-G.inbuf) - (int)inbuf_offset; + G.inptr = G.inbuf + (int)inbuf_offset; + } + + /* should be in proper position now, so check for sig */ + if (readbuf(__G__ G.sig, 4) == 0) { /* bad offset */ + Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg), + filnum, "EOF", request)); + error_in_archive = PK_BADERR; + continue; /* but can still try next one */ + } + if (strncmp(G.sig, local_hdr_sig, 4)) { + Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg), + filnum, LoadFarStringSmall(LocalHdrSig), request)); + /* + GRRDUMP(G.sig, 4) + GRRDUMP(local_hdr_sig, 4) + */ + error_in_archive = PK_ERR; + if ((filnum == 1 && G.extra_bytes != 0L) || + (G.extra_bytes == 0L && old_extra_bytes != 0L)) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(AttemptRecompensate))); + if (G.extra_bytes) { + old_extra_bytes = G.extra_bytes; + G.extra_bytes = 0L; + } else + G.extra_bytes = old_extra_bytes; /* third attempt */ + ZLSEEK(G.pInfo->offset) + if (readbuf(__G__ G.sig, 4) == 0) { /* bad offset */ + Info(slide, 0x401, ((char *)slide, + LoadFarString(OffsetMsg), filnum, "EOF", request)); + error_in_archive = PK_BADERR; + continue; /* but can still try next one */ + } + if (strncmp(G.sig, local_hdr_sig, 4)) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(OffsetMsg), filnum, + LoadFarStringSmall(LocalHdrSig), request)); + error_in_archive = PK_BADERR; + continue; + } + } else + continue; /* this one hosed; try next */ + } + if ((error = process_local_file_hdr(__G)) != PK_COOL) { + Info(slide, 0x421, ((char *)slide, LoadFarString(BadLocalHdr), + filnum)); + error_in_archive = error; /* only PK_EOF defined */ + continue; /* can still try next one */ + } + if ((error = do_string(__G__ G.lrec.filename_length, DS_FN)) != + PK_COOL) + { + if (error > error_in_archive) + error_in_archive = error; + if (error > PK_WARN) { + Info(slide, 0x401, ((char *)slide, LoadFarString(FilNamMsg), + FnFilter1(G.filename), "local")); + continue; /* go on to next one */ + } + } + if (G.extra_field != (uch *)NULL) { + free(G.extra_field); + G.extra_field = (uch *)NULL; + } + if ((error = + do_string(__G__ G.lrec.extra_field_length, EXTRA_FIELD)) != 0) + { + if (error > error_in_archive) + error_in_archive = error; + if (error > PK_WARN) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(ExtFieldMsg), + FnFilter1(G.filename), "local")); + continue; /* go on */ + } + } + +#if CRYPT + if (G.pInfo->encrypted && + (error = decrypt(__G__ uO.pwdarg)) != PK_COOL) { + if (error == PK_WARN) { + if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) + Info(slide, 0x401, ((char *)slide, + LoadFarString(SkipIncorrectPasswd), + FnFilter1(G.filename))); + ++num_bad_pwd; + } else { /* (error > PK_WARN) */ + if (error > error_in_archive) + error_in_archive = error; + Info(slide, 0x401, ((char *)slide, + LoadFarString(SkipCannotGetPasswd), + FnFilter1(G.filename))); + } + continue; /* go on to next file */ + } +#endif /* CRYPT */ + + /* + * just about to extract file: if extracting to disk, check if + * already exists, and if so, take appropriate action according to + * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper + * loop because we don't store the possibly renamed filename[] in + * info[]) + */ +#ifdef DLL + if (!uO.tflag && !uO.cflag && !G.redirect_data) +#else + if (!uO.tflag && !uO.cflag) +#endif + { + renamed = FALSE; /* user hasn't renamed output file yet */ + +startover: + query = FALSE; + /* for files from DOS FAT, check for use of backslash instead + * of slash as directory separator (bug in some zipper(s); so + * far, not a problem in HPFS, NTFS or VFAT systems) + */ +#ifndef SFX + if (G.pInfo->hostnum == FS_FAT_ && !strchr(G.filename, '/')) { + char *p=G.filename-1; + + while (*++p) { + if (*p == '\\') { + if (!G.reported_backslash) { + Info(slide, 0x21, ((char *)slide, + LoadFarString(BackslashPathSep), G.zipfn)); + G.reported_backslash = TRUE; + if (!error_in_archive) + error_in_archive = PK_WARN; + } + *p = '/'; + } + } + } +#endif /* !SFX */ + + /* mapname can create dirs if not freshening or if renamed */ + if ((error = mapname(__G__ renamed)) > PK_WARN) { + if (error == IZ_CREATED_DIR) { +#ifdef SET_DIR_ATTRIB + dirtime *d_entry; + + d_entry = (dirtime *)malloc(sizeof(dirtime)); + if (d_entry == (dirtime *)NULL) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(DirlistEntryNoMem))); + } else { + unsigned eb_izux_flg; + + d_entry->next = dirlist; + dirlist = d_entry; + dirlist->fn = + (char *)malloc(strlen(G.filename) + 1); + if (dirlist->fn == (char *)NULL) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(DirlistEntryNoMem))); + dirlist = d_entry->next; + free(d_entry); + if (!error_in_archive) + error_in_archive = PK_WARN; + continue; + } + strcpy(dirlist->fn, G.filename); + dirlist->perms = G.pInfo->file_attr; +#ifdef USE_EF_UT_TIME + eb_izux_flg = G.extra_field? ef_scan_for_izux( + G.extra_field, G.lrec.extra_field_length, 0, + G.lrec.last_mod_dos_datetime, +#ifdef IZ_CHECK_TZ + (G.tz_is_valid ? &(dirlist->u.t3) : NULL), +#else + &(dirlist->u.t3), +#endif + dirlist->uidgid) + : 0; +#else /* !USE_EF_UT_TIME */ + eb_izux_flg = 0; +#endif /* ?USE_EF_UT_TIME */ + if (eb_izux_flg & EB_UT_FL_MTIME) { + TTrace((stderr, + "\nextract: Unix dir e.f. modtime = %ld\n", + dirlist->u.t3.mtime)); + } else { + dirlist->u.t3.mtime = dos_to_unix_time( + G.lrec.last_mod_dos_datetime); + } + if (eb_izux_flg & EB_UT_FL_ATIME) { + TTrace((stderr, + "\nextract: Unix dir e.f. actime = %ld\n", + dirlist->u.t3.atime)); + } else { + dirlist->u.t3.atime = + dirlist->u.t3.mtime; + } + dirlist->have_uidgid = + (uO.X_flag && (eb_izux_flg & EB_UX2_VALID)); + ++num_dirs; + } +#endif /* SET_DIR_ATTRIB */ + } else if (error == IZ_VOL_LABEL) { +#ifdef DOS_OS2_W32 + Info(slide, 0x401, ((char *)slide, + LoadFarString(SkipVolumeLabel), + FnFilter1(G.filename), + uO.volflag? "hard disk " : "")); +#else + Info(slide, 1, ((char *)slide, + LoadFarString(SkipVolumeLabel), + FnFilter1(G.filename), "")); +#endif + /* if (!error_in_archive) + error_in_archive = PK_WARN; */ + } else if (error > PK_ERR && error_in_archive < PK_ERR) + error_in_archive = PK_ERR; + Trace((stderr, "mapname(%s) returns error = %d\n", + FnFilter1(G.filename), error)); + continue; /* go on to next file */ + } + +#ifdef QDOS + QFilename(__G__ G.filename); +#endif + switch (check_for_newer(__G__ G.filename)) { + case DOES_NOT_EXIST: +#ifdef NOVELL_BUG_FAILSAFE + G.dne = TRUE; /* stat() says file DOES NOT EXIST */ +#endif + /* if freshening, don't skip if just renamed */ + if (uO.fflag && !renamed) + continue; /* freshen (no new files): skip */ + break; + case EXISTS_AND_OLDER: + if (uO.overwrite_none) { +#ifdef WINDLL + char szStr[FILNAMSIZ+40]; /* add. space for text */ + + if ((!G.prompt_always) || (done_once)) { + sprintf(szStr, + "Target file exists.\nSkipping %s\n", + FnFilter1(G.filename)); + win_fprintf((zvoid *)&G, stdout, + strlen(szStr), szStr); + } else { + query = TRUE; + break; + } +#endif /* WINDLL */ + continue; /* never overwrite: skip file */ + } +#ifdef UNIXBACKUP + if (!uO.overwrite_all && !uO.B_flag) +#else + if (!uO.overwrite_all) +#endif + query = TRUE; + break; + case EXISTS_AND_NEWER: /* (or equal) */ + if (uO.overwrite_none || (uO.uflag && !renamed)) { +#ifdef WINDLL + char szStr[FILNAMSIZ+40]; /* add. space for text */ + + if ((!G.prompt_always) || (done_once)) { + sprintf(szStr, + "Target file newer.\nSkipping %s\n", + FnFilter1(G.filename)); + win_fprintf((zvoid *)&G, stdout, + strlen(szStr), szStr); + } else { + query = TRUE; + break; + } +#endif /* WINDLL */ + continue; /* skip if update/freshen & orig name */ + } +#ifdef UNIXBACKUP + if (!uO.overwrite_all && !uO.B_flag) +#else + if (!uO.overwrite_all) +#endif + query = TRUE; + break; + } + if (query) { +#ifdef WINDLL + switch (G.lpUserFunctions->replace != NULL ? + (*G.lpUserFunctions->replace)(G.filename) : + IDM_REPLACE_NONE) { + case IDM_REPLACE_RENAME: + _ISO_INTERN(G.filename); + renamed = TRUE; + goto startover; + case IDM_REPLACE_YES: + break; + case IDM_REPLACE_ALL: + uO.overwrite_all = TRUE; + uO.overwrite_none = FALSE; /* just to make sure */ + break; + case IDM_REPLACE_NONE: + uO.overwrite_none = TRUE; + uO.overwrite_all = FALSE; /* make sure */ + done_once = TRUE; + /* FALL THROUGH, skip */ + case IDM_REPLACE_NO: + { + char szStr[FILNAMSIZ+40]; + + sprintf(szStr, + "Target file newer.\nSkipping %s\n", + FnFilter1(G.filename)); + win_fprintf((zvoid *)&G, stdout, + strlen(szStr), szStr); + } + continue; + } +#else /* !WINDLL */ +reprompt: + Info(slide, 0x81, ((char *)slide, + LoadFarString(ReplaceQuery), + FnFilter1(G.filename))); + if (fgets(G.answerbuf, 9, stdin) == (char *)NULL) { + Info(slide, 1, ((char *)slide, + LoadFarString(AssumeNone))); + *G.answerbuf = 'N'; + if (!error_in_archive) + error_in_archive = 1; /* not extracted: warning */ + } + switch (*G.answerbuf) { + case 'A': /* dangerous option: force caps */ + uO.overwrite_all = TRUE; + uO.overwrite_none = FALSE; /* just to make sure */ + break; + case 'r': + case 'R': + do { + Info(slide, 0x81, ((char *)slide, + LoadFarString(NewNameQuery))); + fgets(G.filename, FILNAMSIZ, stdin); + /* usually get \n here: better check for it */ + len = strlen(G.filename); + if (G.filename[len-1] == '\n') + G.filename[--len] = '\0'; + } while (len == 0); +#ifdef WIN32 /* WIN32 fgets( ... , stdin) returns OEM coded strings */ + _OEM_INTERN(G.filename); +#endif + renamed = TRUE; + goto startover; /* sorry for a goto */ + case 'y': + case 'Y': + break; + case 'N': + uO.overwrite_none = TRUE; + uO.overwrite_all = FALSE; /* make sure */ + /* FALL THROUGH, skip */ + case 'n': + continue; /* skip file */ + default: + Info(slide, 1, ((char *)slide, + LoadFarString(InvalidResponse), *G.answerbuf)); + goto reprompt; /* yet another goto? */ + } /* end switch (*answerbuf) */ +#endif /* ?WINDLL */ + } /* end if (query) */ + } /* end if (extracting to disk) */ + +#ifdef DLL + if ((G.statreportcb != NULL) && + (*G.statreportcb)(__G__ UZ_ST_START_EXTRACT, G.zipfn, + G.filename, NULL)) { + if (fn_matched) + free((zvoid *)fn_matched); + if (xn_matched) + free((zvoid *)xn_matched); + return IZ_CTRLC; /* cancel operation by user request */ + } +#endif +#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */ + UserStop(); +#endif +#ifdef AMIGA + G.filenote_slot = i; +#endif + G.disk_full = 0; + if ((error = extract_or_test_member(__G)) != PK_COOL) { + if (error > error_in_archive) + error_in_archive = error; /* ...and keep going */ +#ifdef DLL + if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) { +#else + if (G.disk_full > 1) { +#endif + if (fn_matched) + free((zvoid *)fn_matched); + if (xn_matched) + free((zvoid *)xn_matched); + return error_in_archive; /* (unless disk full) */ + } + } +#ifdef DLL + if ((G.statreportcb != NULL) && + (*G.statreportcb)(__G__ UZ_ST_FINISH_MEMBER, G.zipfn, + G.filename, (zvoid *)&G.lrec.ucsize)) { + if (fn_matched) + free((zvoid *)fn_matched); + if (xn_matched) + free((zvoid *)xn_matched); + return IZ_CTRLC; /* cancel operation by user request */ + } +#endif +#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */ + UserStop(); +#endif + } /* end for-loop (i: files in current block) */ + + + /* + * Jump back to where we were in the central directory, then go and do + * the next batch of files. + */ + +#ifdef USE_STRM_INPUT + fseek((FILE *)G.zipfd, (LONGINT)cd_bufstart, SEEK_SET); + G.cur_zipfile_bufstart = ftell((FILE *)G.zipfd); +#else /* !USE_STRM_INPUT */ + G.cur_zipfile_bufstart = lseek(G.zipfd,(LONGINT)cd_bufstart,SEEK_SET); +#endif /* ?USE_STRM_INPUT */ + read(G.zipfd, (char *)G.inbuf, INBUFSIZ); /* been here before... */ + G.inptr = cd_inptr; + G.incnt = cd_incnt; + ++blknum; + +#ifdef TEST + printf("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart, cd_bufstart); + printf("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart, + cur_zipfile_bufstart); + printf("inptr-inbuf = %d\n", G.inptr-G.inbuf); + printf("incnt = %d\n\n", G.incnt); +#endif + + } /* end while-loop (blocks of files in central directory) */ + +/*--------------------------------------------------------------------------- + Go back through saved list of directories, sort and set times/perms/UIDs + and GIDs from the deepest level on up. + ---------------------------------------------------------------------------*/ + +#ifdef SET_DIR_ATTRIB + if (num_dirs > 0) { + sorted_dirlist = (dirtime **)malloc(num_dirs*sizeof(dirtime *)); + if (sorted_dirlist == (dirtime **)NULL) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(DirlistSortNoMem))); + while (dirlist != (dirtime *)NULL) { + dirtime *d = dirlist; + + dirlist = dirlist->next; + free(d); + } + } else { + if (num_dirs == 1) + sorted_dirlist[0] = dirlist; + else { + for (i = 0; i < num_dirs; ++i) { + sorted_dirlist[i] = dirlist; + dirlist = dirlist->next; + } + qsort((char *)sorted_dirlist, num_dirs, sizeof(dirtime *), + dircomp); + } + + Trace((stderr, "setting directory times/perms/attributes\n")); + for (i = 0; i < num_dirs; ++i) { + dirtime *d = sorted_dirlist[i]; + + Trace((stderr, "dir = %s\n", d->fn)); + if ((error = set_direc_attribs(__G__ d)) != PK_OK) { + Info(slide, 0x201, ((char *)slide, + LoadFarString(DirlistSetAttrFailed), d->fn)); + if (!error_in_archive) + error_in_archive = error; + } + free(d->fn); + free(d); + } + free(sorted_dirlist); + } + } +#endif /* SET_DIR_ATTRIB */ + +#if (defined(WIN32) && defined(NTSD_EAS)) + process_defer_NT(__G); /* process any deferred items for this .zip file */ +#endif + +/*--------------------------------------------------------------------------- + Check for unmatched filespecs on command line and print warning if any + found. Free allocated memory. + ---------------------------------------------------------------------------*/ + + if (fn_matched) { + for (i = 0; i < G.filespecs; ++i) + if (!fn_matched[i]) { +#ifdef DLL + if (!G.redirect_data && !G.redirect_text) + Info(slide, 0x401, ((char *)slide, + LoadFarString(FilenameNotMatched), G.pfnames[i])); + else + setFileNotFound(__G); +#else + Info(slide, 1, ((char *)slide, + LoadFarString(FilenameNotMatched), G.pfnames[i])); +#endif + if (error_in_archive <= PK_WARN) + error_in_archive = PK_FIND; /* some files not found */ + } + free((zvoid *)fn_matched); + } + if (xn_matched) { + for (i = 0; i < G.xfilespecs; ++i) + if (!xn_matched[i]) + Info(slide, 0x401, ((char *)slide, + LoadFarString(ExclFilenameNotMatched), G.pxnames[i])); + free((zvoid *)xn_matched); + } + +/*--------------------------------------------------------------------------- + Double-check that we're back at the end-of-central-directory record, and + print quick summary of results, if we were just testing the archive. We + send the summary to stdout so that people doing the testing in the back- + ground and redirecting to a file can just do a "tail" on the output file. + ---------------------------------------------------------------------------*/ + +#ifndef SFX + if (readbuf(__G__ G.sig, 4) == 0) + error_in_archive = PK_EOF; + if (strncmp(G.sig, end_central_sig, 4)) { /* just to make sure */ + Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg))); + Info(slide, 0x401, ((char *)slide, LoadFarString(ReportMsg))); + if (!error_in_archive) /* don't overwrite stronger error */ + error_in_archive = PK_WARN; + } +#endif /* !SFX */ + if (uO.tflag) { + unsigned num = filnum - num_bad_pwd; + + if (uO.qflag < 2) { /* GRR 930710: was (uO.qflag == 1) */ + if (error_in_archive) + Info(slide, 0, ((char *)slide, LoadFarString(ErrorInArchive), + (error_in_archive == 1)? "warning-" : "", G.zipfn)); + else if (num == 0) + Info(slide, 0, ((char *)slide, LoadFarString(ZeroFilesTested), + G.zipfn)); + else if (G.process_all_files && (num_skipped+num_bad_pwd == 0)) + Info(slide, 0, ((char *)slide, LoadFarString(NoErrInCompData), + G.zipfn)); + else + Info(slide, 0, ((char *)slide, LoadFarString(NoErrInTestedFiles) + , G.zipfn, num, (num==1)? "":"s")); + if (num_skipped > 0) + Info(slide, 0, ((char *)slide, LoadFarString(FilesSkipped), + num_skipped, (num_skipped==1)? "":"s")); +#if CRYPT + if (num_bad_pwd > 0) + Info(slide, 0, ((char *)slide, LoadFarString(FilesSkipBadPasswd) + , num_bad_pwd, (num_bad_pwd==1)? "":"s")); +#endif /* CRYPT */ + } else if ((uO.qflag == 0) && !error_in_archive && (num == 0)) + Info(slide, 0, ((char *)slide, LoadFarString(ZeroFilesTested), + G.zipfn)); + } + + /* give warning if files not tested or extracted (first condition can still + * happen if zipfile is empty and no files specified on command line) */ + + if ((filnum == 0) && error_in_archive <= PK_WARN) { + if (num_skipped > 0) + error_in_archive = IZ_UNSUP; /* unsupport. compression/encryption */ + else + error_in_archive = PK_FIND; /* no files found at all */ + } +#if CRYPT + else if ((filnum == num_bad_pwd) && error_in_archive <= PK_WARN) + error_in_archive = IZ_BADPWD; /* bad passwd => all files skipped */ +#endif + else if ((num_skipped > 0) && error_in_archive <= PK_WARN) + error_in_archive = IZ_UNSUP; /* was PK_WARN; Jean-loup complained */ +#if CRYPT + else if ((num_bad_pwd > 0) && !error_in_archive) + error_in_archive = PK_WARN; +#endif + + return error_in_archive; + +} /* end function extract_or_test_files() */ + + + + + +/***************************/ +/* Function store_info() */ +/***************************/ + +static int store_info(__G) /* return 0 if skipping, 1 if OK */ + __GDEF +{ +#ifdef SFX +# define UNKN_COMPR \ + (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED) +#else +# ifdef COPYRIGHT_CLEAN /* no reduced files */ +# define UNKN_RED (G.crec.compression_method >= REDUCED1 && \ + G.crec.compression_method <= REDUCED4) +# else +# define UNKN_RED FALSE /* reducing not unknown */ +# endif +# ifdef LZW_CLEAN /* no shrunk files */ +# define UNKN_SHR (G.crec.compression_method == SHRUNK) +# else +# define UNKN_SHR FALSE /* unshrinking not unknown */ +# endif +# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \ + G.crec.compression_method==TOKENIZED || G.crec.compression_method>DEFLATED) +#endif + +/*--------------------------------------------------------------------------- + Check central directory info for version/compatibility requirements. + ---------------------------------------------------------------------------*/ + + G.pInfo->encrypted = G.crec.general_purpose_bit_flag & 1; /* bit field */ + G.pInfo->ExtLocHdr = (G.crec.general_purpose_bit_flag & 8) == 8; /* bit */ + G.pInfo->textfile = G.crec.internal_file_attributes & 1; /* bit field */ + G.pInfo->crc = G.crec.crc32; + G.pInfo->compr_size = G.crec.csize; + G.pInfo->uncompr_size = G.crec.ucsize; + + switch (uO.aflag) { + case 0: + G.pInfo->textmode = FALSE; /* bit field */ + break; + case 1: + G.pInfo->textmode = G.pInfo->textfile; /* auto-convert mode */ + break; + default: /* case 2: */ + G.pInfo->textmode = TRUE; + break; + } + + if (G.crec.version_needed_to_extract[1] == VMS_) { + if (G.crec.version_needed_to_extract[0] > VMS_UNZIP_VERSION) { + if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) + Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg), + FnFilter1(G.filename), "VMS", + G.crec.version_needed_to_extract[0] / 10, + G.crec.version_needed_to_extract[0] % 10, + VMS_UNZIP_VERSION / 10, VMS_UNZIP_VERSION % 10)); + return 0; + } +#ifndef VMS /* won't be able to use extra field, but still have data */ + else if (!uO.tflag && !uO.overwrite_all) { /* if -o, extract anyway */ + Info(slide, 0x481, ((char *)slide, LoadFarString(VMSFormatQuery), + FnFilter1(G.filename))); + fgets(G.answerbuf, 9, stdin); + if ((*G.answerbuf != 'y') && (*G.answerbuf != 'Y')) + return 0; + } +#endif /* !VMS */ + /* usual file type: don't need VMS to extract */ + } else if (G.crec.version_needed_to_extract[0] > UNZIP_VERSION) { + if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) + Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg), + FnFilter1(G.filename), "PK", + G.crec.version_needed_to_extract[0] / 10, + G.crec.version_needed_to_extract[0] % 10, + UNZIP_VERSION / 10, UNZIP_VERSION % 10)); + return 0; + } + + if UNKN_COMPR { + if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) { +#ifndef SFX + if (G.crec.compression_method < NUM_METHODS) + Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgName), + FnFilter1(G.filename), + LoadFarStringSmall(ComprNames[G.crec.compression_method]))); + else +#endif + Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgNum), + FnFilter1(G.filename), + G.crec.compression_method)); + } + return 0; + } +#if (!CRYPT) + if (G.pInfo->encrypted) { + if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) + Info(slide, 0x401, ((char *)slide, LoadFarString(SkipEncrypted), + FnFilter1(G.filename))); + return 0; + } +#endif /* !CRYPT */ + + /* map whatever file attributes we have into the local format */ + mapattr(__G); /* GRR: worry about return value later */ + + G.pInfo->offset = (long)G.crec.relative_offset_local_header; + return 1; + +} /* end function store_info() */ + + + + + +/***************************************/ +/* Function extract_or_test_member() */ +/***************************************/ + +static int extract_or_test_member(__G) /* return PK-type error code */ + __GDEF +{ + char *nul="[empty] ", *txt="[text] ", *bin="[binary]"; +#ifdef CMS_MVS + char *ebc="[ebcdic]"; +#endif + register int b; + int r, error=PK_COOL; +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) + ulg wsize; +#else +# define wsize WSIZE +#endif + + +/*--------------------------------------------------------------------------- + Initialize variables, buffers, etc. + ---------------------------------------------------------------------------*/ + + G.bits_left = 0; + G.bitbuf = 0L; /* unreduce and unshrink only */ + G.zipeof = 0; + G.newfile = TRUE; + G.crc32val = CRCVAL_INITIAL; + +#ifdef SYMLINKS + /* if file came from Unix and is a symbolic link and we are extracting + * to disk, prepare to restore the link */ + if (S_ISLNK(G.pInfo->file_attr) && + (G.pInfo->hostnum == UNIX_ || G.pInfo->hostnum == ATARI_ || + G.pInfo->hostnum == BEOS_) && + !uO.tflag && !uO.cflag && (G.lrec.ucsize > 0)) + G.symlnk = TRUE; + else + G.symlnk = FALSE; +#endif /* SYMLINKS */ + + if (uO.tflag) { + if (!uO.qflag) + Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), "test", + FnFilter1(G.filename), "", "")); + } else { +#ifdef DLL + if (uO.cflag && !G.redirect_data) +#else + if (uO.cflag) +#endif + { +#if (defined(OS2) && defined(__IBMC__) && (__IBMC__ >= 200)) + G.outfile = freopen("", "wb", stdout); /* VAC++ ignores setmode */ +#else + G.outfile = stdout; +#endif +#ifdef DOS_FLX_H68_OS2_W32 +#if (defined(__HIGHC__) && !defined(FLEXOS)) + setmode(G.outfile, _BINARY); +#else /* !(defined(__HIGHC__) && !defined(FLEXOS)) */ + setmode(fileno(G.outfile), O_BINARY); +#endif /* ?(defined(__HIGHC__) && !defined(FLEXOS)) */ +# define NEWLINE "\r\n" +#else /* !DOS_FLX_H68_OS2_W32 */ +# define NEWLINE "\n" +#endif /* ?DOS_FLX_H68_OS2_W32 */ +#ifdef VMS + if (open_outfile(__G)) /* VMS: required even for stdout! */ + return PK_DISK; +#endif + } else if (open_outfile(__G)) + return PK_DISK; + } + +/*--------------------------------------------------------------------------- + Unpack the file. + ---------------------------------------------------------------------------*/ + + defer_leftover_input(__G); /* so NEXTBYTE bounds check will work */ + switch (G.lrec.compression_method) { + case STORED: + if (!uO.tflag && QCOND2) { +#ifdef SYMLINKS + if (G.symlnk) /* can also be deflated, but rarer... */ + Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), + "link", FnFilter1(G.filename), "", "")); + else +#endif /* SYMLINKS */ + Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), + "extract", FnFilter1(G.filename), + (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)? + "" : (G.lrec.ucsize == 0L? nul : (G.pInfo->textfile? txt : + bin)), uO.cflag? NEWLINE : "")); + } +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) + if (G.redirect_slide) { + wsize = G.redirect_size; redirSlide = G.redirect_buffer; + } else { + wsize = WSIZE; redirSlide = slide; + } +#endif + G.outptr = redirSlide; + G.outcnt = 0L; + while ((b = NEXTBYTE) != EOF && !G.disk_full) { + *G.outptr++ = (uch)b; + if (++G.outcnt == wsize) { + flush(__G__ redirSlide, G.outcnt, 0); + G.outptr = redirSlide; + G.outcnt = 0L; + } + } + if (G.outcnt) /* flush final (partial) buffer */ + flush(__G__ redirSlide, G.outcnt, 0); + break; + +#ifndef SFX +#ifndef LZW_CLEAN + case SHRUNK: + if (!uO.tflag && QCOND2) { + Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), + LoadFarStringSmall(Unshrink), FnFilter1(G.filename), + (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)? + "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : "")); + } + if ((r = unshrink(__G)) != PK_COOL) { + if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)) + Info(slide, 0x401, ((char *)slide, + LoadFarStringSmall(ErrUnzipFile), + LoadFarString(NotEnoughMem), + LoadFarStringSmall2(Unshrink), + FnFilter1(G.filename))); + else + Info(slide, 0x401, ((char *)slide, + LoadFarStringSmall(ErrUnzipNoFile), + LoadFarString(NotEnoughMem), + LoadFarStringSmall2(Unshrink))); + error = r; + } + break; +#endif /* !LZW_CLEAN */ + +#ifndef COPYRIGHT_CLEAN + case REDUCED1: + case REDUCED2: + case REDUCED3: + case REDUCED4: + if (!uO.tflag && QCOND2) { + Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), + "unreduc", FnFilter1(G.filename), + (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)? + "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : "")); + } + unreduce(__G); + break; +#endif /* !COPYRIGHT_CLEAN */ + + case IMPLODED: + if (!uO.tflag && QCOND2) { + Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), + "explod", FnFilter1(G.filename), + (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)? + "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : "")); + } + if (((r = explode(__G)) != 0) && (r != 5)) { /* treat 5 specially */ + if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)) + Info(slide, 0x401, ((char *)slide, + LoadFarStringSmall(ErrUnzipFile), r == 3? + LoadFarString(NotEnoughMem) : + LoadFarString(InvalidComprData), + LoadFarStringSmall2(Explode), + FnFilter1(G.filename))); + else + Info(slide, 0x401, ((char *)slide, + LoadFarStringSmall(ErrUnzipNoFile), r == 3? + LoadFarString(NotEnoughMem) : + LoadFarString(InvalidComprData), + LoadFarStringSmall2(Explode))); + error = (r == 3)? PK_MEM3 : PK_ERR; + } + if (r == 5) { + int warning = ((ulg)G.used_csize <= G.lrec.csize); + + if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)) + Info(slide, 0x401, ((char *)slide, LoadFarString(LengthMsg), + "", warning? "warning" : "error", G.used_csize, + G.lrec.ucsize, warning? " " : "", G.lrec.csize, + " [", FnFilter1(G.filename), "]")); + else + Info(slide, 0x401, ((char *)slide, LoadFarString(LengthMsg), + "\n", warning? "warning" : "error", G.used_csize, + G.lrec.ucsize, warning? " ":"", G.lrec.csize, + "", "", ".")); + error = warning? PK_WARN : PK_ERR; + } + break; +#endif /* !SFX */ + + case DEFLATED: + if (!uO.tflag && QCOND2) { + Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), + "inflat", FnFilter1(G.filename), + (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)? + "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : "")); + } +#ifndef USE_ZLIB /* zlib's function is called inflate(), too */ +# define UZinflate inflate +#endif + if ((r = UZinflate(__G)) != 0) { + if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)) + Info(slide, 0x401, ((char *)slide, + LoadFarStringSmall(ErrUnzipFile), r == 3? + LoadFarString(NotEnoughMem) : + LoadFarString(InvalidComprData), + LoadFarStringSmall2(Inflate), + FnFilter1(G.filename))); + else + Info(slide, 0x401, ((char *)slide, + LoadFarStringSmall(ErrUnzipNoFile), r == 3? + LoadFarString(NotEnoughMem) : + LoadFarString(InvalidComprData), + LoadFarStringSmall2(Inflate))); + error = (r == 3)? PK_MEM3 : PK_ERR; + } + break; + + default: /* should never get to this point */ + Info(slide, 0x401, ((char *)slide, + LoadFarString(FileUnknownCompMethod), FnFilter1(G.filename))); + /* close and delete file before return? */ + undefer_input(__G); + return PK_WARN; + + } /* end switch (compression method) */ + +/*--------------------------------------------------------------------------- + Close the file and set its date and time (not necessarily in that order), + and make sure the CRC checked out OK. Logical-AND the CRC for 64-bit + machines (redundant on 32-bit machines). + ---------------------------------------------------------------------------*/ + +#ifdef VMS /* VMS: required even for stdout! (final flush) */ + if (!uO.tflag) /* don't close NULL file */ + close_outfile(__G); +#else +#ifdef DLL + if (!uO.tflag && (!uO.cflag || G.redirect_data)) { + if (G.redirect_data) + FINISH_REDIRECT(); + else + close_outfile(__G); + } +#else + if (!uO.tflag && !uO.cflag) /* don't close NULL file or stdout */ + close_outfile(__G); +#endif +#endif /* VMS */ + + /* GRR: CONVERT close_outfile() TO NON-VOID: CHECK FOR ERRORS! */ + + + if (G.disk_full) { /* set by flush() */ + if (G.disk_full > 1) { +#if (defined(DELETE_IF_FULL) && defined(HAVE_UNLINK)) + /* delete the incomplete file if we can */ + if (unlink(G.filename) != 0) + Trace((stderr, "extract.c: could not delete %s\n", + FnFilter1(G.filename))); +#else + /* warn user about the incomplete file */ + Info(slide, 0x421, ((char *)slide, LoadFarString(FileTruncated), + FnFilter1(G.filename))); +#endif + error = PK_DISK; + } else { + error = PK_WARN; + } + } + + if (error > PK_WARN) {/* don't print redundant CRC error if error already */ + undefer_input(__G); + return error; + } + if (G.crc32val != G.lrec.crc32) { + /* if quiet enough, we haven't output the filename yet: do it */ + if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)) + Info(slide, 0x401, ((char *)slide, "%-22s ", + FnFilter1(G.filename))); + Info(slide, 0x401, ((char *)slide, LoadFarString(BadCRC), G.crc32val, + G.lrec.crc32)); +#if CRYPT + if (G.pInfo->encrypted) + Info(slide, 0x401, ((char *)slide, LoadFarString(MaybeBadPasswd))); +#endif + error = PK_ERR; + } else if (uO.tflag) { +#ifndef SFX + if (G.extra_field) { + if ((r = TestExtraField(__G__ G.extra_field, + G.lrec.extra_field_length)) > error) + error = r; + } else +#endif /* !SFX */ + if (!uO.qflag) + Info(slide, 0, ((char *)slide, " OK\n")); + } else { + if (QCOND2 && !error) /* GRR: is stdout reset to text mode yet? */ + Info(slide, 0, ((char *)slide, "\n")); + } + + undefer_input(__G); + return error; + +} /* end function extract_or_test_member() */ + + + + + +#ifndef SFX + +/*******************************/ +/* Function TestExtraField() */ +/*******************************/ + +static int TestExtraField(__G__ ef, ef_len) + __GDEF + uch *ef; + unsigned ef_len; +{ + ush ebID; + unsigned ebLen; + unsigned eb_cmpr_offs = 0; + int r; + + /* we know the regular compressed file data tested out OK, or else we + * wouldn't be here ==> print filename if any extra-field errors found + */ + while (ef_len >= EB_HEADSIZE) { + ebID = makeword(ef); + ebLen = (unsigned)makeword(ef+EB_LEN); + + if (ebLen > (ef_len - EB_HEADSIZE)) { + /* Discovered some extra field inconsistency! */ + if (uO.qflag) + Info(slide, 1, ((char *)slide, "%-22s ", + FnFilter1(G.filename))); + Info(slide, 1, ((char *)slide, LoadFarString(InconsistEFlength), + ebLen, (ef_len - EB_HEADSIZE))); + return PK_ERR; + } + + switch (ebID) { + case EF_OS2: + case EF_ACL: + case EF_MAC3: + case EF_BEOS: + switch (ebID) { + case EF_OS2: + case EF_ACL: + eb_cmpr_offs = EB_OS2_HLEN; + break; + case EF_MAC3: + if (ebLen >= EB_MAC3_HLEN && + (makeword(ef+(EB_HEADSIZE+EB_FLGS_OFFS)) + & EB_M3_FL_UNCMPR) && + (makelong(ef+EB_HEADSIZE) == ebLen - EB_MAC3_HLEN)) + eb_cmpr_offs = 0; + else + eb_cmpr_offs = EB_MAC3_HLEN; + break; + case EF_BEOS: + if (ebLen >= EB_BEOS_HLEN && + (*(ef+(EB_HEADSIZE+EB_FLGS_OFFS)) & EB_BE_FL_UNCMPR) && + (makelong(ef+EB_HEADSIZE) == ebLen - EB_BEOS_HLEN)) + eb_cmpr_offs = 0; + else + eb_cmpr_offs = EB_BEOS_HLEN; + break; + } + if ((r = test_compr_eb(__G__ ef, ebLen, eb_cmpr_offs, NULL)) + != PK_OK) { + if (uO.qflag) + Info(slide, 1, ((char *)slide, "%-22s ", + FnFilter1(G.filename))); + switch (r) { + case IZ_EF_TRUNC: + Info(slide, 1, ((char *)slide, + LoadFarString(TruncEAs), + ebLen-(eb_cmpr_offs+EB_CMPRHEADLEN), "\n")); + break; + case PK_ERR: + Info(slide, 1, ((char *)slide, + LoadFarString(InvalidComprDataEAs))); + break; + case PK_MEM3: + case PK_MEM4: + Info(slide, 1, ((char *)slide, + LoadFarString(NotEnoughMemEAs))); + break; + default: + if ((r & 0xff) != PK_ERR) + Info(slide, 1, ((char *)slide, + LoadFarString(UnknErrorEAs))); + else { + ush m = (ush)(r >> 8); + if (m == DEFLATED) /* GRR KLUDGE! */ + Info(slide, 1, ((char *)slide, + LoadFarString(BadCRC_EAs))); + else + Info(slide, 1, ((char *)slide, + LoadFarString(UnknComprMethodEAs), m)); + } + break; + } + return r; + } + break; + + case EF_NTSD: + Trace((stderr, "ebID: %i / ebLen: %u\n", ebID, ebLen)); + r = ebLen < EB_NTSD_L_LEN ? IZ_EF_TRUNC : + ((ef[EB_HEADSIZE+EB_NTSD_VERSION] > EB_NTSD_MAX_VER) ? + (PK_WARN | 0x4000) : + test_compr_eb(__G__ ef, ebLen, EB_NTSD_L_LEN, TEST_NTSD)); + if (r != PK_OK) { + if (uO.qflag) + Info(slide, 1, ((char *)slide, "%-22s ", + FnFilter1(G.filename))); + switch (r) { + case IZ_EF_TRUNC: + Info(slide, 1, ((char *)slide, + LoadFarString(TruncNTSD), + ebLen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), "\n")); + break; +#if (defined(WIN32) && defined(NTSD_EAS)) + case PK_WARN: + Info(slide, 1, ((char *)slide, + LoadFarString(InvalidSecurityEAs))); + break; +#endif + case PK_ERR: + Info(slide, 1, ((char *)slide, + LoadFarString(InvalidComprDataEAs))); + break; + case PK_MEM3: + case PK_MEM4: + Info(slide, 1, ((char *)slide, + LoadFarString(NotEnoughMemEAs))); + break; + case (PK_WARN | 0x4000): + Info(slide, 1, ((char *)slide, + LoadFarString(UnsuppNTSDVersEAs), + (int)ef[EB_HEADSIZE+EB_NTSD_VERSION])); + r = PK_WARN; + break; + default: + if ((r & 0xff) != PK_ERR) + Info(slide, 1, ((char *)slide, + LoadFarString(UnknErrorEAs))); + else { + ush m = (ush)(r >> 8); + if (m == DEFLATED) /* GRR KLUDGE! */ + Info(slide, 1, ((char *)slide, + LoadFarString(BadCRC_EAs))); + else + Info(slide, 1, ((char *)slide, + LoadFarString(UnknComprMethodEAs), m)); + } + break; + } + return r; + } + break; + case EF_PKVMS: + case EF_PKW32: + case EF_PKUNIX: + case EF_ASIUNIX: + case EF_IZVMS: + case EF_IZUNIX: + case EF_VMCMS: + case EF_MVS: + case EF_SPARK: + case EF_AV: + default: + break; + } + ef_len -= (ebLen + EB_HEADSIZE); + ef += (ebLen + EB_HEADSIZE); + } + + if (!uO.qflag) + Info(slide, 0, ((char *)slide, " OK\n")); + + return PK_COOL; + +} /* end function TestExtraField() */ + + + + + +/******************************/ +/* Function test_compr_eb() */ +/******************************/ + +#ifdef PROTO +static int test_compr_eb( + __GPRO__ + uch *eb, + unsigned eb_size, + unsigned compr_offset, + int (*test_uc_ebdata)(__GPRO__ uch *eb, unsigned eb_size, + uch *eb_ucptr, ulg eb_ucsize)) +#else /* !PROTO */ +static int test_compr_eb(__G__ eb, eb_size, compr_offset, test_uc_ebdata) + __GDEF + uch *eb; + unsigned eb_size; + unsigned compr_offset; + int (*test_uc_ebdata)(); +#endif /* ?PROTO */ +{ + ulg eb_ucsize; + uch *eb_ucptr; + int r; + + if (compr_offset < 4) /* field is not compressed: */ + return PK_OK; /* do nothing and signal OK */ + + if ((eb_size < (EB_UCSIZE_P + 4)) || + ((eb_ucsize = makelong(eb+(EB_HEADSIZE+EB_UCSIZE_P))) > 0L && + eb_size <= (compr_offset + EB_CMPRHEADLEN))) + return IZ_EF_TRUNC; /* no compressed data! */ + + if ((eb_ucptr = (uch *)malloc((extent)eb_ucsize)) == (uch *)NULL) + return PK_MEM4; + + r = memextract(__G__ eb_ucptr, eb_ucsize, + eb + (EB_HEADSIZE + compr_offset), + (ulg)(eb_size - compr_offset)); + + if (r == PK_OK && test_uc_ebdata != NULL) + r = (*test_uc_ebdata)(__G__ eb, eb_size, eb_ucptr, eb_ucsize); + + free(eb_ucptr); + return r; + +} /* end function test_compr_eb() */ + +#endif /* !SFX */ + + + + + +/***************************/ +/* Function memextract() */ +/***************************/ + +int memextract(__G__ tgt, tgtsize, src, srcsize) /* extract compressed */ + __GDEF /* extra field block; */ + uch *tgt, *src; /* return PK-type error */ + ulg tgtsize, srcsize; /* level */ +{ + long old_csize=G.csize; + uch *old_inptr=G.inptr; + int old_incnt=G.incnt; + int r, error=PK_OK; + ush method; + ulg extra_field_crc; + + + method = makeword(src); + extra_field_crc = makelong(src+2); + + /* compressed extra field exists completely in memory at this location: */ + G.inptr = src + 2 + 4; /* method and extra_field_crc */ + G.incnt = (int)(G.csize = (long)(srcsize - (2 + 4))); + G.mem_mode = TRUE; + G.outbufptr = tgt; + G.outsize = tgtsize; + + switch (method) { + case STORED: + memcpy((char *)tgt, (char *)G.inptr, (extent)G.incnt); + G.outcnt = G.csize; /* for CRC calculation */ + break; + case DEFLATED: + G.outcnt = 0L; + if ((r = UZinflate(__G)) != 0) { + if (!uO.tflag) + Info(slide, 0x401, ((char *)slide, + LoadFarStringSmall(ErrUnzipNoFile), r == 3? + LoadFarString(NotEnoughMem) : + LoadFarString(InvalidComprData), + LoadFarStringSmall2(Inflate))); + error = (r == 3)? PK_MEM3 : PK_ERR; + } + if (G.outcnt == 0L) /* inflate's final FLUSH sets outcnt */ + break; + break; + default: + if (uO.tflag) + error = PK_ERR | ((int)method << 8); + else { + Info(slide, 0x401, ((char *)slide, + LoadFarString(UnsupportedExtraField), method)); + error = PK_ERR; /* GRR: should be passed on up via SetEAs() */ + } + break; + } + + G.inptr = old_inptr; + G.incnt = old_incnt; + G.csize = old_csize; + G.mem_mode = FALSE; + + if (!error) { + register ulg crcval = crc32(CRCVAL_INITIAL, tgt, (extent)G.outcnt); + + if (crcval != extra_field_crc) { + if (uO.tflag) + error = PK_ERR | (DEFLATED << 8); /* kludge for now */ + else { + Info(slide, 0x401, ((char *)slide, + LoadFarString(BadExtraFieldCRC), G.zipfn, crcval, + extra_field_crc)); + error = PK_ERR; + } + } + } + return error; + +} /* end function memextract() */ + + + + + +/*************************/ +/* Function memflush() */ +/*************************/ + +int memflush(__G__ rawbuf, size) + __GDEF + uch *rawbuf; + ulg size; +{ + if (size > G.outsize) + return 50; /* more data than output buffer can hold */ + + memcpy((char *)G.outbufptr, (char *)rawbuf, (extent)size); + G.outbufptr += (unsigned int)size; + G.outsize -= size; + G.outcnt += size; + + return 0; + +} /* end function memflush() */ + + + + + +/*************************/ +/* Function fnfilter() */ /* here instead of in list.c for SFX */ +/*************************/ + +char *fnfilter(raw, space) /* convert name to safely printable form */ + ZCONST char *raw; + uch *space; +{ +#ifndef NATIVE /* ASCII: filter ANSI escape codes, etc. */ + uch *r=(uch *)raw, *s=space; + + while (*r) { +#ifdef QDOS + if (qlflag & 2) { + if (*r == '/' || *r == '.') { + ++r; + *s++ = '_'; + continue; + } + } else +#endif + if (*r < 32) + *s++ = '^', *s++ = (uch)(64 + *r++); + else + *s++ = *r++; + } + *s = 0; + +#ifdef WINDLL + INTERN_TO_ISO((char *)space, (char *)space); /* translate to ANSI */ +#else +#ifdef WIN32 + /* Win9x console always uses OEM character coding, and + WinNT console is set to OEM charset by default, too */ + INTERN_TO_OEM((char *)space, (char *)space); +#endif /* WIN32 */ +#endif /* ?WINDLL */ + + return (char *)space; + +#else /* NATIVE: EBCDIC or whatever */ + return (char *)raw; +#endif + +} /* end function fnfilter() */ + + + + + +#ifdef SET_DIR_ATTRIB +/* must sort saved directories so can set perms from bottom up */ + +/************************/ +/* Function dircomp() */ +/************************/ + +static int dircomp(a, b) /* used by qsort(); swiped from Zip */ + ZCONST zvoid *a, *b; +{ + /* order is significant: this sorts in reverse order (deepest first) */ + return strcmp((*(dirtime **)b)->fn, (*(dirtime **)a)->fn); + /* return namecmp((*(dirtime **)b)->fn, (*(dirtime **)a)->fn); */ +} + + + +#if 0 /* not used in Unix, but maybe for future OSes? */ + +/************************/ +/* Function namecmp() */ +/************************/ + +static int namecmp(s1, s2) /* [not] used by dircomp(); swiped from Zip */ + ZCONST char *s1, *s2; +{ + int d; + + for (;;) { + d = (int)(uch)case_map(*s1) + - (int)(uch)case_map(*s2); + + if (d || *s1 == 0 || *s2 == 0) + return d; + + s1++; + s2++; + } +} + +#endif /* 0 */ +#endif /* SET_DIR_ATTRIB */ |