1 /*---------------------------------------------------------------------------
5 This file contains the high-level routines ("driver routines") for extrac-
6 ting and testing zipfile members. It calls the low-level routines in files
7 explode.c, inflate.c, unreduce.c and unshrink.c.
9 Contains: extract_or_test_files()
11 extract_or_test_member()
18 ---------------------------------------------------------------------------*/
22 #define UNZIP_INTERNAL
27 # include "wince/intrface.h"
29 # include "windll/windll.h"
33 #define GRRDUMP(buf,len) { \
36 for (j = 0; j < (len)/16; ++j) { \
38 for (i = 0; i < 16; ++i) \
39 pipeit("%02x ", (uch)(buf)[i+(j<<4)]); \
41 for (i = 0; i < 16; ++i) { \
42 char c = (char)(buf)[i+(j<<4)]; \
55 for (i = j<<4; i < (len); ++i) \
56 pipeit("%02x ", (uch)(buf)[i]); \
58 for (i = j<<4; i < (len); ++i) { \
59 char c = (char)(buf)[i]; \
72 static int store_info
OF((__GPRO
));
73 static int extract_or_test_member
OF((__GPRO
));
75 static int TestExtraField
OF((__GPRO__ uch
*ef
, unsigned ef_len
));
76 static int test_compr_eb
OF((__GPRO__ uch
*eb
, unsigned eb_size
,
77 unsigned compr_offset
,
78 int (*test_uc_ebdata
)(__GPRO__ uch
*eb
, unsigned eb_size
,
79 uch
*eb_ucptr
, ulg eb_ucsize
)));
82 static int dircomp
OF((ZCONST zvoid
*a
, ZCONST zvoid
*b
));
87 /*******************************/
88 /* Strings used in extract.c */
89 /*******************************/
91 static ZCONST
char Far VersionMsg
[] =
92 " skipping: %-22s need %s compat. v%u.%u (can do v%u.%u)\n";
93 static ZCONST
char Far ComprMsgNum
[] =
94 " skipping: %-22s unsupported compression method %u\n";
96 static ZCONST
char Far ComprMsgName
[] =
97 " skipping: %-22s `%s' method not supported\n";
98 static ZCONST
char Far CmprNone
[] = "store";
99 static ZCONST
char Far CmprShrink
[] = "shrink";
100 static ZCONST
char Far CmprReduce
[] = "reduce";
101 static ZCONST
char Far CmprImplode
[] = "implode";
102 static ZCONST
char Far CmprTokenize
[] = "tokenize";
103 static ZCONST
char Far CmprDeflate
[] = "deflate";
104 static ZCONST
char Far CmprEnDeflate
[] = "enhanced deflate";
105 static ZCONST
char Far CmprDCLImplode
[] = "DCL implode";
106 static ZCONST
char Far
*ComprNames
[NUM_METHODS
] = {
107 CmprNone
, CmprShrink
, CmprReduce
, CmprReduce
, CmprReduce
, CmprReduce
,
108 CmprImplode
, CmprTokenize
, CmprDeflate
, CmprEnDeflate
, CmprDCLImplode
111 static ZCONST
char Far FilNamMsg
[] =
112 "%s: bad filename length (%s)\n";
113 static ZCONST
char Far ExtFieldMsg
[] =
114 "%s: bad extra field length (%s)\n";
115 static ZCONST
char Far OffsetMsg
[] =
116 "file #%u: bad zipfile offset (%s): %ld\n";
117 static ZCONST
char Far ExtractMsg
[] =
118 "%8sing: %-22s %s%s";
120 static ZCONST
char Far LengthMsg
[] =
121 "%s %s: %ld bytes required to uncompress to %lu bytes;\n %s\
122 supposed to require %lu bytes%s%s%s\n";
125 static ZCONST
char Far BadFileCommLength
[] = "%s: bad file comment length\n";
126 static ZCONST
char Far LocalHdrSig
[] = "local header sig";
127 static ZCONST
char Far BadLocalHdr
[] = "file #%u: bad local header\n";
128 static ZCONST
char Far AttemptRecompensate
[] =
129 " (attempting to re-compensate)\n";
131 static ZCONST
char Far BackslashPathSep
[] =
132 "warning: %s appears to use backslashes as path separators\n";
134 static ZCONST
char Far SkipVolumeLabel
[] =
135 " skipping: %-22s %svolume label\n";
137 #ifdef SET_DIR_ATTRIB /* messages of code for setting directory attributes */
138 static ZCONST
char Far DirlistEntryNoMem
[] =
139 "warning: cannot alloc memory for dir times/permissions/UID/GID\n";
140 static ZCONST
char Far DirlistSortNoMem
[] =
141 "warning: cannot alloc memory to sort dir times/perms/etc.\n";
142 static ZCONST
char Far DirlistSetAttrFailed
[] =
143 "warning: set times/attribs failed for %s\n";
147 static ZCONST
char Far ReplaceQuery
[] =
148 "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ";
149 static ZCONST
char Far AssumeNone
[] = " NULL\n(assuming [N]one)\n";
150 static ZCONST
char Far NewNameQuery
[] = "new name: ";
151 static ZCONST
char Far InvalidResponse
[] = "error: invalid response [%c]\n";
154 static ZCONST
char Far ErrorInArchive
[] =
155 "At least one %serror was detected in %s.\n";
156 static ZCONST
char Far ZeroFilesTested
[] =
157 "Caution: zero files tested in %s.\n";
160 static ZCONST
char Far VMSFormatQuery
[] =
161 "\n%s: stored in VMS format. Extract anyway? (y/n) ";
165 static ZCONST
char Far SkipCannotGetPasswd
[] =
166 " skipping: %-22s unable to get password\n";
167 static ZCONST
char Far SkipIncorrectPasswd
[] =
168 " skipping: %-22s incorrect password\n";
169 static ZCONST
char Far FilesSkipBadPasswd
[] =
170 "%u file%s skipped because of incorrect password.\n";
171 static ZCONST
char Far MaybeBadPasswd
[] =
172 " (may instead be incorrect password)\n";
174 static ZCONST
char Far SkipEncrypted
[] =
175 " skipping: %-22s encrypted (not supported)\n";
178 static ZCONST
char Far NoErrInCompData
[] =
179 "No errors detected in compressed data of %s.\n";
180 static ZCONST
char Far NoErrInTestedFiles
[] =
181 "No errors detected in %s for the %u file%s tested.\n";
182 static ZCONST
char Far FilesSkipped
[] =
183 "%u file%s skipped because of unsupported compression or encoding.\n";
185 static ZCONST
char Far ErrUnzipFile
[] = " error: %s%s %s\n";
186 static ZCONST
char Far ErrUnzipNoFile
[] = "\n error: %s%s\n";
187 static ZCONST
char Far NotEnoughMem
[] = "not enough memory to ";
188 static ZCONST
char Far InvalidComprData
[] = "invalid compressed data to ";
189 static ZCONST
char Far Inflate
[] = "inflate";
192 static ZCONST
char Far Explode
[] = "explode";
194 static ZCONST
char Far Unshrink
[] = "unshrink";
198 #if (!defined(DELETE_IF_FULL) || !defined(HAVE_UNLINK))
199 static ZCONST
char Far FileTruncated
[] =
200 "warning: %s is probably truncated\n";
203 static ZCONST
char Far FileUnknownCompMethod
[] =
204 "%s: unknown compression method\n";
205 static ZCONST
char Far BadCRC
[] = " bad CRC %08lx (should be %08lx)\n";
207 /* TruncEAs[] also used in OS/2 mapname(), close_outfile() */
208 char ZCONST Far TruncEAs
[] = " compressed EA data missing (%d bytes)%s";
209 char ZCONST Far TruncNTSD
[] =
210 " compressed WinNT security data missing (%d bytes)%s";
213 static ZCONST
char Far InconsistEFlength
[] = "bad extra-field entry:\n \
214 EF block length (%u bytes) exceeds remaining EF data (%u bytes)\n";
215 static ZCONST
char Far InvalidComprDataEAs
[] =
216 " invalid compressed data for EAs\n";
217 # if (defined(WIN32) && defined(NTSD_EAS))
218 static ZCONST
char Far InvalidSecurityEAs
[] =
219 " EAs fail security check\n";
221 static ZCONST
char Far UnsuppNTSDVersEAs
[] =
222 " unsupported NTSD EAs version %d\n";
223 static ZCONST
char Far BadCRC_EAs
[] = " bad CRC for extended attributes\n";
224 static ZCONST
char Far UnknComprMethodEAs
[] =
225 " unknown compression method for EAs (%u)\n";
226 static ZCONST
char Far NotEnoughMemEAs
[] =
227 " out of memory while inflating EAs\n";
228 static ZCONST
char Far UnknErrorEAs
[] =
229 " unknown error on extended attributes\n";
232 static ZCONST
char Far UnsupportedExtraField
[] =
233 "\nerror: unsupported extra-field compression type (%u)--skipping\n";
234 static ZCONST
char Far BadExtraFieldCRC
[] =
235 "error [%s]: bad extra-field CRC %08lx (should be %08lx)\n";
241 /**************************************/
242 /* Function extract_or_test_files() */
243 /**************************************/
245 int extract_or_test_files(__G
) /* return PK-type error code */
249 unsigned i
, j
, filnum
=0, blknum
=0;
250 int cd_incnt
, renamed
, query
;
251 int error
, error_in_archive
=PK_COOL
, *fn_matched
=NULL
, *xn_matched
=NULL
;
257 unsigned members_remaining
, num_skipped
=0, num_bad_pwd
=0;
258 long cd_bufstart
, bufstart
, inbuf_offset
, request
;
259 LONGINT old_extra_bytes
= 0L;
260 #ifdef SET_DIR_ATTRIB
262 dirtime
*dirlist
=(dirtime
*)NULL
, **sorted_dirlist
=(dirtime
**)NULL
;
266 /*---------------------------------------------------------------------------
267 The basic idea of this function is as follows. Since the central di-
268 rectory lies at the end of the zipfile and the member files lie at the
269 beginning or middle or wherever, it is not very desirable to simply
270 read a central directory entry, jump to the member and extract it, and
271 then jump back to the central directory. In the case of a large zipfile
272 this would lead to a whole lot of disk-grinding, especially if each mem-
273 ber file is small. Instead, we read from the central directory the per-
274 tinent information for a block of files, then go extract/test the whole
275 block. Thus this routine contains two small(er) loops within a very
276 large outer loop: the first of the small ones reads a block of files
277 from the central directory; the second extracts or tests each file; and
278 the outer one loops over blocks. There's some file-pointer positioning
279 stuff in between, but that's about it. Btw, it's because of this jump-
280 ing around that we can afford to be lenient if an error occurs in one of
281 the member files: we should still be able to go find the other members,
282 since we know the offset of each from the beginning of the zipfile.
283 ---------------------------------------------------------------------------*/
286 members_remaining
= (unsigned)G
.ecrec
.total_entries_central_dir
;
292 G
.reported_backslash
= FALSE
;
295 /* malloc space for check on unmatched filespecs (OK if one or both NULL) */
296 if (G
.filespecs
> 0 &&
297 (fn_matched
=(int *)malloc(G
.filespecs
*sizeof(int))) != (int *)NULL
)
298 for (i
= 0; i
< G
.filespecs
; ++i
)
299 fn_matched
[i
] = FALSE
;
300 if (G
.xfilespecs
> 0 &&
301 (xn_matched
=(int *)malloc(G
.xfilespecs
*sizeof(int))) != (int *)NULL
)
302 for (i
= 0; i
< G
.xfilespecs
; ++i
)
303 xn_matched
[i
] = FALSE
;
305 /*---------------------------------------------------------------------------
306 Begin main loop over blocks of member files. We know the entire central
307 directory is on this disk: we would not have any of this information un-
308 less the end-of-central-directory record was on this disk, and we would
309 not have gotten to this routine unless this is also the disk on which
310 the central directory starts. In practice, this had better be the ONLY
311 disk in the archive, but we'll add multi-disk support soon.
312 ---------------------------------------------------------------------------*/
314 while (members_remaining
) {
317 memzero(G
.filenotes
, DIR_BLKSIZ
* sizeof(char *));
321 * Loop through files in central directory, storing offsets, file
322 * attributes, case-conversion and text-conversion flags until block
326 while (members_remaining
&& (j
< DIR_BLKSIZ
)) {
328 G
.pInfo
= &G
.info
[j
];
330 if (readbuf(__G__ G
.sig
, 4) == 0) {
331 error_in_archive
= PK_EOF
;
332 members_remaining
= 0; /* ...so no more left to do */
335 if (strncmp(G
.sig
, central_hdr_sig
, 4)) { /* just to make sure */
336 Info(slide
, 0x401, ((char *)slide
, LoadFarString(CentSigMsg
),
337 j
+ blknum
*DIR_BLKSIZ
+ 1));
338 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ReportMsg
)));
339 error_in_archive
= PK_BADERR
;
340 members_remaining
= 0; /* ...so no more left to do */
343 /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag */
344 if ((error
= process_cdir_file_hdr(__G
)) != PK_COOL
) {
345 error_in_archive
= error
; /* only PK_EOF defined */
346 members_remaining
= 0; /* ...so no more left to do */
349 if ((error
= do_string(__G__ G
.crec
.filename_length
, DS_FN
)) !=
352 if (error
> error_in_archive
)
353 error_in_archive
= error
;
354 if (error
> PK_WARN
) { /* fatal: no more left to do */
355 Info(slide
, 0x401, ((char *)slide
, LoadFarString(FilNamMsg
),
356 FnFilter1(G
.filename
), "central"));
357 members_remaining
= 0;
361 if ((error
= do_string(__G__ G
.crec
.extra_field_length
,
364 if (error
> error_in_archive
)
365 error_in_archive
= error
;
366 if (error
> PK_WARN
) { /* fatal */
367 Info(slide
, 0x401, ((char *)slide
,
368 LoadFarString(ExtFieldMsg
),
369 FnFilter1(G
.filename
), "central"));
370 members_remaining
= 0;
376 if ((error
= do_string(__G__ G
.crec
.file_comment_length
,
377 uO
.N_flag
? FILENOTE
: SKIP
)) != PK_COOL
)
379 if ((error
= do_string(__G__ G
.crec
.file_comment_length
, SKIP
))
383 if (error
> error_in_archive
)
384 error_in_archive
= error
;
385 if (error
> PK_WARN
) { /* fatal */
386 Info(slide
, 0x421, ((char *)slide
,
387 LoadFarString(BadFileCommLength
),
388 FnFilter1(G
.filename
)));
389 members_remaining
= 0;
393 if (G
.process_all_files
) {
395 ++j
; /* file is OK; info[] stored; continue with next */
401 if (G
.filespecs
== 0)
403 else { /* check if this entry matches an `include' argument */
404 do_this_file
= FALSE
;
405 for (i
= 0; i
< G
.filespecs
; i
++)
406 if (match(G
.filename
, G
.pfnames
[i
], uO
.C_flag
)) {
407 do_this_file
= TRUE
; /* ^-- ignore case or not? */
409 fn_matched
[i
] = TRUE
;
410 break; /* found match, so stop looping */
413 if (do_this_file
) { /* check if this is an excluded file */
414 for (i
= 0; i
< G
.xfilespecs
; i
++)
415 if (match(G
.filename
, G
.pxnames
[i
], uO
.C_flag
)) {
416 do_this_file
= FALSE
; /* ^-- ignore case or not? */
418 xn_matched
[i
] = TRUE
;
424 ++j
; /* file is OK */
426 ++num_skipped
; /* unsupp. compression or encryption */
428 } /* end if (process_all_files) */
431 } /* end while-loop (adding files to current block) */
433 /* save position in central directory so can come back later */
434 cd_bufstart
= G
.cur_zipfile_bufstart
;
438 /*-----------------------------------------------------------------------
439 Second loop: process files in current block, extracting or testing
441 -----------------------------------------------------------------------*/
443 for (i
= 0; i
< j
; ++i
) {
444 filnum
++; /* filnum = i + blknum*DIR_BLKSIZ + 1; */
445 G
.pInfo
= &G
.info
[i
];
446 #ifdef NOVELL_BUG_FAILSAFE
447 G
.dne
= FALSE
; /* assume file exists until stat() says otherwise */
450 /* if the target position is not within the current input buffer
451 * (either haven't yet read far enough, or (maybe) skipping back-
452 * ward), skip to the target position and reset readbuf(). */
454 /* ZLSEEK(pInfo->offset): */
455 request
= G
.pInfo
->offset
+ G
.extra_bytes
;
456 inbuf_offset
= request
% INBUFSIZ
;
457 bufstart
= request
- inbuf_offset
;
459 Trace((stderr
, "\ndebug: request = %ld, inbuf_offset = %ld\n",
460 request
, inbuf_offset
));
462 "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
463 bufstart
, G
.cur_zipfile_bufstart
));
465 Info(slide
, 0x401, ((char *)slide
, LoadFarStringSmall(SeekMsg
),
466 G
.zipfn
, LoadFarString(ReportMsg
)));
467 error_in_archive
= PK_ERR
;
468 if (filnum
== 1 && G
.extra_bytes
!= 0L) {
469 Info(slide
, 0x401, ((char *)slide
,
470 LoadFarString(AttemptRecompensate
)));
471 old_extra_bytes
= G
.extra_bytes
;
473 request
= G
.pInfo
->offset
; /* could also check if != 0 */
474 inbuf_offset
= request
% INBUFSIZ
;
475 bufstart
= request
- inbuf_offset
;
476 Trace((stderr
, "debug: request = %ld, inbuf_offset = %ld\n",
477 request
, inbuf_offset
));
479 "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
480 bufstart
, G
.cur_zipfile_bufstart
));
482 error_in_archive
= PK_BADERR
;
483 continue; /* this one hosed; try next */
488 Trace((stderr
, "debug: recompensated request still < 0\n"));
489 Info(slide
, 0x401, ((char *)slide
, LoadFarStringSmall(SeekMsg
),
490 G
.zipfn
, LoadFarString(ReportMsg
)));
491 error_in_archive
= PK_BADERR
;
493 } else if (bufstart
!= G
.cur_zipfile_bufstart
) {
494 Trace((stderr
, "debug: bufstart != cur_zipfile_bufstart\n"));
495 #ifdef USE_STRM_INPUT
496 fseek((FILE *)G
.zipfd
,(LONGINT
)bufstart
,SEEK_SET
);
497 G
.cur_zipfile_bufstart
= ftell((FILE *)G
.zipfd
);
498 #else /* !USE_STRM_INPUT */
499 G
.cur_zipfile_bufstart
=
500 lseek(G
.zipfd
,(LONGINT
)bufstart
,SEEK_SET
);
501 #endif /* ?USE_STRM_INPUT */
502 if ((G
.incnt
= read(G
.zipfd
,(char *)G
.inbuf
,INBUFSIZ
)) <= 0)
504 Info(slide
, 0x401, ((char *)slide
, LoadFarString(OffsetMsg
),
505 filnum
, "lseek", bufstart
));
506 error_in_archive
= PK_BADERR
;
507 continue; /* can still do next file */
509 G
.inptr
= G
.inbuf
+ (int)inbuf_offset
;
510 G
.incnt
-= (int)inbuf_offset
;
512 G
.incnt
+= (int)(G
.inptr
-G
.inbuf
) - (int)inbuf_offset
;
513 G
.inptr
= G
.inbuf
+ (int)inbuf_offset
;
516 /* should be in proper position now, so check for sig */
517 if (readbuf(__G__ G
.sig
, 4) == 0) { /* bad offset */
518 Info(slide
, 0x401, ((char *)slide
, LoadFarString(OffsetMsg
),
519 filnum
, "EOF", request
));
520 error_in_archive
= PK_BADERR
;
521 continue; /* but can still try next one */
523 if (strncmp(G
.sig
, local_hdr_sig
, 4)) {
524 Info(slide
, 0x401, ((char *)slide
, LoadFarString(OffsetMsg
),
525 filnum
, LoadFarStringSmall(LocalHdrSig
), request
));
528 GRRDUMP(local_hdr_sig, 4)
530 error_in_archive
= PK_ERR
;
531 if ((filnum
== 1 && G
.extra_bytes
!= 0L) ||
532 (G
.extra_bytes
== 0L && old_extra_bytes
!= 0L)) {
533 Info(slide
, 0x401, ((char *)slide
,
534 LoadFarString(AttemptRecompensate
)));
536 old_extra_bytes
= G
.extra_bytes
;
539 G
.extra_bytes
= old_extra_bytes
; /* third attempt */
540 ZLSEEK(G
.pInfo
->offset
)
541 if (readbuf(__G__ G
.sig
, 4) == 0) { /* bad offset */
542 Info(slide
, 0x401, ((char *)slide
,
543 LoadFarString(OffsetMsg
), filnum
, "EOF", request
));
544 error_in_archive
= PK_BADERR
;
545 continue; /* but can still try next one */
547 if (strncmp(G
.sig
, local_hdr_sig
, 4)) {
548 Info(slide
, 0x401, ((char *)slide
,
549 LoadFarString(OffsetMsg
), filnum
,
550 LoadFarStringSmall(LocalHdrSig
), request
));
551 error_in_archive
= PK_BADERR
;
555 continue; /* this one hosed; try next */
557 if ((error
= process_local_file_hdr(__G
)) != PK_COOL
) {
558 Info(slide
, 0x421, ((char *)slide
, LoadFarString(BadLocalHdr
),
560 error_in_archive
= error
; /* only PK_EOF defined */
561 continue; /* can still try next one */
563 if ((error
= do_string(__G__ G
.lrec
.filename_length
, DS_FN
)) !=
566 if (error
> error_in_archive
)
567 error_in_archive
= error
;
568 if (error
> PK_WARN
) {
569 Info(slide
, 0x401, ((char *)slide
, LoadFarString(FilNamMsg
),
570 FnFilter1(G
.filename
), "local"));
571 continue; /* go on to next one */
574 if (G
.extra_field
!= (uch
*)NULL
) {
576 G
.extra_field
= (uch
*)NULL
;
579 do_string(__G__ G
.lrec
.extra_field_length
, EXTRA_FIELD
)) != 0)
581 if (error
> error_in_archive
)
582 error_in_archive
= error
;
583 if (error
> PK_WARN
) {
584 Info(slide
, 0x401, ((char *)slide
,
585 LoadFarString(ExtFieldMsg
),
586 FnFilter1(G
.filename
), "local"));
587 continue; /* go on */
592 if (G
.pInfo
->encrypted
&&
593 (error
= decrypt(__G__ uO
.pwdarg
)) != PK_COOL
) {
594 if (error
== PK_WARN
) {
595 if (!((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
)))
596 Info(slide
, 0x401, ((char *)slide
,
597 LoadFarString(SkipIncorrectPasswd
),
598 FnFilter1(G
.filename
)));
600 } else { /* (error > PK_WARN) */
601 if (error
> error_in_archive
)
602 error_in_archive
= error
;
603 Info(slide
, 0x401, ((char *)slide
,
604 LoadFarString(SkipCannotGetPasswd
),
605 FnFilter1(G
.filename
)));
607 continue; /* go on to next file */
612 * just about to extract file: if extracting to disk, check if
613 * already exists, and if so, take appropriate action according to
614 * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper
615 * loop because we don't store the possibly renamed filename[] in
619 if (!uO
.tflag
&& !uO
.cflag
&& !G
.redirect_data
)
621 if (!uO
.tflag
&& !uO
.cflag
)
624 renamed
= FALSE
; /* user hasn't renamed output file yet */
628 /* for files from DOS FAT, check for use of backslash instead
629 * of slash as directory separator (bug in some zipper(s); so
630 * far, not a problem in HPFS, NTFS or VFAT systems)
633 if (G
.pInfo
->hostnum
== FS_FAT_
&& !strchr(G
.filename
, '/')) {
634 char *p
=G
.filename
-1;
638 if (!G
.reported_backslash
) {
639 Info(slide
, 0x21, ((char *)slide
,
640 LoadFarString(BackslashPathSep
), G
.zipfn
));
641 G
.reported_backslash
= TRUE
;
642 if (!error_in_archive
)
643 error_in_archive
= PK_WARN
;
651 /* mapname can create dirs if not freshening or if renamed */
652 if ((error
= mapname(__G__ renamed
)) > PK_WARN
) {
653 if (error
== IZ_CREATED_DIR
) {
654 #ifdef SET_DIR_ATTRIB
657 d_entry
= (dirtime
*)malloc(sizeof(dirtime
));
658 if (d_entry
== (dirtime
*)NULL
) {
659 Info(slide
, 0x401, ((char *)slide
,
660 LoadFarString(DirlistEntryNoMem
)));
662 unsigned eb_izux_flg
;
664 d_entry
->next
= dirlist
;
667 (char *)malloc(strlen(G
.filename
) + 1);
668 if (dirlist
->fn
== (char *)NULL
) {
669 Info(slide
, 0x401, ((char *)slide
,
670 LoadFarString(DirlistEntryNoMem
)));
671 dirlist
= d_entry
->next
;
673 if (!error_in_archive
)
674 error_in_archive
= PK_WARN
;
677 strcpy(dirlist
->fn
, G
.filename
);
678 dirlist
->perms
= G
.pInfo
->file_attr
;
679 #ifdef USE_EF_UT_TIME
680 eb_izux_flg
= G
.extra_field
? ef_scan_for_izux(
681 G
.extra_field
, G
.lrec
.extra_field_length
, 0,
682 G
.lrec
.last_mod_dos_datetime
,
684 (G
.tz_is_valid
? &(dirlist
->u
.t3
) : NULL
),
690 #else /* !USE_EF_UT_TIME */
692 #endif /* ?USE_EF_UT_TIME */
693 if (eb_izux_flg
& EB_UT_FL_MTIME
) {
695 "\nextract: Unix dir e.f. modtime = %ld\n",
696 dirlist
->u
.t3
.mtime
));
698 dirlist
->u
.t3
.mtime
= dos_to_unix_time(
699 G
.lrec
.last_mod_dos_datetime
);
701 if (eb_izux_flg
& EB_UT_FL_ATIME
) {
703 "\nextract: Unix dir e.f. actime = %ld\n",
704 dirlist
->u
.t3
.atime
));
706 dirlist
->u
.t3
.atime
=
709 dirlist
->have_uidgid
=
710 (uO
.X_flag
&& (eb_izux_flg
& EB_UX2_VALID
));
713 #endif /* SET_DIR_ATTRIB */
714 } else if (error
== IZ_VOL_LABEL
) {
716 Info(slide
, 0x401, ((char *)slide
,
717 LoadFarString(SkipVolumeLabel
),
718 FnFilter1(G
.filename
),
719 uO
.volflag
? "hard disk " : ""));
721 Info(slide
, 1, ((char *)slide
,
722 LoadFarString(SkipVolumeLabel
),
723 FnFilter1(G
.filename
), ""));
725 /* if (!error_in_archive)
726 error_in_archive = PK_WARN; */
727 } else if (error
> PK_ERR
&& error_in_archive
< PK_ERR
)
728 error_in_archive
= PK_ERR
;
729 Trace((stderr
, "mapname(%s) returns error = %d\n",
730 FnFilter1(G
.filename
), error
));
731 continue; /* go on to next file */
735 QFilename(__G__ G
.filename
);
737 switch (check_for_newer(__G__ G
.filename
)) {
739 #ifdef NOVELL_BUG_FAILSAFE
740 G
.dne
= TRUE
; /* stat() says file DOES NOT EXIST */
742 /* if freshening, don't skip if just renamed */
743 if (uO
.fflag
&& !renamed
)
744 continue; /* freshen (no new files): skip */
746 case EXISTS_AND_OLDER
:
747 if (uO
.overwrite_none
) {
749 char szStr
[FILNAMSIZ
+40]; /* add. space for text */
751 if ((!G
.prompt_always
) || (done_once
)) {
753 "Target file exists.\nSkipping %s\n",
754 FnFilter1(G
.filename
));
755 win_fprintf((zvoid
*)&G
, stdout
,
756 strlen(szStr
), szStr
);
762 continue; /* never overwrite: skip file */
765 if (!uO
.overwrite_all
&& !uO
.B_flag
)
767 if (!uO
.overwrite_all
)
771 case EXISTS_AND_NEWER
: /* (or equal) */
772 if (uO
.overwrite_none
|| (uO
.uflag
&& !renamed
)) {
774 char szStr
[FILNAMSIZ
+40]; /* add. space for text */
776 if ((!G
.prompt_always
) || (done_once
)) {
778 "Target file newer.\nSkipping %s\n",
779 FnFilter1(G
.filename
));
780 win_fprintf((zvoid
*)&G
, stdout
,
781 strlen(szStr
), szStr
);
787 continue; /* skip if update/freshen & orig name */
790 if (!uO
.overwrite_all
&& !uO
.B_flag
)
792 if (!uO
.overwrite_all
)
799 switch (G
.lpUserFunctions
->replace
!= NULL
?
800 (*G
.lpUserFunctions
->replace
)(G
.filename
) :
802 case IDM_REPLACE_RENAME
:
803 _ISO_INTERN(G
.filename
);
806 case IDM_REPLACE_YES
:
808 case IDM_REPLACE_ALL
:
809 uO
.overwrite_all
= TRUE
;
810 uO
.overwrite_none
= FALSE
; /* just to make sure */
812 case IDM_REPLACE_NONE
:
813 uO
.overwrite_none
= TRUE
;
814 uO
.overwrite_all
= FALSE
; /* make sure */
816 /* FALL THROUGH, skip */
819 char szStr
[FILNAMSIZ
+40];
822 "Target file newer.\nSkipping %s\n",
823 FnFilter1(G
.filename
));
824 win_fprintf((zvoid
*)&G
, stdout
,
825 strlen(szStr
), szStr
);
831 Info(slide
, 0x81, ((char *)slide
,
832 LoadFarString(ReplaceQuery
),
833 FnFilter1(G
.filename
)));
834 if (fgets(G
.answerbuf
, 9, stdin
) == (char *)NULL
) {
835 Info(slide
, 1, ((char *)slide
,
836 LoadFarString(AssumeNone
)));
838 if (!error_in_archive
)
839 error_in_archive
= 1; /* not extracted: warning */
841 switch (*G
.answerbuf
) {
842 case 'A': /* dangerous option: force caps */
843 uO
.overwrite_all
= TRUE
;
844 uO
.overwrite_none
= FALSE
; /* just to make sure */
849 Info(slide
, 0x81, ((char *)slide
,
850 LoadFarString(NewNameQuery
)));
851 fgets(G
.filename
, FILNAMSIZ
, stdin
);
852 /* usually get \n here: better check for it */
853 len
= strlen(G
.filename
);
854 if (G
.filename
[len
-1] == '\n')
855 G
.filename
[--len
] = '\0';
857 #ifdef WIN32 /* WIN32 fgets( ... , stdin) returns OEM coded strings */
858 _OEM_INTERN(G
.filename
);
861 goto startover
; /* sorry for a goto */
866 uO
.overwrite_none
= TRUE
;
867 uO
.overwrite_all
= FALSE
; /* make sure */
868 /* FALL THROUGH, skip */
870 continue; /* skip file */
872 Info(slide
, 1, ((char *)slide
,
873 LoadFarString(InvalidResponse
), *G
.answerbuf
));
874 goto reprompt
; /* yet another goto? */
875 } /* end switch (*answerbuf) */
877 } /* end if (query) */
878 } /* end if (extracting to disk) */
881 if ((G
.statreportcb
!= NULL
) &&
882 (*G
.statreportcb
)(__G__ UZ_ST_START_EXTRACT
, G
.zipfn
,
885 free((zvoid
*)fn_matched
);
887 free((zvoid
*)xn_matched
);
888 return IZ_CTRLC
; /* cancel operation by user request */
891 #ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
898 if ((error
= extract_or_test_member(__G
)) != PK_COOL
) {
899 if (error
> error_in_archive
)
900 error_in_archive
= error
; /* ...and keep going */
902 if (G
.disk_full
> 1 || error_in_archive
== IZ_CTRLC
) {
904 if (G
.disk_full
> 1) {
907 free((zvoid
*)fn_matched
);
909 free((zvoid
*)xn_matched
);
910 return error_in_archive
; /* (unless disk full) */
914 if ((G
.statreportcb
!= NULL
) &&
915 (*G
.statreportcb
)(__G__ UZ_ST_FINISH_MEMBER
, G
.zipfn
,
916 G
.filename
, (zvoid
*)&G
.lrec
.ucsize
)) {
918 free((zvoid
*)fn_matched
);
920 free((zvoid
*)xn_matched
);
921 return IZ_CTRLC
; /* cancel operation by user request */
924 #ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
927 } /* end for-loop (i: files in current block) */
931 * Jump back to where we were in the central directory, then go and do
932 * the next batch of files.
935 #ifdef USE_STRM_INPUT
936 fseek((FILE *)G
.zipfd
, (LONGINT
)cd_bufstart
, SEEK_SET
);
937 G
.cur_zipfile_bufstart
= ftell((FILE *)G
.zipfd
);
938 #else /* !USE_STRM_INPUT */
939 G
.cur_zipfile_bufstart
= lseek(G
.zipfd
,(LONGINT
)cd_bufstart
,SEEK_SET
);
940 #endif /* ?USE_STRM_INPUT */
941 read(G
.zipfd
, (char *)G
.inbuf
, INBUFSIZ
); /* been here before... */
947 pipeit("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart
, cd_bufstart
);
948 pipeit("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart
,
949 cur_zipfile_bufstart
);
950 pipeit("inptr-inbuf = %d\n", G
.inptr
-G
.inbuf
);
951 pipeit("incnt = %d\n\n", G
.incnt
);
954 } /* end while-loop (blocks of files in central directory) */
956 /*---------------------------------------------------------------------------
957 Go back through saved list of directories, sort and set times/perms/UIDs
958 and GIDs from the deepest level on up.
959 ---------------------------------------------------------------------------*/
961 #ifdef SET_DIR_ATTRIB
963 sorted_dirlist
= (dirtime
**)malloc(num_dirs
*sizeof(dirtime
*));
964 if (sorted_dirlist
== (dirtime
**)NULL
) {
965 Info(slide
, 0x401, ((char *)slide
,
966 LoadFarString(DirlistSortNoMem
)));
967 while (dirlist
!= (dirtime
*)NULL
) {
968 dirtime
*d
= dirlist
;
970 dirlist
= dirlist
->next
;
975 sorted_dirlist
[0] = dirlist
;
977 for (i
= 0; i
< num_dirs
; ++i
) {
978 sorted_dirlist
[i
] = dirlist
;
979 dirlist
= dirlist
->next
;
981 qsort((char *)sorted_dirlist
, num_dirs
, sizeof(dirtime
*),
985 Trace((stderr
, "setting directory times/perms/attributes\n"));
986 for (i
= 0; i
< num_dirs
; ++i
) {
987 dirtime
*d
= sorted_dirlist
[i
];
989 Trace((stderr
, "dir = %s\n", d
->fn
));
990 if ((error
= set_direc_attribs(__G__ d
)) != PK_OK
) {
991 Info(slide
, 0x201, ((char *)slide
,
992 LoadFarString(DirlistSetAttrFailed
), d
->fn
));
993 if (!error_in_archive
)
994 error_in_archive
= error
;
999 free(sorted_dirlist
);
1002 #endif /* SET_DIR_ATTRIB */
1004 #if (defined(WIN32) && defined(NTSD_EAS))
1005 process_defer_NT(__G
); /* process any deferred items for this .zip file */
1008 /*---------------------------------------------------------------------------
1009 Check for unmatched filespecs on command line and print warning if any
1010 found. Free allocated memory.
1011 ---------------------------------------------------------------------------*/
1014 for (i
= 0; i
< G
.filespecs
; ++i
)
1015 if (!fn_matched
[i
]) {
1017 if (!G
.redirect_data
&& !G
.redirect_text
)
1018 Info(slide
, 0x401, ((char *)slide
,
1019 LoadFarString(FilenameNotMatched
), G
.pfnames
[i
]));
1021 setFileNotFound(__G
);
1023 Info(slide
, 1, ((char *)slide
,
1024 LoadFarString(FilenameNotMatched
), G
.pfnames
[i
]));
1026 if (error_in_archive
<= PK_WARN
)
1027 error_in_archive
= PK_FIND
; /* some files not found */
1029 free((zvoid
*)fn_matched
);
1032 for (i
= 0; i
< G
.xfilespecs
; ++i
)
1034 Info(slide
, 0x401, ((char *)slide
,
1035 LoadFarString(ExclFilenameNotMatched
), G
.pxnames
[i
]));
1036 free((zvoid
*)xn_matched
);
1039 /*---------------------------------------------------------------------------
1040 Double-check that we're back at the end-of-central-directory record, and
1041 print quick summary of results, if we were just testing the archive. We
1042 send the summary to stdout so that people doing the testing in the back-
1043 ground and redirecting to a file can just do a "tail" on the output file.
1044 ---------------------------------------------------------------------------*/
1047 if (readbuf(__G__ G
.sig
, 4) == 0)
1048 error_in_archive
= PK_EOF
;
1049 if (strncmp(G
.sig
, end_central_sig
, 4)) { /* just to make sure */
1050 Info(slide
, 0x401, ((char *)slide
, LoadFarString(EndSigMsg
)));
1051 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ReportMsg
)));
1052 if (!error_in_archive
) /* don't overwrite stronger error */
1053 error_in_archive
= PK_WARN
;
1057 unsigned num
= filnum
- num_bad_pwd
;
1059 if (uO
.qflag
< 2) { /* GRR 930710: was (uO.qflag == 1) */
1060 if (error_in_archive
)
1061 Info(slide
, 0, ((char *)slide
, LoadFarString(ErrorInArchive
),
1062 (error_in_archive
== 1)? "warning-" : "", G
.zipfn
));
1064 Info(slide
, 0, ((char *)slide
, LoadFarString(ZeroFilesTested
),
1066 else if (G
.process_all_files
&& (num_skipped
+num_bad_pwd
== 0))
1067 Info(slide
, 0, ((char *)slide
, LoadFarString(NoErrInCompData
),
1070 Info(slide
, 0, ((char *)slide
, LoadFarString(NoErrInTestedFiles
)
1071 , G
.zipfn
, num
, (num
==1)? "":"s"));
1072 if (num_skipped
> 0)
1073 Info(slide
, 0, ((char *)slide
, LoadFarString(FilesSkipped
),
1074 num_skipped
, (num_skipped
==1)? "":"s"));
1076 if (num_bad_pwd
> 0)
1077 Info(slide
, 0, ((char *)slide
, LoadFarString(FilesSkipBadPasswd
)
1078 , num_bad_pwd
, (num_bad_pwd
==1)? "":"s"));
1080 } else if ((uO
.qflag
== 0) && !error_in_archive
&& (num
== 0))
1081 Info(slide
, 0, ((char *)slide
, LoadFarString(ZeroFilesTested
),
1085 /* give warning if files not tested or extracted (first condition can still
1086 * happen if zipfile is empty and no files specified on command line) */
1088 if ((filnum
== 0) && error_in_archive
<= PK_WARN
) {
1089 if (num_skipped
> 0)
1090 error_in_archive
= IZ_UNSUP
; /* unsupport. compression/encryption */
1092 error_in_archive
= PK_FIND
; /* no files found at all */
1095 else if ((filnum
== num_bad_pwd
) && error_in_archive
<= PK_WARN
)
1096 error_in_archive
= IZ_BADPWD
; /* bad passwd => all files skipped */
1098 else if ((num_skipped
> 0) && error_in_archive
<= PK_WARN
)
1099 error_in_archive
= IZ_UNSUP
; /* was PK_WARN; Jean-loup complained */
1101 else if ((num_bad_pwd
> 0) && !error_in_archive
)
1102 error_in_archive
= PK_WARN
;
1105 return error_in_archive
;
1107 } /* end function extract_or_test_files() */
1113 /***************************/
1114 /* Function store_info() */
1115 /***************************/
1117 static int store_info(__G
) /* return 0 if skipping, 1 if OK */
1121 # define UNKN_COMPR \
1122 (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED)
1124 # ifdef COPYRIGHT_CLEAN /* no reduced files */
1125 # define UNKN_RED (G.crec.compression_method >= REDUCED1 && \
1126 G.crec.compression_method <= REDUCED4)
1128 # define UNKN_RED FALSE /* reducing not unknown */
1130 # ifdef LZW_CLEAN /* no shrunk files */
1131 # define UNKN_SHR (G.crec.compression_method == SHRUNK)
1133 # define UNKN_SHR FALSE /* unshrinking not unknown */
1135 # define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
1136 G.crec.compression_method==TOKENIZED || G.crec.compression_method>DEFLATED)
1139 /*---------------------------------------------------------------------------
1140 Check central directory info for version/compatibility requirements.
1141 ---------------------------------------------------------------------------*/
1143 G
.pInfo
->encrypted
= G
.crec
.general_purpose_bit_flag
& 1; /* bit field */
1144 G
.pInfo
->ExtLocHdr
= (G
.crec
.general_purpose_bit_flag
& 8) == 8; /* bit */
1145 G
.pInfo
->textfile
= G
.crec
.internal_file_attributes
& 1; /* bit field */
1146 G
.pInfo
->crc
= G
.crec
.crc32
;
1147 G
.pInfo
->compr_size
= G
.crec
.csize
;
1148 G
.pInfo
->uncompr_size
= G
.crec
.ucsize
;
1152 G
.pInfo
->textmode
= FALSE
; /* bit field */
1155 G
.pInfo
->textmode
= G
.pInfo
->textfile
; /* auto-convert mode */
1157 default: /* case 2: */
1158 G
.pInfo
->textmode
= TRUE
;
1162 if (G
.crec
.version_needed_to_extract
[1] == VMS_
) {
1163 if (G
.crec
.version_needed_to_extract
[0] > VMS_UNZIP_VERSION
) {
1164 if (!((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
)))
1165 Info(slide
, 0x401, ((char *)slide
, LoadFarString(VersionMsg
),
1166 FnFilter1(G
.filename
), "VMS",
1167 G
.crec
.version_needed_to_extract
[0] / 10,
1168 G
.crec
.version_needed_to_extract
[0] % 10,
1169 VMS_UNZIP_VERSION
/ 10, VMS_UNZIP_VERSION
% 10));
1172 #ifndef VMS /* won't be able to use extra field, but still have data */
1173 else if (!uO
.tflag
&& !uO
.overwrite_all
) { /* if -o, extract anyway */
1174 Info(slide
, 0x481, ((char *)slide
, LoadFarString(VMSFormatQuery
),
1175 FnFilter1(G
.filename
)));
1176 fgets(G
.answerbuf
, 9, stdin
);
1177 if ((*G
.answerbuf
!= 'y') && (*G
.answerbuf
!= 'Y'))
1181 /* usual file type: don't need VMS to extract */
1182 } else if (G
.crec
.version_needed_to_extract
[0] > UNZIP_VERSION
) {
1183 if (!((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
)))
1184 Info(slide
, 0x401, ((char *)slide
, LoadFarString(VersionMsg
),
1185 FnFilter1(G
.filename
), "PK",
1186 G
.crec
.version_needed_to_extract
[0] / 10,
1187 G
.crec
.version_needed_to_extract
[0] % 10,
1188 UNZIP_VERSION
/ 10, UNZIP_VERSION
% 10));
1193 if (!((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
))) {
1195 if (G
.crec
.compression_method
< NUM_METHODS
)
1196 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ComprMsgName
),
1197 FnFilter1(G
.filename
),
1198 LoadFarStringSmall(ComprNames
[G
.crec
.compression_method
])));
1201 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ComprMsgNum
),
1202 FnFilter1(G
.filename
),
1203 G
.crec
.compression_method
));
1208 if (G
.pInfo
->encrypted
) {
1209 if (!((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
)))
1210 Info(slide
, 0x401, ((char *)slide
, LoadFarString(SkipEncrypted
),
1211 FnFilter1(G
.filename
)));
1216 /* map whatever file attributes we have into the local format */
1217 mapattr(__G
); /* GRR: worry about return value later */
1219 G
.pInfo
->offset
= (long)G
.crec
.relative_offset_local_header
;
1222 } /* end function store_info() */
1228 /***************************************/
1229 /* Function extract_or_test_member() */
1230 /***************************************/
1232 static int extract_or_test_member(__G
) /* return PK-type error code */
1235 char *nul
="[empty] ", *txt
="[text] ", *bin
="[binary]";
1237 char *ebc
="[ebcdic]";
1240 int r
, error
=PK_COOL
;
1241 #if (defined(DLL) && !defined(NO_SLIDE_REDIR))
1244 # define wsize WSIZE
1248 /*---------------------------------------------------------------------------
1249 Initialize variables, buffers, etc.
1250 ---------------------------------------------------------------------------*/
1253 G
.bitbuf
= 0L; /* unreduce and unshrink only */
1256 G
.crc32val
= CRCVAL_INITIAL
;
1259 /* if file came from Unix and is a symbolic link and we are extracting
1260 * to disk, prepare to restore the link */
1261 if (S_ISLNK(G
.pInfo
->file_attr
) &&
1262 (G
.pInfo
->hostnum
== UNIX_
|| G
.pInfo
->hostnum
== ATARI_
||
1263 G
.pInfo
->hostnum
== BEOS_
) &&
1264 !uO
.tflag
&& !uO
.cflag
&& (G
.lrec
.ucsize
> 0))
1268 #endif /* SYMLINKS */
1272 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
), "test",
1273 FnFilter1(G
.filename
), "", ""));
1276 if (uO
.cflag
&& !G
.redirect_data
)
1281 #if (defined(OS2) && defined(__IBMC__) && (__IBMC__ >= 200))
1282 G
.outfile
= freopen("", "wb", stdout
); /* VAC++ ignores setmode */
1286 #ifdef DOS_FLX_H68_OS2_W32
1287 #if (defined(__HIGHC__) && !defined(FLEXOS))
1288 setmode(G
.outfile
, _BINARY
);
1289 #else /* !(defined(__HIGHC__) && !defined(FLEXOS)) */
1290 setmode(fileno(G
.outfile
), O_BINARY
);
1291 #endif /* ?(defined(__HIGHC__) && !defined(FLEXOS)) */
1292 # define NEWLINE "\r\n"
1293 #else /* !DOS_FLX_H68_OS2_W32 */
1294 # define NEWLINE "\n"
1295 #endif /* ?DOS_FLX_H68_OS2_W32 */
1297 if (open_outfile(__G
)) /* VMS: required even for stdout! */
1300 } else if (open_outfile(__G
))
1304 /*---------------------------------------------------------------------------
1306 ---------------------------------------------------------------------------*/
1308 defer_leftover_input(__G
); /* so NEXTBYTE bounds check will work */
1309 switch (G
.lrec
.compression_method
) {
1311 if (!uO
.tflag
&& QCOND2
) {
1313 if (G
.symlnk
) /* can also be deflated, but rarer... */
1314 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
),
1315 "link", FnFilter1(G
.filename
), "", ""));
1317 #endif /* SYMLINKS */
1318 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
),
1319 "extract", FnFilter1(G
.filename
),
1320 (uO
.aflag
!= 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1321 "" : (G
.lrec
.ucsize
== 0L? nul
: (G
.pInfo
->textfile
? txt
:
1322 bin
)), uO
.cflag
? NEWLINE
: ""));
1324 #if (defined(DLL) && !defined(NO_SLIDE_REDIR))
1325 if (G
.redirect_slide
) {
1326 wsize
= G
.redirect_size
; redirSlide
= G
.redirect_buffer
;
1328 wsize
= WSIZE
; redirSlide
= slide
;
1331 G
.outptr
= redirSlide
;
1333 while ((b
= NEXTBYTE
) != EOF
&& !G
.disk_full
) {
1334 *G
.outptr
++ = (uch
)b
;
1335 if (++G
.outcnt
== wsize
) {
1336 flush(__G__ redirSlide
, G
.outcnt
, 0);
1337 G
.outptr
= redirSlide
;
1341 if (G
.outcnt
) /* flush final (partial) buffer */
1342 flush(__G__ redirSlide
, G
.outcnt
, 0);
1348 if (!uO
.tflag
&& QCOND2
) {
1349 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
),
1350 LoadFarStringSmall(Unshrink
), FnFilter1(G
.filename
),
1351 (uO
.aflag
!= 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1352 "" : (G
.pInfo
->textfile
? txt
: bin
), uO
.cflag
? NEWLINE
: ""));
1354 if ((r
= unshrink(__G
)) != PK_COOL
) {
1355 if ((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
))
1356 Info(slide
, 0x401, ((char *)slide
,
1357 LoadFarStringSmall(ErrUnzipFile
),
1358 LoadFarString(NotEnoughMem
),
1359 LoadFarStringSmall2(Unshrink
),
1360 FnFilter1(G
.filename
)));
1362 Info(slide
, 0x401, ((char *)slide
,
1363 LoadFarStringSmall(ErrUnzipNoFile
),
1364 LoadFarString(NotEnoughMem
),
1365 LoadFarStringSmall2(Unshrink
)));
1369 #endif /* !LZW_CLEAN */
1371 #ifndef COPYRIGHT_CLEAN
1376 if (!uO
.tflag
&& QCOND2
) {
1377 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
),
1378 "unreduc", FnFilter1(G
.filename
),
1379 (uO
.aflag
!= 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1380 "" : (G
.pInfo
->textfile
? txt
: bin
), uO
.cflag
? NEWLINE
: ""));
1384 #endif /* !COPYRIGHT_CLEAN */
1387 if (!uO
.tflag
&& QCOND2
) {
1388 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
),
1389 "explod", FnFilter1(G
.filename
),
1390 (uO
.aflag
!= 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1391 "" : (G
.pInfo
->textfile
? txt
: bin
), uO
.cflag
? NEWLINE
: ""));
1393 if (((r
= explode(__G
)) != 0) && (r
!= 5)) { /* treat 5 specially */
1394 if ((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
))
1395 Info(slide
, 0x401, ((char *)slide
,
1396 LoadFarStringSmall(ErrUnzipFile
), r
== 3?
1397 LoadFarString(NotEnoughMem
) :
1398 LoadFarString(InvalidComprData
),
1399 LoadFarStringSmall2(Explode
),
1400 FnFilter1(G
.filename
)));
1402 Info(slide
, 0x401, ((char *)slide
,
1403 LoadFarStringSmall(ErrUnzipNoFile
), r
== 3?
1404 LoadFarString(NotEnoughMem
) :
1405 LoadFarString(InvalidComprData
),
1406 LoadFarStringSmall2(Explode
)));
1407 error
= (r
== 3)? PK_MEM3
: PK_ERR
;
1410 int warning
= ((ulg
)G
.used_csize
<= G
.lrec
.csize
);
1412 if ((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
))
1413 Info(slide
, 0x401, ((char *)slide
, LoadFarString(LengthMsg
),
1414 "", warning
? "warning" : "error", G
.used_csize
,
1415 G
.lrec
.ucsize
, warning
? " " : "", G
.lrec
.csize
,
1416 " [", FnFilter1(G
.filename
), "]"));
1418 Info(slide
, 0x401, ((char *)slide
, LoadFarString(LengthMsg
),
1419 "\n", warning
? "warning" : "error", G
.used_csize
,
1420 G
.lrec
.ucsize
, warning
? " ":"", G
.lrec
.csize
,
1422 error
= warning
? PK_WARN
: PK_ERR
;
1428 if (!uO
.tflag
&& QCOND2
) {
1429 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
),
1430 "inflat", FnFilter1(G
.filename
),
1431 (uO
.aflag
!= 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1432 "" : (G
.pInfo
->textfile
? txt
: bin
), uO
.cflag
? NEWLINE
: ""));
1434 #ifndef USE_ZLIB /* zlib's function is called inflate(), too */
1435 # define UZinflate inflate
1437 if ((r
= UZinflate(__G
)) != 0) {
1438 if ((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
))
1439 Info(slide
, 0x401, ((char *)slide
,
1440 LoadFarStringSmall(ErrUnzipFile
), r
== 3?
1441 LoadFarString(NotEnoughMem
) :
1442 LoadFarString(InvalidComprData
),
1443 LoadFarStringSmall2(Inflate
),
1444 FnFilter1(G
.filename
)));
1446 Info(slide
, 0x401, ((char *)slide
,
1447 LoadFarStringSmall(ErrUnzipNoFile
), r
== 3?
1448 LoadFarString(NotEnoughMem
) :
1449 LoadFarString(InvalidComprData
),
1450 LoadFarStringSmall2(Inflate
)));
1451 error
= (r
== 3)? PK_MEM3
: PK_ERR
;
1455 default: /* should never get to this point */
1456 Info(slide
, 0x401, ((char *)slide
,
1457 LoadFarString(FileUnknownCompMethod
), FnFilter1(G
.filename
)));
1458 /* close and delete file before return? */
1462 } /* end switch (compression method) */
1464 /*---------------------------------------------------------------------------
1465 Close the file and set its date and time (not necessarily in that order),
1466 and make sure the CRC checked out OK. Logical-AND the CRC for 64-bit
1467 machines (redundant on 32-bit machines).
1468 ---------------------------------------------------------------------------*/
1470 #ifdef VMS /* VMS: required even for stdout! (final flush) */
1471 if (!uO
.tflag
) /* don't close NULL file */
1475 if (!uO
.tflag
&& (!uO
.cflag
|| G
.redirect_data
)) {
1476 if (G
.redirect_data
)
1482 if (!uO
.tflag
&& !uO
.cflag
) /* don't close NULL file or stdout */
1487 /* GRR: CONVERT close_outfile() TO NON-VOID: CHECK FOR ERRORS! */
1490 if (G
.disk_full
) { /* set by flush() */
1491 if (G
.disk_full
> 1) {
1492 #if (defined(DELETE_IF_FULL) && defined(HAVE_UNLINK))
1493 /* delete the incomplete file if we can */
1494 if (unlink(G
.filename
) != 0)
1495 Trace((stderr
, "extract.c: could not delete %s\n",
1496 FnFilter1(G
.filename
)));
1498 /* warn user about the incomplete file */
1499 Info(slide
, 0x421, ((char *)slide
, LoadFarString(FileTruncated
),
1500 FnFilter1(G
.filename
)));
1508 if (error
> PK_WARN
) {/* don't print redundant CRC error if error already */
1512 if (G
.crc32val
!= G
.lrec
.crc32
) {
1513 /* if quiet enough, we haven't output the filename yet: do it */
1514 if ((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
))
1515 Info(slide
, 0x401, ((char *)slide
, "%-22s ",
1516 FnFilter1(G
.filename
)));
1517 Info(slide
, 0x401, ((char *)slide
, LoadFarString(BadCRC
), G
.crc32val
,
1520 if (G
.pInfo
->encrypted
)
1521 Info(slide
, 0x401, ((char *)slide
, LoadFarString(MaybeBadPasswd
)));
1524 } else if (uO
.tflag
) {
1526 if (G
.extra_field
) {
1527 if ((r
= TestExtraField(__G__ G
.extra_field
,
1528 G
.lrec
.extra_field_length
)) > error
)
1533 Info(slide
, 0, ((char *)slide
, " OK\n"));
1535 if (QCOND2
&& !error
) /* GRR: is stdout reset to text mode yet? */
1536 Info(slide
, 0, ((char *)slide
, "\n"));
1542 } /* end function extract_or_test_member() */
1550 /*******************************/
1551 /* Function TestExtraField() */
1552 /*******************************/
1554 static int TestExtraField(__G__ ef
, ef_len
)
1561 unsigned eb_cmpr_offs
= 0;
1564 /* we know the regular compressed file data tested out OK, or else we
1565 * wouldn't be here ==> print filename if any extra-field errors found
1567 while (ef_len
>= EB_HEADSIZE
) {
1568 ebID
= makeword(ef
);
1569 ebLen
= (unsigned)makeword(ef
+EB_LEN
);
1571 if (ebLen
> (ef_len
- EB_HEADSIZE
)) {
1572 /* Discovered some extra field inconsistency! */
1574 Info(slide
, 1, ((char *)slide
, "%-22s ",
1575 FnFilter1(G
.filename
)));
1576 Info(slide
, 1, ((char *)slide
, LoadFarString(InconsistEFlength
),
1577 ebLen
, (ef_len
- EB_HEADSIZE
)));
1589 eb_cmpr_offs
= EB_OS2_HLEN
;
1592 if (ebLen
>= EB_MAC3_HLEN
&&
1593 (makeword(ef
+(EB_HEADSIZE
+EB_FLGS_OFFS
))
1594 & EB_M3_FL_UNCMPR
) &&
1595 (makelong(ef
+EB_HEADSIZE
) == ebLen
- EB_MAC3_HLEN
))
1598 eb_cmpr_offs
= EB_MAC3_HLEN
;
1601 if (ebLen
>= EB_BEOS_HLEN
&&
1602 (*(ef
+(EB_HEADSIZE
+EB_FLGS_OFFS
)) & EB_BE_FL_UNCMPR
) &&
1603 (makelong(ef
+EB_HEADSIZE
) == ebLen
- EB_BEOS_HLEN
))
1606 eb_cmpr_offs
= EB_BEOS_HLEN
;
1609 if ((r
= test_compr_eb(__G__ ef
, ebLen
, eb_cmpr_offs
, NULL
))
1612 Info(slide
, 1, ((char *)slide
, "%-22s ",
1613 FnFilter1(G
.filename
)));
1616 Info(slide
, 1, ((char *)slide
,
1617 LoadFarString(TruncEAs
),
1618 ebLen
-(eb_cmpr_offs
+EB_CMPRHEADLEN
), "\n"));
1621 Info(slide
, 1, ((char *)slide
,
1622 LoadFarString(InvalidComprDataEAs
)));
1626 Info(slide
, 1, ((char *)slide
,
1627 LoadFarString(NotEnoughMemEAs
)));
1630 if ((r
& 0xff) != PK_ERR
)
1631 Info(slide
, 1, ((char *)slide
,
1632 LoadFarString(UnknErrorEAs
)));
1634 ush m
= (ush
)(r
>> 8);
1635 if (m
== DEFLATED
) /* GRR KLUDGE! */
1636 Info(slide
, 1, ((char *)slide
,
1637 LoadFarString(BadCRC_EAs
)));
1639 Info(slide
, 1, ((char *)slide
,
1640 LoadFarString(UnknComprMethodEAs
), m
));
1649 Trace((stderr
, "ebID: %i / ebLen: %u\n", ebID
, ebLen
));
1650 r
= ebLen
< EB_NTSD_L_LEN
? IZ_EF_TRUNC
:
1651 ((ef
[EB_HEADSIZE
+EB_NTSD_VERSION
] > EB_NTSD_MAX_VER
) ?
1652 (PK_WARN
| 0x4000) :
1653 test_compr_eb(__G__ ef
, ebLen
, EB_NTSD_L_LEN
, TEST_NTSD
));
1656 Info(slide
, 1, ((char *)slide
, "%-22s ",
1657 FnFilter1(G
.filename
)));
1660 Info(slide
, 1, ((char *)slide
,
1661 LoadFarString(TruncNTSD
),
1662 ebLen
-(EB_NTSD_L_LEN
+EB_CMPRHEADLEN
), "\n"));
1664 #if (defined(WIN32) && defined(NTSD_EAS))
1666 Info(slide
, 1, ((char *)slide
,
1667 LoadFarString(InvalidSecurityEAs
)));
1671 Info(slide
, 1, ((char *)slide
,
1672 LoadFarString(InvalidComprDataEAs
)));
1676 Info(slide
, 1, ((char *)slide
,
1677 LoadFarString(NotEnoughMemEAs
)));
1679 case (PK_WARN
| 0x4000):
1680 Info(slide
, 1, ((char *)slide
,
1681 LoadFarString(UnsuppNTSDVersEAs
),
1682 (int)ef
[EB_HEADSIZE
+EB_NTSD_VERSION
]));
1686 if ((r
& 0xff) != PK_ERR
)
1687 Info(slide
, 1, ((char *)slide
,
1688 LoadFarString(UnknErrorEAs
)));
1690 ush m
= (ush
)(r
>> 8);
1691 if (m
== DEFLATED
) /* GRR KLUDGE! */
1692 Info(slide
, 1, ((char *)slide
,
1693 LoadFarString(BadCRC_EAs
)));
1695 Info(slide
, 1, ((char *)slide
,
1696 LoadFarString(UnknComprMethodEAs
), m
));
1716 ef_len
-= (ebLen
+ EB_HEADSIZE
);
1717 ef
+= (ebLen
+ EB_HEADSIZE
);
1721 Info(slide
, 0, ((char *)slide
, " OK\n"));
1725 } /* end function TestExtraField() */
1731 /******************************/
1732 /* Function test_compr_eb() */
1733 /******************************/
1736 static int test_compr_eb(
1740 unsigned compr_offset
,
1741 int (*test_uc_ebdata
)(__GPRO__ uch
*eb
, unsigned eb_size
,
1742 uch
*eb_ucptr
, ulg eb_ucsize
))
1744 static int test_compr_eb(__G__ eb
, eb_size
, compr_offset
, test_uc_ebdata
)
1748 unsigned compr_offset
;
1749 int (*test_uc_ebdata
)();
1756 if (compr_offset
< 4) /* field is not compressed: */
1757 return PK_OK
; /* do nothing and signal OK */
1759 if ((eb_size
< (EB_UCSIZE_P
+ 4)) ||
1760 ((eb_ucsize
= makelong(eb
+(EB_HEADSIZE
+EB_UCSIZE_P
))) > 0L &&
1761 eb_size
<= (compr_offset
+ EB_CMPRHEADLEN
)))
1762 return IZ_EF_TRUNC
; /* no compressed data! */
1764 if ((eb_ucptr
= (uch
*)malloc((extent
)eb_ucsize
)) == (uch
*)NULL
)
1767 r
= memextract(__G__ eb_ucptr
, eb_ucsize
,
1768 eb
+ (EB_HEADSIZE
+ compr_offset
),
1769 (ulg
)(eb_size
- compr_offset
));
1771 if (r
== PK_OK
&& test_uc_ebdata
!= NULL
)
1772 r
= (*test_uc_ebdata
)(__G__ eb
, eb_size
, eb_ucptr
, eb_ucsize
);
1777 } /* end function test_compr_eb() */
1785 /***************************/
1786 /* Function memextract() */
1787 /***************************/
1789 int memextract(__G__ tgt
, tgtsize
, src
, srcsize
) /* extract compressed */
1790 __GDEF
/* extra field block; */
1791 uch
*tgt
, *src
; /* return PK-type error */
1792 ulg tgtsize
, srcsize
; /* level */
1794 long old_csize
=G
.csize
;
1795 uch
*old_inptr
=G
.inptr
;
1796 int old_incnt
=G
.incnt
;
1799 ulg extra_field_crc
;
1802 method
= makeword(src
);
1803 extra_field_crc
= makelong(src
+2);
1805 /* compressed extra field exists completely in memory at this location: */
1806 G
.inptr
= src
+ 2 + 4; /* method and extra_field_crc */
1807 G
.incnt
= (int)(G
.csize
= (long)(srcsize
- (2 + 4)));
1810 G
.outsize
= tgtsize
;
1814 memcpy((char *)tgt
, (char *)G
.inptr
, (extent
)G
.incnt
);
1815 G
.outcnt
= G
.csize
; /* for CRC calculation */
1819 if ((r
= UZinflate(__G
)) != 0) {
1821 Info(slide
, 0x401, ((char *)slide
,
1822 LoadFarStringSmall(ErrUnzipNoFile
), r
== 3?
1823 LoadFarString(NotEnoughMem
) :
1824 LoadFarString(InvalidComprData
),
1825 LoadFarStringSmall2(Inflate
)));
1826 error
= (r
== 3)? PK_MEM3
: PK_ERR
;
1828 if (G
.outcnt
== 0L) /* inflate's final FLUSH sets outcnt */
1833 error
= PK_ERR
| ((int)method
<< 8);
1835 Info(slide
, 0x401, ((char *)slide
,
1836 LoadFarString(UnsupportedExtraField
), method
));
1837 error
= PK_ERR
; /* GRR: should be passed on up via SetEAs() */
1842 G
.inptr
= old_inptr
;
1843 G
.incnt
= old_incnt
;
1844 G
.csize
= old_csize
;
1848 register ulg crcval
= crc32(CRCVAL_INITIAL
, tgt
, (extent
)G
.outcnt
);
1850 if (crcval
!= extra_field_crc
) {
1852 error
= PK_ERR
| (DEFLATED
<< 8); /* kludge for now */
1854 Info(slide
, 0x401, ((char *)slide
,
1855 LoadFarString(BadExtraFieldCRC
), G
.zipfn
, crcval
,
1863 } /* end function memextract() */
1869 /*************************/
1870 /* Function memflush() */
1871 /*************************/
1873 int memflush(__G__ rawbuf
, size
)
1878 if (size
> G
.outsize
)
1879 return 50; /* more data than output buffer can hold */
1881 memcpy((char *)G
.outbufptr
, (char *)rawbuf
, (extent
)size
);
1882 G
.outbufptr
+= (unsigned int)size
;
1888 } /* end function memflush() */
1894 /*************************/
1895 /* Function fnfilter() */ /* here instead of in list.c for SFX */
1896 /*************************/
1898 char *fnfilter(raw
, space
) /* convert name to safely printable form */
1902 #ifndef NATIVE /* ASCII: filter ANSI escape codes, etc. */
1903 uch
*r
=(uch
*)raw
, *s
=space
;
1908 if (*r
== '/' || *r
== '.') {
1916 *s
++ = '^', *s
++ = (uch
)(64 + *r
++);
1923 INTERN_TO_ISO((char *)space
, (char *)space
); /* translate to ANSI */
1926 /* Win9x console always uses OEM character coding, and
1927 WinNT console is set to OEM charset by default, too */
1928 INTERN_TO_OEM((char *)space
, (char *)space
);
1930 #endif /* ?WINDLL */
1932 return (char *)space
;
1934 #else /* NATIVE: EBCDIC or whatever */
1938 } /* end function fnfilter() */
1944 #ifdef SET_DIR_ATTRIB
1945 /* must sort saved directories so can set perms from bottom up */
1947 /************************/
1948 /* Function dircomp() */
1949 /************************/
1951 static int dircomp(a
, b
) /* used by qsort(); swiped from Zip */
1952 ZCONST zvoid
*a
, *b
;
1954 /* order is significant: this sorts in reverse order (deepest first) */
1955 return strcmp((*(dirtime
**)b
)->fn
, (*(dirtime
**)a
)->fn
);
1956 /* return namecmp((*(dirtime **)b)->fn, (*(dirtime **)a)->fn); */
1961 #if 0 /* not used in Unix, but maybe for future OSes? */
1963 /************************/
1964 /* Function namecmp() */
1965 /************************/
1967 static int namecmp(s1
, s2
) /* [not] used by dircomp(); swiped from Zip */
1968 ZCONST
char *s1
, *s2
;
1973 d
= (int)(uch
)case_map(*s1
)
1974 - (int)(uch
)case_map(*s2
);
1976 if (d
|| *s1
== 0 || *s2
== 0)
1985 #endif /* SET_DIR_ATTRIB */