Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | #include "stdafx.h" |
2 | #pragma hdrstop |
||
3 | #include "ZStrings.h" |
||
4 | #include "ZipOp.h" |
||
5 | #include "dz_errs.h" |
||
6 | |||
7 | #undef _DZ_FILE_ |
||
8 | #define _DZ_FILE_ DZ_ZIPREAD_CPP |
||
9 | |||
10 | /* ZipFile.c Copyright (C) 1990-1996 |
||
11 | Mark Adler, Richard B. Wales, Jean-loup Gailly, Kai Uwe Rommel, |
||
12 | Onno van der Linden and Igor Mandrichenko. |
||
13 | This version modified by Chris Vleghert and Eric Engler for BCB/Delphi Zip. |
||
14 | * distributed under LGPL license ** see license.txt for details |
||
15 | |||
16 | Copyright (c) 1990-2007 Info-ZIP. All rights reserved. |
||
17 | |||
18 | See the accompanying file LICENSE, version 2007-Mar-4 or later |
||
19 | (the contents of which are also included in zip.h) for terms of use. |
||
20 | If, for some reason, all these files are missing, the Info-ZIP license |
||
21 | also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html |
||
22 | |||
23 | parts Copyright (C) 1997 Mike White, Eric W. Engler |
||
24 | ************************************************************************ |
||
25 | Copyright (C) 2009, 2010 by Russell J. Peters, Roger Aelbrecht |
||
26 | |||
27 | This file is part of TZipMaster Version 1.9. |
||
28 | |||
29 | TZipMaster is free software: you can redistribute it and/or modify |
||
30 | it under the terms of the GNU Lesser General Public License as published by |
||
31 | the Free Software Foundation, either version 3 of the License, or |
||
32 | (at your option) any later version. |
||
33 | |||
34 | TZipMaster is distributed in the hope that it will be useful, |
||
35 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
37 | GNU Lesser General Public License for more details. |
||
38 | |||
39 | You should have received a copy of the GNU Lesser General Public License |
||
40 | along with TZipMaster. If not, see <http://www.gnu.org/licenses/>. |
||
41 | |||
42 | contact: problems@delphizip.org (include ZipMaster in the subject). |
||
43 | updates: http://www.delphizip.org |
||
44 | DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip |
||
45 | ************************************************************************/ |
||
46 | |||
47 | // -- Structure of a ZIP file -- |
||
48 | // Signatures for zip file information headers |
||
49 | #define LOCSIG 0x04034b50L |
||
50 | #define CENSIG 0x02014b50L |
||
51 | #define ENDSIG 0x06054b50L |
||
52 | #define EXTLOCSIG 0x08074b50L |
||
53 | |||
54 | // Make first pass through zip file, reading information from local file |
||
55 | // headers and then verifying that information with the central file headers. |
||
56 | // Any deviation from the expected zip file format returns an error. At the |
||
57 | // end, a sorted list of file names in the zip file is made to facilitate |
||
58 | // searching by name. The name of the zip file is pointed to by the global |
||
59 | // "zipfile". The globals zfiles, zcount, zcomlen, zcomment, and zsort are |
||
60 | // filled in. Return an error code in the ZEN_xxx class. |
||
61 | // static int readzipfile1(ZGlobals *pG, HANDLE hInz); |
||
62 | int ZipOp::readzipfile(void) |
||
63 | { |
||
64 | HANDLE hInz; |
||
65 | ZipItem *z; /* current zip entry structure */ |
||
66 | int r = 0; // Initialize zip file info |
||
67 | fzipbeg = 0; |
||
68 | fcenbeg = 0; |
||
69 | fzfiles = NULL; // Points to first header |
||
70 | fzcount = 0; // number of files |
||
71 | |||
72 | // If zip file exists, read headers and check structure |
||
73 | if (fzipfile.IsEmpty()) |
||
74 | return DZ_ERR_GOOD; |
||
75 | |||
76 | if (Verbose) |
||
77 | Notify(IVERBOSE, _T("ready to open: %s for read only"), fzipfile.c_str() |
||
78 | ); |
||
79 | |||
80 | if ((hInz = CreateFile(fzipfile, GENERIC_READ, 0, NULL, OPEN_EXISTING, |
||
81 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL)) |
||
82 | != INVALID_HANDLE_VALUE) |
||
83 | { |
||
84 | diag(_T("zip archive is now open")); |
||
85 | r = readzipfile1(hInz); |
||
86 | Close_Handle(&hInz); |
||
87 | |||
88 | if (r < 0) |
||
89 | r = (GetLastError() ? DZ_ERM_ERROR_READ : DZ_ERM_ZIP_EOF); |
||
90 | } |
||
91 | |||
92 | if (r != 0) |
||
93 | return r; |
||
94 | |||
95 | // If one or more files, sort by name |
||
96 | if (fzcount) |
||
97 | { |
||
98 | fndlist = new HashListInt(fzcount); |
||
99 | |||
100 | for (z = fzfiles; z != NULL; z = z->nxt) |
||
101 | fndlist->AddNode(z); |
||
102 | } |
||
103 | |||
104 | return DZ_ERR_GOOD; |
||
105 | } |
||
106 | |||
107 | // ------------------------------------------------------------------------- |
||
108 | |||
109 | /* searches the cextra member of zlist for a zip64 extra field. if it finds one it */ |
||
110 | /* updates the len, siz and off members of zlist with the corresponding values of */ |
||
111 | /* the zip64 extra field, that is if either the len, siz or off member of zlist is */ |
||
112 | /* set to its max value we have to use the corresponding value from the zip64 extra */ |
||
113 | /* field. as of now the dsk member of zlist is not much of interest since we should */ |
||
114 | /* not modify multi volume archives at all. */ |
||
115 | static void adjust_zip_central_entry(ZipItem *z) |
||
116 | { |
||
117 | const uch* pTemp; |
||
118 | /* assume not using zip64 fields */ |
||
119 | |||
120 | /* check if we have a "large file" Zip64 extra field ... */ |
||
121 | pTemp = z->cextra.Find(ZIP64_XDATA_TAG); |
||
122 | |||
123 | if (pTemp == NULL) |
||
124 | return; |
||
125 | |||
126 | /* using zip64 field */ |
||
127 | pTemp += sizeof(XDataHead); |
||
128 | |||
129 | /* ... if so, update corresponding entries in struct zlist */ |
||
130 | if (z->len == MAX_UNSIGNED) |
||
131 | { |
||
132 | z->len = *(ZInt64*)pTemp; |
||
133 | pTemp += 8; |
||
134 | } |
||
135 | |||
136 | if (z->siz == MAX_UNSIGNED) |
||
137 | { |
||
138 | z->siz = *(ZInt64*)pTemp; |
||
139 | pTemp += 8; |
||
140 | } |
||
141 | |||
142 | if (z->off == MAX_UNSIGNED) |
||
143 | z->off = *(ZInt64*)pTemp; |
||
144 | } |
||
145 | |||
146 | # define ZIP64_EOCD_SIG 0x06064b50 |
||
147 | |||
148 | bool NeedEOC64(ZipEndOfCentral *eoc) |
||
149 | { |
||
150 | if (eoc->CentralOffset == MAX_UNSIGNED || eoc->TotalEntries == MAX_WORD || |
||
151 | eoc->CentralSize == MAX_UNSIGNED || eoc->CentralEntries == MAX_WORD || |
||
152 | eoc->ThisDiskNo == MAX_WORD || eoc->CentralDiskNo == MAX_WORD) |
||
153 | return true; |
||
154 | |||
155 | return false; |
||
156 | } |
||
157 | |||
158 | int ZipOp::readzipfile1(HANDLE hInz) |
||
159 | { |
||
160 | ZipEndOfCentral* zeoc; |
||
161 | Zip64EOCLocator* zloc; |
||
162 | ZipEOC64* zeoc64; |
||
163 | ZipCentralHeader *zcen; |
||
164 | ZipLocalHeader *zlcl; |
||
165 | ::extent n; /* length of name */ |
||
166 | ZipItem **x; /* pointer last entry's link */ |
||
167 | ZipItem *z; /* current zip entry structure */ |
||
168 | char *t; /* temporary pointer */ |
||
169 | int found; |
||
170 | char *buf; /* temp buffer for reading zipfile */ |
||
171 | DWORD k; // count of bytes read |
||
172 | int idx; |
||
173 | int cnt, CenEntries; |
||
174 | ZInt64 u8; /* unsigned 8 byte variable */ |
||
175 | ZInt64 censiz; /* size of central directory */ |
||
176 | ZInt64 z64eocd; /* Zip64 End Of Central Directory record byte offset */ |
||
177 | ZInt64 deltaoff = 0; |
||
178 | bool need64; // = false; |
||
179 | DZStrA tmp; |
||
180 | |||
181 | buf = (char*)fwindow; |
||
182 | |||
183 | found = 0; |
||
184 | t = &buf[4096]; |
||
185 | t[1] = '\0'; |
||
186 | t[2] = '\0'; |
||
187 | t[3] = '\0'; |
||
188 | fzipbeg = SetFilePointer64(hInz, -(ZInt64)sizeof(ZipEndOfCentral), |
||
189 | SEEK_END); |
||
190 | |||
191 | if (fzipbeg < 0) |
||
192 | { |
||
193 | Notify(IWARNING, _T("not a zip file")); |
||
194 | return DZ_ERM_INVAL_ZIP; |
||
195 | } |
||
196 | |||
197 | if (ReadFile(hInz, buf, sizeof(ZipEndOfCentral), &k, NULL) && k == sizeof |
||
198 | (ZipEndOfCentral) && *(ulg*)buf == ENDSIG) |
||
199 | found = 2; |
||
200 | else |
||
201 | { |
||
202 | fzipbeg += sizeof(ZipEndOfCentral); // size of file |
||
203 | |||
204 | idx = 16; // max 16 * 4k = 64k |
||
205 | |||
206 | while (!found && idx-- >= 0 && fzipbeg >= 0) |
||
207 | { |
||
208 | size_t sz; |
||
209 | fzipbeg -= 4096; |
||
210 | |||
211 | if (fzipbeg < 0) |
||
212 | fzipbeg = 0; |
||
213 | |||
214 | if (SetFilePointer64(hInz, fzipbeg, SEEK_SET) < 0) |
||
215 | break; |
||
216 | |||
217 | if (!ReadFile(hInz, buf, 4096 /* (size_t) fzipbeg */ , &k, NULL)) |
||
218 | break; |
||
219 | |||
220 | sz = (size_t)k; |
||
221 | buf[sz] = t[1]; |
||
222 | buf[sz + 1] = t[2]; |
||
223 | buf[sz + 2] = t[3]; |
||
224 | t = &buf[sz - 1]; |
||
225 | while (t >= buf) |
||
226 | { |
||
227 | /* Check for ENDSIG ("PK\5\6" in ASCII) */ |
||
228 | if (*(ulg*)t == ENDSIG) |
||
229 | { |
||
230 | found = 1; |
||
231 | fzipbeg += (ZInt64)(t - buf); // at the eoc |
||
232 | break; |
||
233 | } |
||
234 | |||
235 | --t; |
||
236 | } |
||
237 | } |
||
238 | } |
||
239 | |||
240 | if (!found) |
||
241 | { |
||
242 | Notify(IWARNING, _T("missing end signature--probably not a zip file")); |
||
243 | return DZ_ERM_INVAL_ZIP; |
||
244 | } |
||
245 | |||
246 | // fzipbeg at eoc offset |
||
247 | |||
248 | /* Read end header */ |
||
249 | zeoc = (ZipEndOfCentral*)fwindow; |
||
250 | SetFilePointer64(hInz, (ZInt64)fzipbeg, SEEK_SET); |
||
251 | |||
252 | if (!ReadFile(hInz, zeoc, sizeof(ZipEndOfCentral), &k, NULL) || k != sizeof |
||
253 | (ZipEndOfCentral)) |
||
254 | return-1; |
||
255 | |||
256 | if (zeoc->ThisDiskNo || zeoc->CentralDiskNo || zeoc->CentralEntries != |
||
257 | zeoc->TotalEntries) |
||
258 | Notify(IWARNING, _T("multiple disk information ignored")); |
||
259 | |||
260 | CenEntries = zeoc->CentralEntries; |
||
261 | |||
262 | if (!fzcomlen) // ignore if have new |
||
263 | { |
||
264 | fzcomlen = zeoc->ZipCommentLen; |
||
265 | |||
266 | if (fzcomlen) |
||
267 | { |
||
268 | if (!ReadFile(hInz, fzcomment.GetBuffer(fzcomlen), fzcomlen, &k, |
||
269 | NULL) || k != (DWORD)fzcomlen) |
||
270 | { |
||
271 | fzcomment.Empty(); |
||
272 | return-1; |
||
273 | } |
||
274 | } |
||
275 | } |
||
276 | |||
277 | need64 = NeedEOC64(zeoc); |
||
278 | if (need64) |
||
279 | { |
||
280 | /* account for Zip64 EOCD Record and Zip64 EOCD Locator */ |
||
281 | /* Z64 EOCDL must be just before EOCD if it exists */ |
||
282 | fcenbeg = fzipbeg-sizeof(Zip64EOCLocator); |
||
283 | |||
284 | /* check for empty archive */ |
||
285 | if (fcenbeg >= 0) |
||
286 | { |
||
287 | /* look for signature */ |
||
288 | if (SetFilePointer64(hInz, fcenbeg, SEEK_SET) == -1) |
||
289 | { |
||
290 | Notify(IWARNING, _T("end of file seeking Z64EOCLocator")); |
||
291 | return DZ_ERM_INVAL_ZIP; |
||
292 | } |
||
293 | |||
294 | zloc = (Zip64EOCLocator*)(fwindow + 128); |
||
295 | if (!ReadFile(hInz, zloc, sizeof(Zip64EOCLocator), &k, NULL) |
||
296 | || k != sizeof(Zip64EOCLocator)) |
||
297 | { |
||
298 | throw DZException(DZ_ERM_INVAL_ZIP); |
||
299 | } |
||
300 | |||
301 | if (zloc->HeaderSig == EOC64LocatorSig) |
||
302 | { |
||
303 | /* found Zip64 EOCD Locator */ |
||
304 | /* check for disk information */ |
||
305 | if (zloc->NumberDisks != 1) |
||
306 | { |
||
307 | Notify(IWARNING, _T("multiple disk archives not supported") |
||
308 | ); |
||
309 | throw DZException(DZ_ERM_ZIP_MULTI); |
||
310 | } |
||
311 | |||
312 | /* look for Zip64 EOCD Record */ |
||
313 | z64eocd = zloc->EOC64RelOfs; |
||
314 | if (SetFilePointer64(hInz, z64eocd, SEEK_SET) == -1) |
||
315 | { |
||
316 | throw DZException(DZ_ERM_INVAL_ZIP); |
||
317 | } |
||
318 | |||
319 | zeoc64 = (ZipEOC64*)(fwindow + 256); |
||
320 | if (!ReadFile(hInz, zeoc64, sizeof(ZipEOC64), &k, NULL) |
||
321 | || k != sizeof(ZipEOC64)) |
||
322 | { |
||
323 | throw DZException(DZ_ERM_INVAL_ZIP); |
||
324 | } |
||
325 | |||
326 | if (zeoc64->HeaderSig != EndCentral64Sig) |
||
327 | { |
||
328 | Notify(IWARNING, _T( |
||
329 | "Z64 EOCD not found but Z64 EOCD Locator exists")); |
||
330 | throw DZException(DZ_ERM_INVAL_ZIP); |
||
331 | } |
||
332 | |||
333 | /* get size of CD */ |
||
334 | /* get start of CD */ |
||
335 | CenEntries = zeoc->CentralEntries; |
||
336 | fcenbeg = zeoc64->CentralOffSet; |
||
337 | deltaoff = 0; // Zip64 offsets must be correct or could not locate EOC64 |
||
338 | fadjust = 0; // no adjust needed |
||
339 | } |
||
340 | else |
||
341 | { |
||
342 | /* assume no Locator and no Zip64 EOCD Record */ |
||
343 | need64 = false; |
||
344 | censiz = zeoc->CentralSize; |
||
345 | fcenbeg = censiz ? zeoc->CentralOffset : fzipbeg; |
||
346 | u8 = (fzipbeg - censiz) - fcenbeg; |
||
347 | |||
348 | if (u8) |
||
349 | { |
||
350 | if (Verbose) |
||
351 | Notify(IWARNING, _T("wrong central directory offset")); |
||
352 | } |
||
353 | else |
||
354 | fadjust = 0; // no adjust needed |
||
355 | |||
356 | deltaoff = fadjust ? u8 : 0L; |
||
357 | } |
||
358 | } |
||
359 | } |
||
360 | else |
||
361 | { |
||
362 | /* assume no Locator and no Zip64 EOCD Record */ |
||
363 | censiz = zeoc->CentralSize; |
||
364 | fcenbeg = censiz ? zeoc->CentralOffset : fzipbeg; |
||
365 | u8 = (fzipbeg - censiz) - fcenbeg; |
||
366 | |||
367 | if (u8) |
||
368 | { |
||
369 | if (Verbose) |
||
370 | Notify(IWARNING, _T("wrong central directory offset")); |
||
371 | } |
||
372 | else |
||
373 | fadjust = 0; // no adjust needed |
||
374 | |||
375 | deltaoff = fadjust ? u8 : 0L; |
||
376 | } |
||
377 | |||
378 | if (!CenEntries || (need64 && fzipbeg < sizeof(Zip64EOCLocator))) |
||
379 | { |
||
380 | /* zip file seems empty */ |
||
381 | return DZ_ERR_GOOD; |
||
382 | } |
||
383 | |||
384 | if (SetFilePointer64(hInz, fcenbeg + deltaoff, SEEK_SET) == -1) |
||
385 | { |
||
386 | Notify(IWARNING, _T("error seeking central directory")); |
||
387 | return DZ_ERM_INVAL_ZIP; |
||
388 | } |
||
389 | |||
390 | CB->UserXItem(CenEntries + CenEntries, 9, _T("*Loading central")); |
||
391 | |||
392 | cnt = 0; |
||
393 | |||
394 | x = &fzfiles; /* first link */ |
||
395 | zcen = (ZipCentralHeader*)fwindow + 512; |
||
396 | |||
397 | if (!ReadFile(hInz, zcen, 4, &k, NULL) || k != 4) |
||
398 | return-1; |
||
399 | |||
400 | while (zcen->HeaderSig == CENSIG) |
||
401 | { |
||
402 | /* Read central header. The portion of the central header that should |
||
403 | be in common with local header is read raw, for later comparison. |
||
404 | (this requires that the offset of ext in the zlist structure |
||
405 | be greater than or equal to LOCHEAD) */ |
||
406 | if (!ReadFile(hInz, &zcen->MadeBy, CENHEAD, &k, NULL) || k != CENHEAD) |
||
407 | return-1; |
||
408 | |||
409 | z = new ZipItem; |
||
410 | /* Link into list */ |
||
411 | z->nxt = NULL; |
||
412 | *x = z; // link it now so it can't get lost |
||
413 | x = &z->nxt; |
||
414 | z->vem = zcen->MadeBy; // MadeByVersion; |
||
415 | z->ver = zcen->VersionNeed; |
||
416 | z->flg = zcen->Flag; |
||
417 | z->how = zcen->ComprMethod; |
||
418 | z->tim = zcen->ModifStamp; |
||
419 | z->crc = zcen->CRC32; |
||
420 | z->siz = zcen->ComprSize; |
||
421 | z->len = zcen->UnComprSize; |
||
422 | z->nam = zcen->FileNameLen; |
||
423 | z->ext = 0; |
||
424 | z->com = zcen->FileComLen; |
||
425 | z->dsk = zcen->DiskStart; |
||
426 | z->att = zcen->IntFileAtt; |
||
427 | z->atx = zcen->ExtFileAtt; |
||
428 | z->off = zcen->RelOffLocal + deltaoff; |
||
429 | z->options.dosflag = ((z->vem & 0xff00) == 0) ? 1 : 0; |
||
430 | z->options.level = flevel; |
||
431 | z->options.noext = 0; |
||
432 | |||
433 | if (!z->nam || z->nam > MAX_PATH) |
||
434 | { |
||
435 | const TCHAR*erm = z->nam ? _T("name too long") : _T |
||
436 | ("zero-length name"); |
||
437 | Notify(IWARNING, _T("%s for entry #%lu"), erm, (ulg)fzcount + 1); |
||
438 | #ifndef DEBUG |
||
439 | return DZ_ERM_INVAL_ZIP; |
||
440 | #endif |
||
441 | } |
||
442 | |||
443 | /* Read file name, extra field and comment field */ |
||
444 | if (!ReadFile(hInz, tmp.GetBuffer(z->nam), z->nam, &k, NULL) |
||
445 | || k != z->nam) |
||
446 | return-1; |
||
447 | |||
448 | tmp.ReleaseBuffer(z->nam); |
||
449 | |||
450 | z->HName = tmp; |
||
451 | |||
452 | if (zcen->ExtraLen) |
||
453 | { |
||
454 | DZRawData xdata; |
||
455 | if (!ReadFile(hInz, xdata.GetBuffer(zcen->ExtraLen), |
||
456 | zcen->ExtraLen, &k, NULL) || k != (unsigned)zcen->ExtraLen) |
||
457 | return-1; |
||
458 | |||
459 | z->cext = zcen->ExtraLen; |
||
460 | z->cextra = xdata; |
||
461 | } |
||
462 | |||
463 | DZStrA zcom; // file comment |
||
464 | if (z->com) |
||
465 | { |
||
466 | if (!ReadFile(hInz, zcom.GetBuffer(z->com), z->com, &k, NULL) |
||
467 | || k != z->com) |
||
468 | return-1; |
||
469 | |||
470 | zcom.ReleaseBuffer(z->com); |
||
471 | } |
||
472 | |||
473 | // decode header name |
||
474 | z->Enc = IsEncoded(z->vem, z->flg & FLAG_UTF8_BIT) & 3; |
||
475 | |||
476 | if (z->Enc == zeoAuto && ValidUTF8(z->hname) > 0) |
||
477 | z->Enc = zeoUTF8; |
||
478 | DZStrW wn; |
||
479 | if (z->cext && (fEncodedAs == zeoAuto || fEncodedAs == zeoUPATH)) |
||
480 | { |
||
481 | const UPhead *up = (const UPhead*)z->cextra.Find(UPATH_XDATA_TAG); |
||
482 | if (up && up->ver == 1 && up->hed.vsize > sizeof(UPhead)) |
||
483 | { |
||
484 | ulg ocrc = crc32(0, (uch*)z->hname, z->nam); |
||
485 | if (ocrc == up->crc) |
||
486 | { |
||
487 | const char *bf = ((char*)up)+sizeof(UPhead); |
||
488 | int ulen = up->hed.vsize - 5; |
||
489 | wn = DZStrW(CP_UTF8, bf, ulen); |
||
490 | } |
||
491 | } |
||
492 | |||
493 | } |
||
494 | if (wn.IsEmpty()) |
||
495 | { |
||
496 | int UseCP = CP_THREAD_ACP; |
||
497 | switch((Encodings)z->Enc) |
||
498 | { |
||
499 | case zeoAuto: |
||
500 | case zeoNone: |
||
501 | UseCP = fFromPage; |
||
502 | break; |
||
503 | |||
504 | case zeoUTF8: |
||
505 | UseCP = CP_UTF8; |
||
506 | break; |
||
507 | |||
508 | case zeoOEM: |
||
509 | UseCP = CP_OEM; |
||
510 | break; |
||
511 | } |
||
512 | wn = DZStrW(UseCP, z->hname, z->nam); |
||
513 | } |
||
514 | |||
515 | DZStrW wx, wt = StrExtSep(wn); |
||
516 | int nerr = CleanPath(wt, wx); |
||
517 | if (nerr) |
||
518 | { |
||
519 | if (Verbose) |
||
520 | Notify(IVERBOSE, _T("read file - invalid filename %s [%d]"), |
||
521 | z->hname, nerr); |
||
522 | return DZ_ERM_INVAL_NAME; |
||
523 | } |
||
524 | |||
525 | z->IName = wx; |
||
526 | z->XName = wx; |
||
527 | if (!zcom.IsEmpty()) |
||
528 | { |
||
529 | wn.Empty(); |
||
530 | if (z->Enc == zeoAuto || z->Enc == zeoUPATH) |
||
531 | { |
||
532 | const UPhead *up = (const UPhead*)z->cextra.Find |
||
533 | (UCMNT_XDATA_TAG); |
||
534 | |||
535 | if (up && up->ver == 1 && up->hed.vsize > sizeof(UPhead)) |
||
536 | { |
||
537 | ulg ocrc = crc32(0, (uch*)zcom.c_str(), z->com); |
||
538 | if (ocrc == up->crc) |
||
539 | { |
||
540 | int len = up->hed.vsize-sizeof(UPhead); |
||
541 | const char *bf = ((char*)up)+sizeof(UPhead); |
||
542 | wn = DZStrW(CP_UTF8, bf, len); |
||
543 | } |
||
544 | } |
||
545 | |||
546 | } |
||
547 | int UseCP = CP_THREAD_ACP; |
||
548 | switch((Encodings)z->Enc) |
||
549 | { |
||
550 | case zeoAuto: |
||
551 | case zeoNone: |
||
552 | UseCP = fFromPage; |
||
553 | break; |
||
554 | |||
555 | case zeoUTF8: |
||
556 | UseCP = CP_UTF8; |
||
557 | break; |
||
558 | |||
559 | case zeoOEM: |
||
560 | UseCP = CP_OEM; |
||
561 | break; |
||
562 | } |
||
563 | if (wn.IsEmpty()) |
||
564 | wn = DZStrW(UseCP, zcom.c_str(), z->com); |
||
565 | z->Comment = wn; |
||
566 | } |
||
567 | |||
568 | /* zip64 support 08/31/2003 R.Nausedat */ |
||
569 | /* here, we have to read the len, siz etc values from the CD */ |
||
570 | /* entry as we might have to adjust them regarding their */ |
||
571 | /* correspronding zip64 extra fields. */ |
||
572 | /* also, we cannot compare the values from the CD entries with */ |
||
573 | /* the values from the LH as they might be different. */ |
||
574 | /* adjust/update siz,len and off (to come: dsk) entries */ |
||
575 | /* PKZIP does not care of the version set in a CDH: if */ |
||
576 | /* there is a zip64 extra field assigned to a CDH PKZIP */ |
||
577 | /* uses it, we should do so, too. */ |
||
578 | adjust_zip_central_entry(z); |
||
579 | #ifdef _ZDEBUG |
||
580 | Notify(ITRACE, _T("readzipfile1: %s dosflag %i"), z->iname, |
||
581 | z->options.dosflag); |
||
582 | #endif |
||
583 | |||
584 | /* Update zipbeg offset, prepare for next header */ |
||
585 | if (z->off < fzipbeg) |
||
586 | fzipbeg = z->off; |
||
587 | |||
588 | fzcount++; |
||
589 | |||
590 | if (Verbose < 0) |
||
591 | Notify(ITRACE, _T("read file [%d] %s"), fzcount, z->xname); |
||
592 | |||
593 | /* Read next signature */ |
||
594 | zcen = (ZipCentralHeader*)fwindow + 512; |
||
595 | |||
596 | if (!ReadFile(hInz, zcen, 4, &k, NULL) || k != 4) |
||
597 | return-1; |
||
598 | |||
599 | if (++cnt >= 10) |
||
600 | { |
||
601 | CB->UserXProgress(cnt, 9); |
||
602 | cnt = 0; |
||
603 | |||
604 | if (Abort_Flag) |
||
605 | Fatal(DZ_ERM_ABORT, 0); |
||
606 | } |
||
607 | } |
||
608 | |||
609 | /* Point to start of header list and read local headers */ |
||
610 | idx = 0; |
||
611 | |||
612 | z = fzfiles; |
||
613 | |||
614 | while (z != NULL) |
||
615 | { |
||
616 | if (Verbose < 0) |
||
617 | Notify(ITRACE, _T("checking file [%d] %s"), ++idx, z->iname); |
||
618 | |||
619 | /* Read next signature */ |
||
620 | zlcl = (ZipLocalHeader*)fwindow + 640; |
||
621 | |||
622 | if (SetFilePointer64(hInz, z->off, SEEK_SET) < 0 || !ReadFile |
||
623 | (hInz, zlcl, sizeof(ZipLocalHeader), &k, NULL) || k != sizeof(ZipLocalHeader)) |
||
624 | return-1; |
||
625 | |||
626 | if (zlcl->HeaderSig != LOCSIG) |
||
627 | { |
||
628 | Notify(IWARNING, _T("local header not found for %s"), z->iname); |
||
629 | return DZ_ERM_INVAL_ZIP; |
||
630 | } |
||
631 | |||
632 | z->lflg = zlcl->Flag; |
||
633 | |||
634 | n = zlcl->FileNameLen; |
||
635 | z->ext = zlcl->ExtraLen; |
||
636 | bool IsProblematic = false; |
||
637 | |||
638 | if ((z->atx & 0xFFFF0000u) != 0 && z->vem == FS_FAT && |
||
639 | (z->ver == 25 || z->ver == 26 || z->ver == 40)) |
||
640 | IsProblematic = true; |
||
641 | |||
642 | /* Compare name and extra fields */ |
||
643 | if (n != z->nam) |
||
644 | { |
||
645 | Notify(IWARNING, _T("name lengths in local and central differ for %s"), |
||
646 | z->iname); |
||
647 | |||
648 | if (!IsProblematic) // unreliable in PKZIP |
||
649 | return DZ_ERM_INVAL_ZIP; |
||
650 | } |
||
651 | |||
652 | if (!ReadFile(hInz, tmp.GetBuffer(z->nam + 1), z->nam, &k, NULL) |
||
653 | || k != z->nam) |
||
654 | { |
||
655 | return-1; |
||
656 | } |
||
657 | |||
658 | tmp.ReleaseBuffer(); |
||
659 | |||
660 | if (memcmp(tmp.c_str(), z->hname, z->nam) && |
||
661 | (!IsProblematic || !ZMatch(tmp, z->iname))) |
||
662 | { |
||
663 | Notify(IWARNING, _T("names in local and central differ for %s"), |
||
664 | z->iname); |
||
665 | if (!IsProblematic) // unreliable in PKZIP |
||
666 | { |
||
667 | return DZ_ERM_INVAL_ZIP; |
||
668 | } |
||
669 | } |
||
670 | |||
671 | if (z->ext) |
||
672 | { |
||
673 | DZRawData tmp; |
||
674 | |||
675 | if (!ReadFile(hInz, tmp.GetBuffer(z->ext), z->ext, &k, NULL) |
||
676 | || k != (DWORD)z->ext) |
||
677 | { |
||
678 | z->extra = NULL; |
||
679 | return-1; |
||
680 | } |
||
681 | tmp.SetLength(z->ext); |
||
682 | z->extra = tmp; |
||
683 | } |
||
684 | |||
685 | /* Clear actions */ |
||
686 | z->mark = 0; |
||
687 | z->trash = 0; |
||
688 | z = z->nxt; |
||
689 | if (++cnt >= 5) |
||
690 | { |
||
691 | CB->UserXProgress(cnt, 9); |
||
692 | cnt = 0; |
||
693 | |||
694 | if (Abort_Flag) |
||
695 | break; |
||
696 | } |
||
697 | } |
||
698 | |||
699 | if (cnt) |
||
700 | CB->UserXProgress(cnt, 9); // last few |
||
701 | |||
702 | return DZ_ERR_GOOD; |
||
703 | } |