Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | #include "stdafx.h" |
2 | #pragma hdrstop |
||
3 | #include "dz_errs.h" |
||
4 | |||
5 | #undef _DZ_FILE_ |
||
6 | #define _DZ_FILE_ DZ_UNZPROC_CPP |
||
7 | /* |
||
8 | Process.c - |
||
9 | |||
10 | Copyright (c) 1990-2007 Info-ZIP. All rights reserved. |
||
11 | |||
12 | See the accompanying file LICENSE, version 2007-Mar-4 or later |
||
13 | (the contents of which are also included in zip.h) for terms of use. |
||
14 | If, for some reason, all these files are missing, the Info-ZIP license |
||
15 | also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html |
||
16 | |||
17 | parts Copyright (C) 1997 Mike White, Eric W. Engler |
||
18 | ************************************************************************ |
||
19 | Copyright (C) 2009, 2010 by Russell J. Peters, Roger Aelbrecht |
||
20 | |||
21 | This file is part of TZipMaster Version 1.9. |
||
22 | |||
23 | TZipMaster is free software: you can redistribute it and/or modify |
||
24 | it under the terms of the GNU Lesser General Public License as published by |
||
25 | the Free Software Foundation, either version 3 of the License, or |
||
26 | (at your option) any later version. |
||
27 | |||
28 | TZipMaster is distributed in the hope that it will be useful, |
||
29 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
31 | GNU Lesser General Public License for more details. |
||
32 | |||
33 | You should have received a copy of the GNU Lesser General Public License |
||
34 | along with TZipMaster. If not, see <http://www.gnu.org/licenses/>. |
||
35 | |||
36 | contact: problems@delphizip.org (include ZipMaster in the subject). |
||
37 | updates: http://www.delphizip.org |
||
38 | DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip |
||
39 | *********************************************************************** */ |
||
40 | |||
41 | /* --------------------------------------------------------------------------- |
||
42 | * process.c |
||
43 | * This file contains the top-level routines for processing multiple zipfiles. |
||
44 | * Contains: process_zipfiles() |
||
45 | * do_seekable() |
||
46 | * find_ecrec() |
||
47 | * uz_end_central() |
||
48 | * process_cdir_file_hdr() |
||
49 | * get_cdir_ent() |
||
50 | * process_local_file_hdr() |
||
51 | * ef_scan_for_izux() |
||
52 | *--------------------------------------------------------------------------- */ |
||
53 | |||
54 | #include "UnzOp.h" |
||
55 | #include <stdio.h> |
||
56 | |||
57 | /* =========================================================================== |
||
58 | * Function process_zipfiles() |
||
59 | * return PK-type error code |
||
60 | */ |
||
61 | void UnzOpr::process_zipfiles(void) |
||
62 | { |
||
63 | int NumWinFiles, NumLoseFiles, NumWarnFiles; |
||
64 | int NumMissDirs, NumMissFiles; |
||
65 | int error; // , error_in_archive = 0; |
||
66 | |||
67 | if (Verbose < 0) |
||
68 | Notify(ITRACE, _T("In process_zipfiles")); |
||
69 | |||
70 | fhold = finbuf + INBUFSIZ; |
||
71 | /* to check for boundary-spanning sigs */ |
||
72 | |||
73 | if (Verbose < 0) |
||
74 | Notify(ITRACE, _T("two")); |
||
75 | /* --------------------------------------------------------------------------- |
||
76 | * Match (possible) wildcard zipfile specification with existing files and |
||
77 | * attempt to process each. If no hits, try again after appending ".zip" |
||
78 | * suffix. If still no luck, give up. |
||
79 | *--------------------------------------------------------------------------- */ |
||
80 | NumWinFiles = NumLoseFiles = NumWarnFiles = 0; |
||
81 | NumMissDirs = NumMissFiles = 0; |
||
82 | if (Verbose < 0) |
||
83 | Notify(ITRACE, _T("four in process.c")); // - ready to dowild"); |
||
84 | |||
85 | if (DZ_ERR(error = do_seekable(0)) == PK_WARN) |
||
86 | ++NumWarnFiles; |
||
87 | else if (error == IZ_DIR) |
||
88 | ++NumMissDirs; |
||
89 | else if (DZ_ERR(error) == PK_NOZIP) |
||
90 | ++NumMissFiles; |
||
91 | else if (error) |
||
92 | ++NumLoseFiles; |
||
93 | else |
||
94 | ++NumWinFiles; |
||
95 | |||
96 | if (Verbose < 0) |
||
97 | { |
||
98 | Notify(ITRACE, _T( |
||
99 | "after do_seekable, warn=%d missdir=%d missfi=%d losefi=%d winfi=%d") |
||
100 | , NumWarnFiles, NumMissDirs, NumMissFiles, NumLoseFiles, |
||
101 | NumWinFiles); |
||
102 | |||
103 | Notify(ITRACE, _T("do_seekable(0) returns %d"), error); |
||
104 | } |
||
105 | |||
106 | if (Verbose < 0) |
||
107 | Notify(ITRACE, _T("six")); |
||
108 | /* --------------------------------------------------------------------------- |
||
109 | * Print summary of all zipfiles, assuming zipfile spec was a wildcard (no |
||
110 | * need for a summary if just one zipfile). |
||
111 | *--------------------------------------------------------------------------- */ |
||
112 | if ((NumWinFiles > 1) || (NumWinFiles == 1 && NumMissDirs + NumMissFiles + |
||
113 | NumLoseFiles + NumWarnFiles > 0)) |
||
114 | Notify(0, _T("files processed OK")); |
||
115 | if (NumWarnFiles > 0) |
||
116 | Notify(0, _T("warnings were given")); |
||
117 | if (NumLoseFiles > 0 || NumMissFiles > 0) |
||
118 | Notify(0, _T("file(s) not found")); |
||
119 | if (NumMissDirs == 1) |
||
120 | Notify(0, _T("zip file was dir")); |
||
121 | else if (NumMissDirs > 0) |
||
122 | Notify(0, _T("many zip file were dirs")); |
||
123 | if (NumWinFiles + NumLoseFiles + NumWarnFiles == 0) |
||
124 | Notify(0, _T("no files found")); |
||
125 | |||
126 | if (Verbose < 0) |
||
127 | Notify(ITRACE, _T("seven")); |
||
128 | /* free allocated memory */ |
||
129 | inflate_free(); |
||
130 | |||
131 | if (foutbuf2) |
||
132 | delete[]foutbuf2; |
||
133 | return; |
||
134 | } |
||
135 | /* end function process_zipfiles() */ |
||
136 | |||
137 | /* =========================================================================== |
||
138 | * Function do_seekable() |
||
139 | * return PK-type error code */ |
||
140 | int UnzOpr::do_seekable(int lastchance) |
||
141 | { |
||
142 | /* static int no_ecrec = FALSE; SKM: moved to globals.h */ |
||
143 | ulg sig; |
||
144 | struct stati64 stt64; |
||
145 | int maybe_exe = false; |
||
146 | int too_weird_to_continue = false; |
||
147 | int error = 0, error_in_archive; |
||
148 | |||
149 | if (Verbose < 0) |
||
150 | Notify(ITRACE, _T("starting do_seekable")); |
||
151 | |||
152 | /* --------------------------------------------------------------------------- |
||
153 | * Open the zipfile for reading in BINARY mode to prevent CR/LF translation, |
||
154 | * which would corrupt the bit streams. |
||
155 | *--------------------------------------------------------------------------- */ |
||
156 | if (_tstati64(fzipfn, &stt64) || (error = S_ISDIR(stt64.st_mode)) != 0) |
||
157 | return error ? IZ_DIR : PK_NOZIP; |
||
158 | |||
159 | fziplen = stt64.st_size; |
||
160 | |||
161 | if (stt64.st_mode & S_IEXEC) |
||
162 | maybe_exe = true; |
||
163 | /* might find unzip, not unzip.zip; etc. */ |
||
164 | |||
165 | if (Verbose) // < 0) |
||
166 | Notify(ITRACE, _T("opening zip file; fname=%s"), fzipfn.c_str()); |
||
167 | fUnzInfile = NULL; |
||
168 | AutoStream uzfile(&fUnzInfile); |
||
169 | |||
170 | fUnzInfile = new ZFile(this, fzipfn, |
||
171 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS); |
||
172 | if (!uzfile.Stream()->IsOpen()) |
||
173 | { |
||
174 | if (Verbose < 0) |
||
175 | Notify(ITRACE, _T("could not open: %s [%s]"), fzipfn.c_str(), |
||
176 | SysMsg().c_str()); |
||
177 | |||
178 | throw DZException(DZ_ERM_ERROR_CREATE); |
||
179 | } |
||
180 | |||
181 | if (Verbose < 0) |
||
182 | Notify(ITRACE, _T("zip file %s opened OK"), fzipfn.c_str()); |
||
183 | /* the stat() test above, but... */ |
||
184 | // if (Verbose < 0) |
||
185 | // Notify(ITRACE, "do_seekable, loc 3"); |
||
186 | |||
187 | /* --------------------------------------------------------------------------- |
||
188 | * Find and process the end-of-central-directory header. UnZip need only |
||
189 | * check last 65557 bytes of zipfile: comment may be up to 65535, end-of- |
||
190 | * central-directory record is 18 bytes, and signature itself is 4 bytes; |
||
191 | * add some to allow for appended garbage. |
||
192 | *--------------------------------------------------------------------------- */ |
||
193 | |||
194 | fcur_zipfile_bufstart = 0; |
||
195 | finptr = finbuf; |
||
196 | |||
197 | #ifdef TIMESTAMP |
||
198 | if (!fqflag && !fT_flag) |
||
199 | #else |
||
200 | if (!fqflag) |
||
201 | #endif |
||
202 | |||
203 | Notify(0, _T("Archive: %s"), fzipfn.c_str()); |
||
204 | |||
205 | if (Verbose < 0) |
||
206 | Notify(ITRACE, _T("do_seekable, loc 4")); |
||
207 | if ((((error_in_archive = find_ecrec(MIN(fziplen, 66000L))) != 0 || |
||
208 | ((error_in_archive = uz_end_central()) != 0 && DZ_ERR |
||
209 | (error_in_archive) != PK_WARN)))) |
||
210 | { |
||
211 | delete fUnzInfile; |
||
212 | fUnzInfile = NULL; |
||
213 | |||
214 | if (maybe_exe) |
||
215 | Notify(0, _T("maybe an EXE file: %s"), fzipfn.c_str()); |
||
216 | if (lastchance) |
||
217 | return error_in_archive; |
||
218 | else |
||
219 | { |
||
220 | fno_ecrec = true; |
||
221 | /* assume we found wrong file: e.g., */ |
||
222 | return PK_NOZIP; |
||
223 | /* unzip instead of unzip.zip */ |
||
224 | } |
||
225 | } |
||
226 | |||
227 | if (Verbose < 0) |
||
228 | Notify(ITRACE, _T("do_seekable, loc 5")); |
||
229 | if (fzflag > 0) |
||
230 | { |
||
231 | delete fUnzInfile; |
||
232 | fUnzInfile = NULL; |
||
233 | return error_in_archive; |
||
234 | } |
||
235 | |||
236 | /* --------------------------------------------------------------------------- |
||
237 | * Test the end-of-central-directory info for incompatibilities (multi-disk |
||
238 | * archives) or inconsistencies (missing or extra bytes in zipfile). |
||
239 | *--------------------------------------------------------------------------- */ |
||
240 | #ifdef NO_MULTIPART |
||
241 | error = (fecrec.number_this_disk == 1) && (fecrec.num_disk_start_cdir == 1); |
||
242 | #else |
||
243 | error = (fecrec.number_this_disk != 0); |
||
244 | #endif |
||
245 | #ifdef NO_MULTIPART /* concatenation of multiple parts works in some cases */ |
||
246 | // else |
||
247 | if (!error && fecrec.number_this_disk != 0) |
||
248 | { |
||
249 | DZError(DZ_ERM_ZIP_MULTI); |
||
250 | error_in_archive = PK_FIND; |
||
251 | too_weird_to_continue = true; |
||
252 | } |
||
253 | #endif |
||
254 | |||
255 | if (Verbose < 0) |
||
256 | Notify(ITRACE, _T("do_seekable, loc 6")); |
||
257 | if (!too_weird_to_continue) |
||
258 | { |
||
259 | /* (relatively) normal zipfile: go for it */ |
||
260 | if (error) |
||
261 | { |
||
262 | Notify(0, _T("maybe a pak bug in %s"), fzipfn.c_str()); |
||
263 | error_in_archive = PK_WARN; |
||
264 | } |
||
265 | |||
266 | if ((fextra_bytes = freal_ecrec_offset - fexpect_ecrec_offset) < 0L) |
||
267 | { |
||
268 | Notify(0, _T("missing bytes in zipfile")); |
||
269 | error_in_archive = PK_ERR; |
||
270 | } |
||
271 | else if (fextra_bytes > 0) |
||
272 | { |
||
273 | if ((fecrec.offset_start_central_directory == 0) && |
||
274 | (fecrec.size_central_directory != 0)) |
||
275 | { |
||
276 | /* zip 1.5 -go bug */ |
||
277 | Notify(0, _T("NULL central dir")); |
||
278 | fecrec.offset_start_central_directory = fextra_bytes; |
||
279 | fextra_bytes = 0; |
||
280 | error_in_archive = PK_ERR; |
||
281 | } |
||
282 | else |
||
283 | { |
||
284 | Notify(0, _T("Warning: extra bytes at start of zipfile")); |
||
285 | error_in_archive = PK_WARN; |
||
286 | } |
||
287 | } |
||
288 | |||
289 | /* ----------------------------------------------------------------------- |
||
290 | * Check for empty zipfile and exit now if so. |
||
291 | *----------------------------------------------------------------------- */ |
||
292 | if (Verbose < 0) |
||
293 | Notify(ITRACE, _T("do_seekable, loc 7")); |
||
294 | if (fexpect_ecrec_offset == 0L && fecrec.size_central_directory == 0) |
||
295 | { |
||
296 | Notify(0, _T("Empty zipfile")); |
||
297 | delete fUnzInfile; |
||
298 | fUnzInfile = NULL; |
||
299 | return PK_ERR_NOWARN(error_in_archive) ? error_in_archive : PK_WARN; |
||
300 | } |
||
301 | |||
302 | /* ----------------------------------------------------------------------- |
||
303 | * Compensate for missing or extra bytes, and seek to where the start |
||
304 | * of central directory should be. If header not found, uncompensate |
||
305 | * and try again (necessary for at least some Atari archives created |
||
306 | * with STZip, as well as archives created by J.H. Holm's ZIPSPLIT 1.1). |
||
307 | *----------------------------------------------------------------------- */ |
||
308 | zlseek(fecrec.offset_start_central_directory); |
||
309 | #ifdef OLD_SEEK_TEST |
||
310 | if (readbuf((char*) & sig, 4) == 0) |
||
311 | { |
||
312 | close(fzipfd); |
||
313 | fzipfd = 0; |
||
314 | /* RCV added 29-1-99 */ |
||
315 | return PK_ERR; |
||
316 | /* file may be locked, or possibly disk error(?) */ |
||
317 | } |
||
318 | |||
319 | if (strncmp(fsig, fcentral_hdr_sig, 4)) |
||
320 | #else |
||
321 | if ((readbuf((char*) & sig, 4) == 0) || sig != CentralFileHeaderSig) |
||
322 | #endif |
||
323 | { |
||
324 | if (Verbose < 0) |
||
325 | Notify(ITRACE, _T("central dir found")); |
||
326 | fextra_bytes = 0; |
||
327 | zlseek(fecrec.offset_start_central_directory); |
||
328 | if ((readbuf((char*) & sig, 4) == 0) |
||
329 | || sig != CentralFileHeaderSig) |
||
330 | { |
||
331 | DZError(DZ_ERM_NO_CENTRAL); |
||
332 | delete fUnzInfile; |
||
333 | fUnzInfile = NULL; |
||
334 | |||
335 | return PK_BADERR; |
||
336 | } |
||
337 | |||
338 | Notify(0, _T("central dir too long")); |
||
339 | error_in_archive = PK_ERR; |
||
340 | } |
||
341 | |||
342 | /* ----------------------------------------------------------------------- |
||
343 | * Seek to the start of the central directory one last time, since we |
||
344 | * have just read the first entry's signature bytes; then list, extract |
||
345 | * or test member files as instructed, and close the zipfile. |
||
346 | *----------------------------------------------------------------------- */ |
||
347 | if (Verbose < 0) |
||
348 | Notify(ITRACE, _T("about to extract files (error = %d)"), |
||
349 | error_in_archive); |
||
350 | zlseek(fecrec.offset_start_central_directory); |
||
351 | // GO DO EXTRACT OR TEST |
||
352 | error = extract_or_test_files(); |
||
353 | /* EXTRACT OR TEST 'EM */ |
||
354 | |||
355 | if (Verbose < 0) |
||
356 | Notify(ITRACE, _T("Done with extract/list files (error = %d)"), |
||
357 | error); |
||
358 | if (error > error_in_archive) /* don't overwrite stronger error */ |
||
359 | error_in_archive = error; |
||
360 | /* with (for example) a warning */ |
||
361 | } |
||
362 | /* end if (!too_weird_to_continue) */ |
||
363 | |||
364 | delete fUnzInfile; |
||
365 | fUnzInfile = NULL; |
||
366 | |||
367 | return error_in_archive; |
||
368 | } |
||
369 | |||
370 | /* end function do_seekable() */ |
||
371 | |||
372 | /** ******************** */ |
||
373 | /* Function rec_find() */ |
||
374 | /** ******************** */ |
||
375 | |||
376 | /* return 0 when rec found, 1 when not found, 2 in case of read error */ |
||
377 | int UnzOpr::rec_find(ZInt64 searchlen, ulg signature, int rec_size) |
||
378 | { |
||
379 | int i, numblks, found = FALSE; |
||
380 | ZInt64 tail_len; |
||
381 | |||
382 | /* --------------------------------------------------------------------------- |
||
383 | Zipfile is longer than INBUFSIZ: may need to loop. Start with short |
||
384 | block at end of zipfile (if not TOO short). |
||
385 | --------------------------------------------------------------------------- */ |
||
386 | |||
387 | if ((tail_len = fziplen % INBUFSIZ) > rec_size) |
||
388 | { |
||
389 | fcur_zipfile_bufstart = fUnzInfile->SetPosition(fziplen - tail_len, |
||
390 | SEEK_SET); |
||
391 | if ((fincnt = vclRead((char*)finbuf, (unsigned int)tail_len)) != (int) |
||
392 | tail_len) |
||
393 | return 2; /* it's expedient... */ |
||
394 | |||
395 | /* 'P' must be at least (rec_size+4) bytes from end of zipfile */ |
||
396 | for (finptr = finbuf + (int)tail_len - (rec_size + 4); |
||
397 | finptr >= finbuf; --finptr) |
||
398 | { |
||
399 | if (*(ulg*)finptr == signature) |
||
400 | { |
||
401 | // if ((*finptr == (uch)0x50) && /* ASCII 'P' */ |
||
402 | // !strncmp((char *)finptr, signature, 4)) { |
||
403 | fincnt -= (int)(finptr - finbuf); |
||
404 | found = TRUE; |
||
405 | break; |
||
406 | } |
||
407 | } |
||
408 | /* sig may span block boundary: */ |
||
409 | memcpy((char*)fhold, (char*)finbuf, 3); |
||
410 | } |
||
411 | else |
||
412 | fcur_zipfile_bufstart = fziplen - tail_len; |
||
413 | |||
414 | /* ----------------------------------------------------------------------- |
||
415 | Loop through blocks of zipfile data, starting at the end and going |
||
416 | toward the beginning. In general, need not check whole zipfile for |
||
417 | signature, but may want to do so if testing. |
||
418 | ----------------------------------------------------------------------- */ |
||
419 | |||
420 | numblks = (int)((searchlen - tail_len + (INBUFSIZ - 1)) / INBUFSIZ); |
||
421 | /* ==amount= ==done== ==rounding== =blksiz= */ |
||
422 | |||
423 | for (i = 1; !found && (i <= numblks); ++i) |
||
424 | { |
||
425 | fcur_zipfile_bufstart -= INBUFSIZ; |
||
426 | fUnzInfile->SetPosition(fcur_zipfile_bufstart, SEEK_SET); |
||
427 | if ((fincnt = vclRead((char*)finbuf, INBUFSIZ)) != INBUFSIZ) |
||
428 | return 2; /* read error is fatal failure */ |
||
429 | |||
430 | for (finptr = finbuf + INBUFSIZ - 1; finptr >= finbuf; --finptr) |
||
431 | if (*(ulg*)finptr == signature) |
||
432 | { |
||
433 | // if ((*finptr == (uch)0x50) && /* ASCII 'P' */ |
||
434 | // !strncmp((char *)finptr, signature, 4)) { |
||
435 | fincnt -= (int)(finptr - finbuf); |
||
436 | found = TRUE; |
||
437 | break; |
||
438 | } |
||
439 | /* sig may span block boundary: */ |
||
440 | memcpy((char*)fhold, (char*)finbuf, 3); |
||
441 | } |
||
442 | return(found ? 0 : 1); |
||
443 | } /* end function rec_find() */ |
||
444 | |||
445 | /** ***************************** */ |
||
446 | /* Function check_ecrec_zip64() */ |
||
447 | /** ***************************** */ |
||
448 | |||
449 | int UnzOpr::check_ecrec_zip64(void) |
||
450 | { |
||
451 | return fecrec.offset_start_central_directory == 0xFFFFFFFFL || |
||
452 | fecrec.size_central_directory == 0xFFFFFFFFL || |
||
453 | fecrec.total_entries_central_dir == 0xFFFF || |
||
454 | fecrec.num_entries_centrl_dir_ths_disk == 0xFFFF || |
||
455 | fecrec.num_disk_start_cdir == 0xFFFF || fecrec.number_this_disk == |
||
456 | 0xFFFF; |
||
457 | } /* end function check_ecrec_zip64() */ |
||
458 | |||
459 | /** ************************ */ |
||
460 | /* Function find_ecrec64() */ |
||
461 | /** ************************ */ |
||
462 | # define NUMBER_THIS_DISK64 16 |
||
463 | # define NUM_DISK_WITH_START_CEN_DIR64 20 |
||
464 | # define NUM_ENTRIES_CEN_DIR_THS_DISK64 24 |
||
465 | # define TOTAL_ENTRIES_CENTRAL_DIR64 32 |
||
466 | # define SIZE_CENTRAL_DIRECTORY64 40 |
||
467 | # define OFFSET_START_CENTRAL_DIRECTORY64 48 |
||
468 | |||
469 | int UnzOpr::find_ecrec64(ZInt64 searchlen) /* return PK-class error */ |
||
470 | { |
||
471 | uch byterec[ECREC64_SIZE + 4]; |
||
472 | |||
473 | switch(rec_find(searchlen, EndCentral64Sig /* fend_central64_sig */ , |
||
474 | ECREC64_SIZE)) |
||
475 | { |
||
476 | case 1: |
||
477 | return PK_OK; |
||
478 | case 2: |
||
479 | // if (uO.qflag || uO.zipinfo_mode) |
||
480 | // Info(slide, 0x401, ((char *)slide, "[%s]\n", fzipfn)); |
||
481 | Notify(IERROR, _T("end-of-central-dir64 signature not found [%s]"), |
||
482 | fzipfn.c_str()); |
||
483 | // Info(slide, 0x401, ((char *)slide, |
||
484 | // LoadFarString(Cent64EndSigSearchErr))); |
||
485 | return PK_ERR; |
||
486 | /* else: found ECREC64, continue! */ |
||
487 | } |
||
488 | |||
489 | freal_ecrec_offset = fcur_zipfile_bufstart + (finptr - finbuf); |
||
490 | |||
491 | if (readbuf((char*)byterec, ECREC64_SIZE + 4) == 0) |
||
492 | return PK_EOF; |
||
493 | |||
494 | if (fecrec.number_this_disk == 0xffff) |
||
495 | fecrec.number_this_disk = makelong(&byterec[NUMBER_THIS_DISK64]); |
||
496 | if (fecrec.num_disk_start_cdir == 0xffff) |
||
497 | fecrec.num_disk_start_cdir = makelong |
||
498 | (&byterec[NUM_DISK_WITH_START_CEN_DIR64]); |
||
499 | if (fecrec.num_entries_centrl_dir_ths_disk == 0xffff) |
||
500 | fecrec.num_entries_centrl_dir_ths_disk = makeint64 |
||
501 | (&byterec[NUM_ENTRIES_CEN_DIR_THS_DISK64]); |
||
502 | if (fecrec.total_entries_central_dir == 0xffff) |
||
503 | fecrec.total_entries_central_dir = makeint64 |
||
504 | (&byterec[TOTAL_ENTRIES_CENTRAL_DIR64]); |
||
505 | if (fecrec.size_central_directory == 0xffffffff) |
||
506 | fecrec.size_central_directory = makeint64 |
||
507 | (&byterec[SIZE_CENTRAL_DIRECTORY64]); |
||
508 | if (fecrec.offset_start_central_directory == 0xffffffff) |
||
509 | fecrec.offset_start_central_directory = makeint64 |
||
510 | (&byterec[OFFSET_START_CENTRAL_DIRECTORY64]); |
||
511 | |||
512 | /* We know its a big file now. The "end of the central directory" mark |
||
513 | used as break condition for the central-directory scan is the |
||
514 | "end_central64" signature. */ |
||
515 | fecrec.is_zip64_archive = TRUE; |
||
516 | return PK_COOL; |
||
517 | } /* end function find_ecrec64() */ |
||
518 | |||
519 | /* =========================================================================== |
||
520 | * Function find_ecrec() |
||
521 | */ |
||
522 | int UnzOpr::find_ecrec(ZInt64 searchlen) |
||
523 | { |
||
524 | /* return PK-class error */ |
||
525 | int // i, numblks, |
||
526 | found = false; |
||
527 | int result; |
||
528 | // /*long*/ZInt64 tail_len; |
||
529 | ec_byte_rec byterec; |
||
530 | |||
531 | if (Verbose < 0) |
||
532 | Notify(ITRACE, _T("in find_ecrec (end of central dir)")); |
||
533 | |||
534 | /* --------------------------------------------------------------------------- |
||
535 | * Treat case of short zipfile separately. |
||
536 | *-------------------------------------------------------------------------- */ |
||
537 | if (fziplen <= INBUFSIZ) |
||
538 | { |
||
539 | fUnzInfile->SetPosition(0L, SEEK_SET); |
||
540 | if ((fincnt = vclRead((char*)finbuf, (unsigned int)fziplen)) == (int) |
||
541 | fziplen) |
||
542 | /* 'P' must be at least 22 bytes from end of zipfile */ |
||
543 | for (finptr = finbuf + (int)fziplen - 22; finptr >= finbuf; |
||
544 | --finptr) |
||
545 | if (*(ulg*)finptr == EndCentralDirSig) |
||
546 | // if ((native(* finptr) == 'P') && !strncmp((char *) finptr, fend_central_sig, 4)) |
||
547 | { |
||
548 | fincnt -= (int)(finptr - finbuf); |
||
549 | found = true; |
||
550 | break; |
||
551 | } |
||
552 | |||
553 | /* --------------------------------------------------------------------------- |
||
554 | * Zipfile is longer than INBUFSIZ: may need to loop. Start with short |
||
555 | * block at end of zipfile (if not TOO short). |
||
556 | *--------------------------------------------------------------------------- */ |
||
557 | } |
||
558 | else |
||
559 | { |
||
560 | found = rec_find(searchlen, EndCentralDirSig /* fend_central_sig */ , |
||
561 | ECREC_SIZE) == 0; |
||
562 | } |
||
563 | /* end if (ziplen > INBUFSIZ) */ |
||
564 | |||
565 | /* --------------------------------------------------------------------------- |
||
566 | * Searched through whole region where signature should be without finding |
||
567 | * it. Print informational message and die a horrible death. |
||
568 | *--------------------------------------------------------------------------- */ |
||
569 | // fail: |
||
570 | if (!found) |
||
571 | { |
||
572 | // UnzErr(UEN_EOF01); |
||
573 | DZError(DZ_ERM_NO_CENTRAL); |
||
574 | return PK_ERR; |
||
575 | /* failed */ |
||
576 | } |
||
577 | |||
578 | /* --------------------------------------------------------------------------- |
||
579 | * Found the signature, so get the end-central data before returning. Do |
||
580 | * any necessary machine-type conversions (byte ordering, structure padding |
||
581 | * compensation) by reading data into character array and copying to struct. |
||
582 | *--------------------------------------------------------------------------- */ |
||
583 | freal_ecrec_offset = fcur_zipfile_bufstart + (finptr - finbuf); |
||
584 | |||
585 | if (Verbose < 0) |
||
586 | { |
||
587 | Notify(ITRACE, _T( |
||
588 | "Found end-of-central-dir signature at offset %Ld (%.8LXh)"), |
||
589 | freal_ecrec_offset, freal_ecrec_offset); |
||
590 | Notify(ITRACE, _T( |
||
591 | " from beginning of file; offset %d (%.4Xh) within block"), |
||
592 | finptr - finbuf, finptr - finbuf); |
||
593 | } |
||
594 | |||
595 | if (readbuf((char*)byterec, ECREC_SIZE + 4) == 0) |
||
596 | return PK_EOF; |
||
597 | fecrec.number_this_disk = makeword(&byterec[NUMBER_THIS_DISK]); |
||
598 | fecrec.num_disk_start_cdir = makeword |
||
599 | (&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]); |
||
600 | fecrec.num_entries_centrl_dir_ths_disk = makeword |
||
601 | (&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]); |
||
602 | fecrec.total_entries_central_dir = makeword |
||
603 | (&byterec[TOTAL_ENTRIES_CENTRAL_DIR]); |
||
604 | fecrec.size_central_directory = makelong(&byterec[SIZE_CENTRAL_DIRECTORY]); |
||
605 | fecrec.offset_start_central_directory = makelong |
||
606 | (&byterec[OFFSET_START_CENTRAL_DIRECTORY]); |
||
607 | fecrec.zipfile_comment_length = makeword(&byterec[ZIPFILE_COMMENT_LENGTH]); |
||
608 | |||
609 | if (check_ecrec_zip64()) |
||
610 | { |
||
611 | result = find_ecrec64(searchlen + 76); |
||
612 | /* 76 bytes for zip64ec & zip64 locator */ |
||
613 | if (result != PK_COOL) |
||
614 | return result; |
||
615 | } |
||
616 | |||
617 | fexpect_ecrec_offset = fecrec.offset_start_central_directory + |
||
618 | fecrec.size_central_directory; |
||
619 | return PK_COOL; |
||
620 | } |
||
621 | /* end function find_ecrec() */ |
||
622 | |||
623 | /* =========================================================================== |
||
624 | * Function uz_end_central() |
||
625 | * Get the zipfile comment (up to 64KB long), if any, and print it out. |
||
626 | * Then position the file pointer to the beginning of the central directory |
||
627 | * and fill buffer. |
||
628 | * Return PK-type error code. |
||
629 | */ |
||
630 | int UnzOpr::uz_end_central(void) |
||
631 | { |
||
632 | int error = PK_COOL; |
||
633 | return error; |
||
634 | } |
||
635 | |||
636 | /* end function uz_end_central() */ |
||
637 | |||
638 | /* =========================================================================== |
||
639 | * Function process_cdir_file_hdr() |
||
640 | * Return PK-type error code. |
||
641 | * cdir = central dir of zipfile. |
||
642 | */ |
||
643 | int UnzOpr::process_cdir_file_hdr(void) |
||
644 | { |
||
645 | int error; |
||
646 | |||
647 | if (Verbose < 0) |
||
648 | Notify(ITRACE, _T("in process_cdir_file_hdr()")); |
||
649 | |||
650 | /* --------------------------------------------------------------------------- |
||
651 | * Get central directory info, save host and method numbers, and set flag |
||
652 | * for lowercase conversion of filename, depending on the OS from which the |
||
653 | * file is coming. |
||
654 | *--------------------------------------------------------------------------- */ |
||
655 | if ((error = get_cdir_ent()) != 0) |
||
656 | { |
||
657 | if (Verbose) |
||
658 | Notify(ITRACE, _T("Error returned by get_cdir_ent call")); |
||
659 | return error; |
||
660 | } |
||
661 | fpInfo->host = fcrec.made_by; |
||
662 | int hostnum = fcrec.made_by >> 8; |
||
663 | if (hostnum > NUM_HOSTS) |
||
664 | { |
||
665 | hostnum = NUM_HOSTS; |
||
666 | fpInfo->host = (fpInfo->host & 255) | (NUM_HOSTS * 256); |
||
667 | } |
||
668 | |||
669 | if (Verbose < 0) |
||
670 | Notify(ITRACE, _T("Good entry; hostnum of file = %d"), hostnum); |
||
671 | |||
672 | /* is there a volume label? */ |
||
673 | if (IS_VOLID(fcrec.external_file_attributes) && |
||
674 | (hostnum == FS_FAT_ || hostnum == FS_HPFS_ || hostnum == FS_NTFS_ || |
||
675 | hostnum == ATARI_)) |
||
676 | { |
||
677 | fpInfo->vollabel = true; |
||
678 | } |
||
679 | else |
||
680 | fpInfo->vollabel = false; |
||
681 | fpInfo->UTF8flag = (fcrec.general_purpose_bit_flag) & FLAG_UTF8_BIT ? 1 : 0; |
||
682 | fpInfo->UNIXflag = fcrec.external_file_attributes & 0xFFFF0000u; |
||
683 | if (Verbose < 0) |
||
684 | Notify(ITRACE, _T("process_cdir_file_hdr returning PK_COOL")); |
||
685 | return PK_COOL; |
||
686 | } |
||
687 | /* end function process_cdir_file_hdr() */ |
||
688 | |||
689 | /* =========================================================================== |
||
690 | * Function get_cdir_ent() |
||
691 | * Return PK-type error code. |
||
692 | */ |
||
693 | int UnzOpr::get_cdir_ent(void) |
||
694 | { |
||
695 | ZipCentralHeader zch; |
||
696 | |||
697 | if (Verbose < 0) |
||
698 | Notify(ITRACE, _T("in get_cdir_ent")); |
||
699 | |||
700 | /* --------------------------------------------------------------------------- |
||
701 | * Read the next central directory entry and do any necessary machine-type |
||
702 | * conversions (byte ordering, structure padding compensation--do so by |
||
703 | * copying the data from the array into which it was read (byterec) to the |
||
704 | * usable struct (crec)). |
||
705 | *--------------------------------------------------------------------------- */ |
||
706 | if (readbuf((char*) & zch.MadeBy, |
||
707 | sizeof(ZipCentralHeader)-sizeof(unsigned long)) == 0) |
||
708 | { |
||
709 | if (Verbose) |
||
710 | Notify(ITRACE, _T("Central Header not found")); |
||
711 | return PK_EOF; |
||
712 | } |
||
713 | |||
714 | fcrec.made_by = zch.MadeBy; |
||
715 | fcrec.version_needed_to_extract[0] = zch.VersionNeeded[0]; |
||
716 | fcrec.version_needed_to_extract[1] = zch.VersionNeeded[1]; |
||
717 | |||
718 | fcrec.general_purpose_bit_flag = zch.Flag; |
||
719 | fcrec.compression_method = zch.ComprMethod; |
||
720 | fcrec.last_mod_file_time = zch.ModifTime; |
||
721 | fcrec.last_mod_file_date = zch.ModifDate; |
||
722 | fcrec.crc32 = zch.CRC32; |
||
723 | fcrec.csize = zch.ComprSize; |
||
724 | fcrec.ucsize = zch.UnComprSize; |
||
725 | fcrec.filename_length = zch.FileNameLen; |
||
726 | fcrec.extra_field_length = zch.ExtraLen; |
||
727 | fcrec.file_comment_length = zch.FileComLen; |
||
728 | fcrec.disk_number_start = zch.DiskStart; |
||
729 | fcrec.internal_file_attributes = zch.IntFileAtt; |
||
730 | fcrec.external_file_attributes = zch.ExtFileAtt; |
||
731 | fcrec.relative_offset_local_header = zch.RelOffLocal; |
||
732 | |||
733 | if (Verbose < 0) |
||
734 | Notify(ITRACE, _T("Found Central Directory entry, filename of len %d"), |
||
735 | fcrec.filename_length); |
||
736 | |||
737 | return PK_COOL; |
||
738 | } |
||
739 | |||
740 | /* end function get_cdir_ent() */ |
||
741 | |||
742 | /* =========================================================================== |
||
743 | * Function process_local_file_hdr() |
||
744 | */ |
||
745 | int UnzOpr::process_local_file_hdr(void) |
||
746 | { |
||
747 | /* return PK-type error code */ |
||
748 | // local_byte_hdr byterec; |
||
749 | ZipLocalHeader zlh; |
||
750 | |||
751 | /* --------------------------------------------------------------------------- |
||
752 | * Read the next local file header and do any necessary machine-type con- |
||
753 | * versions (byte ordering, structure padding compensation--do so by copy- |
||
754 | * ing the data from the array into which it was read (byterec) to the |
||
755 | * usable struct (lrec)). |
||
756 | *--------------------------------------------------------------------------- */ |
||
757 | if (readbuf((char*) & zlh.VersionNeed, |
||
758 | sizeof(ZipLocalHeader)-sizeof(unsigned long)) == 0) |
||
759 | return PK_EOF; |
||
760 | |||
761 | flrec.version_needed_to_extract[0] = zlh.VersionNeeded[0]; |
||
762 | flrec.version_needed_to_extract[1] = zlh.VersionNeeded[1]; |
||
763 | |||
764 | flrec.general_purpose_bit_flag = zlh.Flag; |
||
765 | flrec.compression_method = zlh.ComprMethod; |
||
766 | flrec.last_mod_file_time = zlh.ModifTime; |
||
767 | flrec.last_mod_file_date = zlh.ModifDate; |
||
768 | flrec.crc32 = zlh.CRC32; |
||
769 | flrec.csize = zlh.ComprSize; |
||
770 | flrec.ucsize = zlh.UnComprSize; |
||
771 | flrec.filename_length = zlh.FileNameLen; |
||
772 | flrec.extra_field_length = zlh.ExtraLen; |
||
773 | |||
774 | fcsize = flrec.csize; |
||
775 | fucsize = flrec.ucsize; |
||
776 | |||
777 | if ((flrec.general_purpose_bit_flag & FLAG_EXTEND_BIT) != 0) |
||
778 | { |
||
779 | /* can't trust local header, use central directory: */ |
||
780 | flrec.crc32 = fpInfo->crc; |
||
781 | fcsize = flrec.csize = fpInfo->compr_size; |
||
782 | fucsize = flrec.ucsize = fpInfo->uncomp_size; |
||
783 | } |
||
784 | if (Verbose < 0) |
||
785 | Notify(ITRACE, _T("found Local Header entry, filename len of %d"), |
||
786 | flrec.filename_length); |
||
787 | return PK_COOL; |
||
788 | } |
||
789 | |||
790 | /* end function process_local_file_hdr() */ |
||
791 | |||
792 | /** **************************** */ |
||
793 | /* Function getZip64Data() */ |
||
794 | /** **************************** */ |
||
795 | |||
796 | int __fastcall UnzOpr::getZip64Data(const DZRawData& extra) |
||
797 | // uch *ef_buf, unsigned ef_len) |
||
798 | { |
||
799 | unsigned eb_id; |
||
800 | unsigned eb_len; |
||
801 | |||
802 | /* --------------------------------------------------------------------------- |
||
803 | This function scans the extra field for zip64 information, ie 8-byte |
||
804 | versions of compressed file size, uncompressed file size, relative offset |
||
805 | and a 4-byte version of disk start number. |
||
806 | Sets both local header and central header fields. Not terribly clever, |
||
807 | but it means that this procedure is only called in one place. |
||
808 | --------------------------------------------------------------------------- */ |
||
809 | |||
810 | if (!extra) |
||
811 | return PK_COOL; |
||
812 | |||
813 | const uch* ef_buf = extra.begin(); |
||
814 | unsigned ef_len = extra.Length(); |
||
815 | |||
816 | // TTrace((stderr,"\ngetZip64Data: scanning extra field of length %u\n", ef_len)); |
||
817 | |||
818 | while (ef_len >= EB_HEADSIZE) |
||
819 | { |
||
820 | eb_id = makeword(EB_ID + ef_buf); |
||
821 | eb_len = makeword(EB_LEN + ef_buf); |
||
822 | |||
823 | if (eb_len > (ef_len - EB_HEADSIZE)) |
||
824 | { |
||
825 | /* discovered some extra field inconsistency! */ |
||
826 | if (Verbose) // < 0) |
||
827 | Notify(ITRACE, _T( |
||
828 | "Invalid extra data: block length %u > rest of block %u"), |
||
829 | eb_len, ef_len - EB_HEADSIZE); |
||
830 | break; |
||
831 | } |
||
832 | if (eb_id == ZIP64_XDATA_TAG) |
||
833 | { |
||
834 | |||
835 | int offset = EB_HEADSIZE; |
||
836 | |||
837 | if (fcrec.ucsize == MAX_UNSIGNED || flrec.ucsize == MAX_UNSIGNED) |
||
838 | { |
||
839 | flrec.ucsize = fcrec.ucsize = makeint64(offset + ef_buf); |
||
840 | offset += sizeof(fcrec.ucsize); |
||
841 | } |
||
842 | if (fcrec.csize == MAX_UNSIGNED || flrec.csize == MAX_UNSIGNED) |
||
843 | { |
||
844 | fcsize = flrec.csize = fcrec.csize = makeint64(offset + ef_buf); |
||
845 | offset += sizeof(fcrec.csize); |
||
846 | } |
||
847 | if (fcrec.relative_offset_local_header == MAX_UNSIGNED) |
||
848 | { |
||
849 | fcrec.relative_offset_local_header = makeint64(offset + ef_buf); |
||
850 | offset += sizeof(fcrec.relative_offset_local_header); |
||
851 | } |
||
852 | if (fcrec.disk_number_start == MAX_WORD) |
||
853 | { |
||
854 | fcrec.disk_number_start = makelong(offset + ef_buf); |
||
855 | // offset += sizeof(fcrec.disk_number_start); |
||
856 | } |
||
857 | } |
||
858 | |||
859 | /* Skip this extra field block */ |
||
860 | ef_buf += (eb_len + EB_HEADSIZE); |
||
861 | ef_len -= (eb_len + EB_HEADSIZE); |
||
862 | } |
||
863 | |||
864 | return PK_COOL; |
||
865 | } /* end function getZip64Data() */ |