Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | #include "stdafx.h" |
2 | #pragma hdrstop |
||
3 | #include <shellapi.h> |
||
4 | #include <stdlib.h> |
||
5 | #include "DZRaw.h" |
||
6 | #include "ZipOp.h" |
||
7 | #include "ZipFnc.h" |
||
8 | #include "dz_errs.h" |
||
9 | |||
10 | #undef _DZ_FILE_ |
||
11 | #define _DZ_FILE_ DZ_ZIPFILE_CPP |
||
12 | |||
13 | /* ZipFile.c Copyright (C) 1990-1996 |
||
14 | Mark Adler, Richard B. Wales, Jean-loup Gailly, Kai Uwe Rommel, |
||
15 | Onno van der Linden and Igor Mandrichenko. |
||
16 | This version modified by Chris Vleghert and Eric Engler for BCB/Delphi Zip. |
||
17 | * distributed under LGPL license ** see license.txt for details |
||
18 | |||
19 | Copyright (c) 1990-2007 Info-ZIP. All rights reserved. |
||
20 | |||
21 | See the accompanying file LICENSE, version 2007-Mar-4 or later |
||
22 | (the contents of which are also included in zip.h) for terms of use. |
||
23 | If, for some reason, all these files are missing, the Info-ZIP license |
||
24 | also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html |
||
25 | |||
26 | parts Copyright (C) 1997 Mike White, Eric W. Engler |
||
27 | ************************************************************************ |
||
28 | Copyright (C) 2009, 2010 by Russell J. Peters, Roger Aelbrecht |
||
29 | |||
30 | This file is part of TZipMaster Version 1.9. |
||
31 | |||
32 | TZipMaster is free software: you can redistribute it and/or modify |
||
33 | it under the terms of the GNU Lesser General Public License as published by |
||
34 | the Free Software Foundation, either version 3 of the License, or |
||
35 | (at your option) any later version. |
||
36 | |||
37 | TZipMaster is distributed in the hope that it will be useful, |
||
38 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
39 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
40 | GNU Lesser General Public License for more details. |
||
41 | |||
42 | You should have received a copy of the GNU Lesser General Public License |
||
43 | along with TZipMaster. If not, see <http://www.gnu.org/licenses/>. |
||
44 | |||
45 | contact: problems@delphizip.org (include ZipMaster in the subject). |
||
46 | updates: http://www.delphizip.org |
||
47 | DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip |
||
48 | ************************************************************************/ |
||
49 | #include "direct.h" |
||
50 | |||
51 | // -- Structure of a ZIP file -- |
||
52 | // Signatures for zip file information headers |
||
53 | #define LOCSIG 0x04034b50L |
||
54 | #define CENSIG 0x02014b50L |
||
55 | #define ENDSIG 0x06054b50L |
||
56 | #define EXTLOCSIG 0x08074b50L |
||
57 | |||
58 | // Added R. Aelbrecht for OEM2ISO conversion |
||
59 | #define cpAUTO 0 |
||
60 | #define cpISO 1 |
||
61 | #define cpOEM 2 |
||
62 | |||
63 | #define FS_FAT_ 0 // filesystem used by MS-DOS, OS/2, Win32 |
||
64 | #define FS_HPFS_ 6 // filesystem used by OS/2, NT |
||
65 | #define FS_NTFS_ 11 // filesystem used by Windows NT |
||
66 | |||
67 | |||
68 | // Return a pointer to the entry in zfile with the name n, or NULL if not |
||
69 | // found. n :: Name to find. |
||
70 | ZipItem *ZipFunc::zsearch(const DZStrW &name) |
||
71 | { |
||
72 | if (fzcount && fndlist) |
||
73 | { |
||
74 | ZipItem *x = (ZipItem*)fndlist->FindName(name); |
||
75 | return x; |
||
76 | } |
||
77 | |||
78 | return NULL; |
||
79 | } |
||
80 | |||
81 | |||
82 | void ZipFunc::HWriteInit(void) |
||
83 | { |
||
84 | if (!fhwbuf) |
||
85 | { |
||
86 | fhwsize = 4096; |
||
87 | fhwbuf = new unsigned char[fhwsize]; |
||
88 | } |
||
89 | |||
90 | LocXData = 0; |
||
91 | |||
92 | fhwcnt = 0; |
||
93 | } |
||
94 | |||
95 | // Write headers to a buffer |
||
96 | // if arg == NULL then reset |
||
97 | int ZipFunc::HWrite(const void *arg, int siz) |
||
98 | { |
||
99 | if (!fhwbuf) |
||
100 | { |
||
101 | fhwcnt = -1; |
||
102 | return -1; |
||
103 | } |
||
104 | |||
105 | // if error don't continue |
||
106 | if (fhwcnt < 0) |
||
107 | { |
||
108 | return -1; |
||
109 | } |
||
110 | |||
111 | if (!arg || siz < 1) |
||
112 | { |
||
113 | return fhwcnt; |
||
114 | } |
||
115 | |||
116 | while (fhwcnt + siz >= fhwsize) |
||
117 | { |
||
118 | unsigned char * b2 = new unsigned char [fhwsize + 4096]; |
||
119 | |||
120 | if (!b2) |
||
121 | { |
||
122 | fhwcnt = -1; |
||
123 | return -1; |
||
124 | } |
||
125 | |||
126 | memmove(b2, fhwbuf, fhwcnt); |
||
127 | |||
128 | delete[] fhwbuf; |
||
129 | fhwbuf = b2; |
||
130 | fhwsize += 4096; |
||
131 | } |
||
132 | |||
133 | memmove(fhwbuf + fhwcnt, arg, siz); |
||
134 | |||
135 | fhwcnt += siz; |
||
136 | return fhwcnt; |
||
137 | } |
||
138 | |||
139 | #pragma pack(push, 1) |
||
140 | struct XLocal |
||
141 | { |
||
142 | WORD Tag; |
||
143 | WORD Siz; |
||
144 | __int64 usiz; |
||
145 | __int64 clen; |
||
146 | }; |
||
147 | #pragma pack(pop) |
||
148 | |||
149 | #pragma pack(push, 1) |
||
150 | struct XNTFS |
||
151 | { |
||
152 | WORD Tag; |
||
153 | WORD Siz; |
||
154 | unsigned res; |
||
155 | WORD tg1; |
||
156 | WORD sz1; |
||
157 | }; |
||
158 | #pragma pack(pop) |
||
159 | |||
160 | // Write a local header described by *z to file *f. Return DZ_ERR_GOOD or |
||
161 | // ZEN_TEMP07. z :: Zip entry to write local header for. f :: File to write |
||
162 | // to. |
||
163 | int __fastcall ZipFunc::PutLocal(ZipItem *z) |
||
164 | { |
||
165 | ush tag; |
||
166 | int npos; |
||
167 | unsigned long k; |
||
168 | ZipLocalHeader zlh; |
||
169 | DZRawData ox = z->extra; |
||
170 | |||
171 | if (z->ntfs) |
||
172 | ox = ox - NTFS_STAMP_TAG; |
||
173 | |||
174 | if (Verbose < 0) |
||
175 | Notify(ITRACE, _T("writing Local Header: %s"), z->iname); |
||
176 | |||
177 | HWriteInit(); // reset |
||
178 | |||
179 | unsigned short UFlag = 0; |
||
180 | if (z->Enc == zeoUTF8) |
||
181 | { |
||
182 | z->options.nameutf8 = 1; |
||
183 | UFlag = FLAG_UTF8_BIT; |
||
184 | } |
||
185 | |||
186 | if (z->Enc >= zeoUTF8) |
||
187 | z->vem = OUR_VEM; |
||
188 | |||
189 | #ifdef _FORCE_Z64_ |
||
190 | z->ver = 45; |
||
191 | z->vem = OS_NTFS + 45; |
||
192 | #endif |
||
193 | if (z->siz >= MAX_UNSIGNED) |
||
194 | { |
||
195 | z->ver = 45; // need Zip64 |
||
196 | z->vem = OS_NTFS + 45; |
||
197 | } |
||
198 | |||
199 | // may have been truncated |
||
200 | z->nam = strlen(z->hname); |
||
201 | |||
202 | if (z->nam > MAX_PATH) |
||
203 | z->nam = MAX_PATH; // keep sane |
||
204 | |||
205 | zlh.HeaderSig = LOCSIG; // Should be 0x04034B50 |
||
206 | zlh.Flag = (WORD)(UFlag | z->lflg | ((z->options.level > 8) ? 2 : 0)); |
||
207 | zlh.ComprMethod = z->how; |
||
208 | zlh.ModifStamp = z->tim; |
||
209 | zlh.CRC32 = z->crc; |
||
210 | |||
211 | // allow for bad 'compression' |
||
212 | bool MakeX64 = (z->ver >= 45) || (z->len + 0x800) > MAX_UNSIGNED || |
||
213 | (z->siz + 0x800) > MAX_UNSIGNED; |
||
214 | |||
215 | if ((z->ver < 45) && (z->len >= MAX_UNSIGNED)) |
||
216 | { |
||
217 | z->flg |= FLAG_EXTEND_BIT; // use extended data for sizes |
||
218 | z->ver = 45; // must be 64 bit |
||
219 | z->vem = OS_NTFS + 45; |
||
220 | } |
||
221 | |||
222 | zlh.VersionNeed = (ush)z->ver; |
||
223 | |||
224 | zlh.ComprSize = z->siz >= MAX_UNSIGNED ? MAX_UNSIGNED : (unsigned)z->siz; |
||
225 | zlh.UnComprSize = z->len >= MAX_UNSIGNED ? MAX_UNSIGNED : (unsigned)z->len; |
||
226 | zlh.FileNameLen = (ush)z->nam; |
||
227 | zlh.ExtraLen = 0; // will be updated |
||
228 | HWrite(&zlh, sizeof(ZipLocalHeader)); |
||
229 | HWrite(z->hname, z->nam); |
||
230 | LocXData = -1; |
||
231 | npos = fhwcnt; // size without xtra data |
||
232 | |||
233 | // write Zip64 data |
||
234 | if (MakeX64) |
||
235 | { |
||
236 | XLocal xl; |
||
237 | xl.Tag = ZIP64_XDATA_TAG; |
||
238 | xl.Siz = 16; |
||
239 | xl.usiz = z->siz; |
||
240 | xl.clen = 0; // not known |
||
241 | HWrite(&xl, sizeof(xl)); |
||
242 | LocXData = npos; |
||
243 | ox -= ZIP64_XDATA_TAG; |
||
244 | } |
||
245 | |||
246 | // save utf8 name if needed |
||
247 | if (z->options.enc == zeoUPATH && z->options.nameextd) |
||
248 | { |
||
249 | DZStrA unam = StrToUTF8(StrIntSep(z->IName)); |
||
250 | unsigned ncrc = crc32(0, (uch*)z->hname, z->nam); |
||
251 | tag = UPATH_XDATA_TAG; // Info-Zip Unicode Path |
||
252 | int sz = 5 + unam.length(); |
||
253 | HWrite(&tag, 2); |
||
254 | HWrite(&sz, 2); |
||
255 | sz = 1; // version |
||
256 | HWrite(&sz, 1); |
||
257 | HWrite(&ncrc, 4); |
||
258 | HWrite(unam.c_str(), unam.length()); |
||
259 | ox = UPATH_XDATA_TAG; |
||
260 | } |
||
261 | |||
262 | if (!ox.IsEmpty()) |
||
263 | HWrite(ox, ox.Length()); |
||
264 | |||
265 | ((ZipLocalHeader *)fhwbuf)->ExtraLen = (ush)(fhwcnt - npos); |
||
266 | |||
267 | if (fhwcnt <= 0 |
||
268 | || !fZipOutfile->Write(fhwbuf, fhwcnt, &k) |
||
269 | || k != (unsigned)fhwcnt) |
||
270 | return DZ_ERM_TEMP_FAILED; |
||
271 | |||
272 | fBytesWritten += k; |
||
273 | fOutPosn += k; |
||
274 | |||
275 | // if (Verbose < 0) |
||
276 | // Notify(IDIAG, "wrote Local Header: %s [%d]", z->name, k); |
||
277 | //#ifdef ZDEBUG1 |
||
278 | //Notify(ITRACE, _T("writing Local Header: %s need %x made %x"), z->iname, z->ver, z->vem); |
||
279 | //#endif |
||
280 | #ifdef ZDEBUG |
||
281 | if (Verbose < 0) |
||
282 | { |
||
283 | const ZipLocalHeader *zc = (ZipLocalHeader *)fhwbuf; |
||
284 | Notify(ITRACE, _T("local %s need %x [%x]"), z->iname, |
||
285 | zc->VersionNeed, z->ver); |
||
286 | } |
||
287 | #endif |
||
288 | return DZ_ERR_GOOD; |
||
289 | } |
||
290 | |||
291 | // Rewrite a local header described by *z to file *f. Return DZ_ERR_GOOD or |
||
292 | // ZEN_TEMP07. z :: Zip entry to write local header for. f :: File to write |
||
293 | // to. |
||
294 | int __fastcall ZipFunc::UpdateLocal(ZipItem *z) |
||
295 | { |
||
296 | unsigned long k; |
||
297 | |||
298 | if (!LocXData || fhwcnt <= 0) |
||
299 | { |
||
300 | // something went wrong - local not written or old data missing |
||
301 | Notify(ITRACE, _T("error updating Local Header: %s"), z->iname); |
||
302 | return DZ_ERM_LOGIC_ERROR; |
||
303 | } |
||
304 | |||
305 | if (Verbose < 0) |
||
306 | Notify(ITRACE, _T("updating Local Header: %s"), z->iname); |
||
307 | |||
308 | bool is64 = z->siz >= MAX_UNSIGNED || z->len >= MAX_UNSIGNED; |
||
309 | |||
310 | XLocal *pxd = 0; |
||
311 | |||
312 | if (LocXData > 0) |
||
313 | { |
||
314 | pxd = (XLocal*) & fhwbuf[LocXData]; |
||
315 | |||
316 | if (pxd->Tag != ZIP64_XDATA_TAG) |
||
317 | pxd = 0; // should not happen |
||
318 | } |
||
319 | |||
320 | ZipLocalHeader *ploc = (ZipLocalHeader *)fhwbuf; |
||
321 | |||
322 | ploc->ComprSize = (unsigned)z->siz; |
||
323 | ploc->UnComprSize = (unsigned)z->len; |
||
324 | |||
325 | if (is64) |
||
326 | { |
||
327 | if (!pxd) |
||
328 | { |
||
329 | // cannot update without data |
||
330 | Notify(IWARNING, _T("error updating Local Header: %s"), z->iname); |
||
331 | return DZ_ERM_LOGIC_ERROR; |
||
332 | } |
||
333 | |||
334 | z->ver = 45; // must be 64 bit |
||
335 | |||
336 | z->vem = OS_NTFS + 45; |
||
337 | pxd->usiz = z->len; |
||
338 | pxd->clen = z->siz; |
||
339 | |||
340 | if (z->siz >= MAX_UNSIGNED) |
||
341 | ploc->ComprSize = MAX_UNSIGNED; |
||
342 | |||
343 | if (z->len >= MAX_UNSIGNED) |
||
344 | ploc->UnComprSize = MAX_UNSIGNED; |
||
345 | } |
||
346 | |||
347 | ploc->ComprMethod = z->how; // may have changed |
||
348 | |||
349 | if (z->ver < 45) //30) |
||
350 | z->ver = (ush)((z->how == STORE) ? 10 : 20); |
||
351 | |||
352 | ploc->VersionNeed = (ush)z->ver; |
||
353 | |||
354 | ploc->Flag = (ush)((ploc->Flag & FLAG_UTF8_BIT) | z->lflg | |
||
355 | ((z->options.level > 8) ? 2 : 0)); |
||
356 | |||
357 | ploc->ModifStamp = z->tim; |
||
358 | |||
359 | ploc->CRC32 = z->crc; |
||
360 | |||
361 | if (!fZipOutfile->Write(fhwbuf, fhwcnt, &k) |
||
362 | || k != (unsigned)fhwcnt) |
||
363 | return DZ_ERM_TEMP_FAILED; |
||
364 | |||
365 | // if (Verbose < 0) |
||
366 | // Notify(IDIAG, "updated Local Header: %s", z->name); |
||
367 | return DZ_ERR_GOOD; |
||
368 | } |
||
369 | |||
370 | // Write an extended local header described by *z to file *f. Return an |
||
371 | // error code in the ZEN_ class. z :: Zip entry to write local header for. f |
||
372 | // :: File to write to. |
||
373 | int __fastcall ZipFunc::putextended(ZipItem *z) |
||
374 | { |
||
375 | unsigned long k; |
||
376 | ZipDataDescriptor zdd; |
||
377 | ZipDataDescriptor64 zdd64; |
||
378 | |||
379 | if (Verbose < 0) |
||
380 | Notify(ITRACE, _T("writing extended Local data: %s"), z->iname); |
||
381 | |||
382 | if (z->ver >= 45) |
||
383 | { |
||
384 | zdd64.DataDescSig = EXTLOCSIG; |
||
385 | zdd64.CRC32 = z->crc; |
||
386 | zdd64.ComprSize = z->siz; |
||
387 | zdd64.UnComprSize = z->len; |
||
388 | if (!fZipOutfile->Write(&zdd64, sizeof(ZipDataDescriptor64), &k) |
||
389 | || k != sizeof(ZipDataDescriptor64)) |
||
390 | return DZ_ERM_TEMP_FAILED; |
||
391 | } |
||
392 | else |
||
393 | { |
||
394 | zdd.DataDescSig = EXTLOCSIG; |
||
395 | zdd.CRC32 = z->crc; |
||
396 | zdd.ComprSize = (unsigned)z->siz; |
||
397 | zdd.UnComprSize = (unsigned)z->len; |
||
398 | if (!fZipOutfile->Write(&zdd, sizeof(ZipDataDescriptor), &k) || |
||
399 | k != sizeof(ZipDataDescriptor)) |
||
400 | return DZ_ERM_TEMP_FAILED; |
||
401 | } |
||
402 | |||
403 | fBytesWritten += k; |
||
404 | |||
405 | fOutPosn += k; |
||
406 | return DZ_ERR_GOOD; |
||
407 | } |
||
408 | |||
409 | // Write a central header described by *z to file *f. Return an error code |
||
410 | // in the ZEN_ class. z :: Zip entry to write central header for. f :: File |
||
411 | // to write to. |
||
412 | int __fastcall ZipFunc::putcentral(ZipItem *z) |
||
413 | { |
||
414 | ush tag; |
||
415 | ush siz; |
||
416 | #pragma pack(push, 1) |
||
417 | ZInt64 dat[3]; |
||
418 | #pragma pack(pop) |
||
419 | int xargs, npos; |
||
420 | unsigned long k; |
||
421 | ZipCentralHeader zch; |
||
422 | DZRawData ox = z->cextra; |
||
423 | |||
424 | HWriteInit(); // reset |
||
425 | |||
426 | tag = ZIP64_XDATA_TAG; |
||
427 | xargs = 0; |
||
428 | |||
429 | zch.UnComprSize = z->len >= MAX_UNSIGNED ? MAX_UNSIGNED : (unsigned)z->len; |
||
430 | zch.ComprSize = z->siz >= MAX_UNSIGNED ? MAX_UNSIGNED : (unsigned)z->siz; |
||
431 | zch.RelOffLocal = z->off >= MAX_UNSIGNED ? MAX_UNSIGNED : (unsigned)z->off; |
||
432 | |||
433 | if (zch.UnComprSize == MAX_UNSIGNED) |
||
434 | dat[xargs++] = z->len; // uncompressed |
||
435 | |||
436 | if (zch.ComprSize == MAX_UNSIGNED) |
||
437 | dat[xargs++] = z->siz; // compressed |
||
438 | |||
439 | if (zch.RelOffLocal == MAX_UNSIGNED) |
||
440 | dat[xargs++] = z->off; |
||
441 | |||
442 | #ifdef _FORCE_Z64_ |
||
443 | if (!xargs) |
||
444 | { |
||
445 | zch.UnComprSize = MAX_UNSIGNED; |
||
446 | dat[xargs++] = z->len; // uncompressed |
||
447 | } |
||
448 | #endif |
||
449 | siz = (ush)(xargs ? (xargs << 3) : 0); |
||
450 | |||
451 | unsigned short UFlag = 0; |
||
452 | DZStrA zcom; |
||
453 | // unsigned cp = z->options.dosflag ? CP_OEM : CP_ACP; |
||
454 | if (z->com) |
||
455 | zcom = z->Comment.SafeNarrow(z->options.dosflag ? CP_OEM : CP_ACP); |
||
456 | // zcom = z->Comment.SafeAnsi(); |
||
457 | bool ExtCom = z->options.cmntextd; |
||
458 | |||
459 | if (ExtCom && z->Enc == zeoUTF8) |
||
460 | { |
||
461 | UFlag = FLAG_UTF8_BIT; |
||
462 | zcom = StrToUTF8(z->Comment); |
||
463 | ExtCom = false; |
||
464 | // z->com = (ush) zcom.length(); |
||
465 | } |
||
466 | |||
467 | if (z->options.nameutf8) |
||
468 | UFlag = FLAG_UTF8_BIT; |
||
469 | |||
470 | z->com = (ush) zcom.length(); |
||
471 | |||
472 | if (Verbose < 0) |
||
473 | Notify(ITRACE, _T("central [%d] %s"), xargs, z->iname); |
||
474 | |||
475 | zch.HeaderSig = CENSIG; |
||
476 | zch.MadeBy = z->vem; |
||
477 | zch.VersionNeed = (ush)(xargs ? 45 : z->ver); |
||
478 | zch.Flag = (WORD)(z->flg | UFlag | ((z->options.level > 8) ? 2 : 0)); |
||
479 | zch.ComprMethod = z->how; |
||
480 | zch.ModifStamp = z->tim; |
||
481 | zch.CRC32 = z->crc; |
||
482 | zch.FileNameLen = (ush)z->nam; |
||
483 | zch.ExtraLen = 0; // will update |
||
484 | // zch.FileComLen = (ush)zcom.Length(); |
||
485 | zch.FileComLen = (ush)z->com; |
||
486 | zch.DiskStart = z->dsk; |
||
487 | zch.IntFileAtt = z->att; |
||
488 | zch.ExtFileAtt = z->atx; |
||
489 | |||
490 | HWrite(&zch, sizeof(ZipCentralHeader)); |
||
491 | HWrite(z->hname, zch.FileNameLen); |
||
492 | npos = fhwcnt; |
||
493 | |||
494 | // write Zip64 extra data |
||
495 | if (xargs) |
||
496 | { |
||
497 | HWrite(&tag, 2); |
||
498 | HWrite(&siz, 2); |
||
499 | HWrite(dat, siz); |
||
500 | ox -= ZIP64_XDATA_TAG; |
||
501 | } |
||
502 | |||
503 | if (z->ntfs) |
||
504 | { |
||
505 | XNTFS xn; |
||
506 | xn.Tag = NTFS_STAMP_TAG; |
||
507 | xn.Siz = 32; |
||
508 | xn.res = 0; |
||
509 | xn.tg1 = 1; |
||
510 | xn.sz1 = 24; |
||
511 | HWrite(&xn, sizeof(xn)); |
||
512 | HWrite(z->ntfs, 24); |
||
513 | ox = ox - NTFS_STAMP_TAG; |
||
514 | } |
||
515 | |||
516 | // save utf8 name if needed |
||
517 | if (z->options.enc == zeoUPATH && z->options.nameextd) |
||
518 | { |
||
519 | DZStrA unam = StrToUTF8(StrIntSep(z->IName)); |
||
520 | unsigned ncrc = crc32(0, (uch*)z->hname, z->nam); |
||
521 | tag = UPATH_XDATA_TAG; // Info-Zip Unicode Path |
||
522 | int sz = 5 + unam.length(); |
||
523 | HWrite(&tag, 2); |
||
524 | HWrite(&sz, 2); |
||
525 | sz = 1; // version |
||
526 | HWrite(&sz, 1); |
||
527 | HWrite(&ncrc, 4); |
||
528 | HWrite(unam.c_str(), unam.length()); |
||
529 | ox -= UPATH_XDATA_TAG; |
||
530 | } |
||
531 | |||
532 | // UTF8 comment too |
||
533 | if (ExtCom && z->options.enc == zeoUPATH && z->options.cmntextd) |
||
534 | { |
||
535 | unsigned ncrc = crc32(0, (uch*)zcom.c_str(), zcom.length()); |
||
536 | DZStrA ucom = StrToUTF8(z->Comment); |
||
537 | tag = UCMNT_XDATA_TAG; // Info-Zip Unicode Comment |
||
538 | int sz = 5 + ucom.length(); |
||
539 | HWrite(&tag, 2); |
||
540 | HWrite(&sz, 2); |
||
541 | sz = 1; // version |
||
542 | HWrite(&sz, 1); |
||
543 | HWrite(&ncrc, 4); |
||
544 | HWrite(ucom, ucom.length()); |
||
545 | ox -= UCMNT_XDATA_TAG; |
||
546 | } |
||
547 | |||
548 | // write remaining 'old' extra data |
||
549 | if (!ox.IsEmpty()) |
||
550 | HWrite(ox, ox.Length()); |
||
551 | |||
552 | ((ZipCentralHeader *)fhwbuf)->ExtraLen = (ush)(fhwcnt - npos); |
||
553 | |||
554 | if (zch.FileComLen) |
||
555 | HWrite(zcom.c_str(), zch.FileComLen); |
||
556 | |||
557 | if (fhwcnt <= 0 |
||
558 | || !fZipOutfile->Write(fhwbuf, fhwcnt, &k) |
||
559 | || k != (unsigned)fhwcnt) |
||
560 | return DZ_ERM_TEMP_FAILED; |
||
561 | |||
562 | fBytesWritten += k; |
||
563 | fOutPosn += k; |
||
564 | |||
565 | #ifdef ZDEBUG |
||
566 | if (Verbose < 0) |
||
567 | { |
||
568 | const ZipCentralHeader *zc = (ZipCentralHeader *)fhwbuf; |
||
569 | Notify(ITRACE, _T("central %s-"), z->iname); |
||
570 | Notify(ITRACE, _T(" made %x [%x] need %x [%x]"), |
||
571 | zc->MadeBy, z->vem, zc->VersionNeed, z->ver); |
||
572 | } |
||
573 | #endif |
||
574 | return DZ_ERR_GOOD; |
||
575 | } |
||
576 | |||
577 | // Write the end of central directory data to file *f. Return DZ_ERR_GOOD or |
||
578 | // ZEN_TEMP09. |
||
579 | // n :: Number of entries in central directory. |
||
580 | // s :: Size of central directory. |
||
581 | // c :: Offset of central directory. |
||
582 | // f :: File to write to. |
||
583 | int __fastcall ZipFunc::PutEnd(unsigned CentralCnt, __int64 CentralOffs) //, HANDLE f) |
||
584 | { |
||
585 | ZipEndOfCentral eoc; |
||
586 | unsigned long k; |
||
587 | __int64 cz = fOutPosn - CentralOffs; |
||
588 | // Assert(fOutPosn == SetFilePointer64(fhOutz, 0, 2), _T("invalid out posn")); |
||
589 | HWriteInit(); // reset |
||
590 | #ifndef _FORCE_Z64_ |
||
591 | |||
592 | if (CentralCnt >= MAXWORD || cz >= MAX_UNSIGNED || CentralOffs >= MAX_UNSIGNED) |
||
593 | #endif |
||
594 | { |
||
595 | // make EOC64 |
||
596 | ZipEOC64 e64; |
||
597 | Zip64EOCLocator loc; |
||
598 | e64.HeaderSig = EndCentral64Sig; |
||
599 | e64.vsize = sizeof(ZipEOC64) - 12; // data size |
||
600 | e64.VersionMade = 45; |
||
601 | e64.VersionNeed = 45; |
||
602 | e64.ThisDiskNo = 0; |
||
603 | e64.CentralDiskNo = 0; |
||
604 | e64.CentralEntries = CentralCnt; |
||
605 | e64.TotalEntries = CentralCnt; |
||
606 | e64.CentralSize = cz; |
||
607 | e64.CentralOffSet = CentralOffs; |
||
608 | HWrite(&e64, sizeof(ZipEOC64)); |
||
609 | // make EOC64Locator |
||
610 | loc.HeaderSig = EOC64LocatorSig; |
||
611 | loc.EOC64DiskStt = 0; |
||
612 | loc.EOC64RelOfs = fOutPosn; |
||
613 | loc.NumberDisks = 1; |
||
614 | HWrite(&loc, sizeof(Zip64EOCLocator)); |
||
615 | } |
||
616 | eoc.HeaderSig = ENDSIG; |
||
617 | eoc.CentralDiskNo = eoc.ThisDiskNo = 0; |
||
618 | |||
619 | if (CentralCnt < MAXWORD) |
||
620 | { |
||
621 | eoc.CentralEntries = (ush)CentralCnt; |
||
622 | eoc.TotalEntries = (ush)CentralCnt; |
||
623 | } |
||
624 | else |
||
625 | { |
||
626 | eoc.CentralEntries = (ush) - 1; |
||
627 | eoc.TotalEntries = (ush) - 1; |
||
628 | } |
||
629 | |||
630 | if (cz < MAX_UNSIGNED) |
||
631 | eoc.CentralSize = (unsigned)cz; |
||
632 | else |
||
633 | eoc.CentralSize = (unsigned) - 1; |
||
634 | |||
635 | if (CentralOffs < MAX_UNSIGNED) |
||
636 | eoc.CentralOffset = (unsigned)CentralOffs; |
||
637 | else |
||
638 | eoc.CentralOffset = (unsigned) - 1; |
||
639 | |||
640 | #ifdef _FORCE_Z64_ |
||
641 | eoc.CentralOffset = (unsigned) - 1; |
||
642 | #endif |
||
643 | eoc.ZipCommentLen = (ush)fzcomlen; |
||
644 | |||
645 | HWrite(&eoc, sizeof(ZipEndOfCentral)); |
||
646 | |||
647 | if (eoc.ZipCommentLen) |
||
648 | HWrite(fzcomment, fzcomlen); |
||
649 | |||
650 | if (fhwcnt <= 0 |
||
651 | || !fZipOutfile->Write(fhwbuf, fhwcnt, &k) |
||
652 | || k != (unsigned)fhwcnt) |
||
653 | return DZ_ERM_TEMP_FAILED; |
||
654 | |||
655 | fBytesWritten += k; |
||
656 | fOutPosn += k; |
||
657 | |||
658 | return DZ_ERR_GOOD; |
||
659 | } |
||
660 | |||
661 | // Note: a zip "entry" includes a local header (which includes the file |
||
662 | // name), an encryption header if encrypting, the compressed data and |
||
663 | // possibly an extended local header. |
||
664 | // Copy the zip entry described by *z from file *x to file *y. Return an |
||
665 | // error code in the ZEN_ class. Also update tempzn by the number of bytes |
||
666 | // copied. z :: Zip entry to copy. x, *y :: Source and destination files. |
||
667 | int __fastcall ZipFunc::zipcopy(ZipItem *z) |
||
668 | { |
||
669 | ZInt64 n; // holds local header offset |
||
670 | // Trace(("zipcopy %s\n", z->zname)); |
||
671 | n = (ulg)(4 + LOCHEAD) + (ulg)z->nam + (ulg)z->ext; |
||
672 | // seek to local header |
||
673 | if (SetFilePointer64(fhInz, z->off, FILE_BEGIN) == -1) |
||
674 | return DZ_ERM_ERROR_SEEK; |
||
675 | |||
676 | z->off = fOutPosn; |
||
677 | |||
678 | n += z->siz; |
||
679 | |||
680 | // copy the compressed data and the extended local header if there is one |
||
681 | if (z->lflg & FLAG_EXTEND_BIT) |
||
682 | n += (z->ver >= 45 ? 20 : 16); |
||
683 | |||
684 | fOutPosn += n; |
||
685 | CB->UserItem(n, z->IName); |
||
686 | |||
687 | // return fcopy(n); |
||
688 | int err = fcopy(n); |
||
689 | /* TODO 1 -oRP -cenhancement : Finished Item */ |
||
690 | return err; |
||
691 | } |
||
692 | |||
693 | //------------------------------------------------------------------------- |
||
694 | |||
695 | |||
696 | int ZipFunc::TrashDir(const DZStrW &dir) |
||
697 | { |
||
698 | DZStrW tmp = StrExcSep(dir); |
||
699 | |||
700 | if (tmp.IsEmpty()) |
||
701 | return -1; |
||
702 | |||
703 | if (Verbose) |
||
704 | Notify(IVERBOSE, _T("trashing directory %s (if empty)"), tmp.c_str()); |
||
705 | |||
706 | int err = EraseFile(tmp, fHowToMove); |
||
707 | if (err && Verbose < 0) |
||
708 | Notify(IWARNING, _T("error deleting %s {%x}"), tmp.c_str(), err); |
||
709 | |||
710 | return 0; |
||
711 | } |
||
712 | |||
713 | |||
714 | // Used by qsort() to compare entries in the zfile list. Compare the |
||
715 | // strings in reverse order. a, *b :: char * |
||
716 | static int rcmp(const void *a, const void *b) |
||
717 | { |
||
718 | return _tcscmp(*(const TCHAR**)b, *(const TCHAR**)a); |
||
719 | } |
||
720 | |||
721 | // Delete the compressed files and the directories that contained the |
||
722 | // deleted files, if empty. Return an error code in the ZEN_ class. Failure |
||
723 | // of destroy() or rmdir() is ignored. |
||
724 | int ZipFunc::trash(void) |
||
725 | { |
||
726 | int i; // counter on deleted names |
||
727 | int n; // number of directories to delete |
||
728 | ZipItem *z, *prv = NULL; // current zip entry |
||
729 | // Delete marked names and count directories |
||
730 | n = 0; |
||
731 | |||
732 | for (z = fzfiles; z != NULL; z = z->nxt) |
||
733 | { |
||
734 | if (z->mark == 1 || z->trash) |
||
735 | { |
||
736 | z->mark = 1; |
||
737 | DZStrW f = z->FullPath(); |
||
738 | if (!z->IsFolder) |
||
739 | { |
||
740 | // don't unlink directory SLASH |
||
741 | if (Verbose) |
||
742 | Notify(IVERBOSE, _T("deleting file %s"), f.c_str()); |
||
743 | |||
744 | int err = EraseFile(f, fHowToMove); |
||
745 | if (err && Verbose < 0) |
||
746 | Notify(IWARNING, _T("error deleting %s {%x}"), f.c_str(), err); |
||
747 | |||
748 | // Try to delete all paths that lead up to marked names. This is |
||
749 | // necessary only with the -D option. |
||
750 | if (!fdirnames) |
||
751 | { |
||
752 | diag(_T("no dirnames will be kept")); |
||
753 | DZStrW pth = z->xname; |
||
754 | int ls = pth.ReverseFind(_T('\\')); |
||
755 | if (ls > 0) |
||
756 | { |
||
757 | pth = pth.Left(ls); // only leave prev folders |
||
758 | // remove a lot of duplicates |
||
759 | if (prv && ZMatch(prv->xname, pth)) |
||
760 | z->mark = 0; // ignore same path |
||
761 | else |
||
762 | z->xname = pth.c_str(); |
||
763 | } |
||
764 | else |
||
765 | { |
||
766 | z->mark = 0; // done with it |
||
767 | z->xname = NULL; // free up |
||
768 | } |
||
769 | } |
||
770 | } |
||
771 | } |
||
772 | |||
773 | // is it directory we want to remove? |
||
774 | if (z->mark) |
||
775 | { |
||
776 | n++; |
||
777 | prv = z; |
||
778 | } |
||
779 | } |
||
780 | |||
781 | if (n == 1 && prv) |
||
782 | { |
||
783 | TrashDir(prv->FullPath()); |
||
784 | n = 0; |
||
785 | } |
||
786 | |||
787 | if (n) |
||
788 | { |
||
789 | // Construct the list of all marked directories. Some may be duplicated if |
||
790 | // -D was used. |
||
791 | TCHAR **dlist; // for sorting |
||
792 | typedef TCHAR* PTChar; |
||
793 | dlist = new PTChar[n]; |
||
794 | |||
795 | int dcnt = 0; |
||
796 | for (z = fzfiles; z != NULL; z = z->nxt) |
||
797 | { |
||
798 | if (z->mark && dcnt < n) |
||
799 | { |
||
800 | if (_tcslen(z->xname) < 1) |
||
801 | continue; |
||
802 | |||
803 | DZStrW fullpth = z->FullPath(); |
||
804 | const TCHAR *fp = fullpth.c_str(); |
||
805 | int dlen = _tcslen(fp); |
||
806 | TCHAR *dn = new TCHAR[dlen + 1]; |
||
807 | |||
808 | if (!dn) |
||
809 | break; // keep safe |
||
810 | |||
811 | TCHAR *d = dn; |
||
812 | |||
813 | for (int i = 0; i < dlen; i++) |
||
814 | *d++ = (TCHAR)_totupper(*fp++); |
||
815 | |||
816 | *d = 0; |
||
817 | if (dcnt == 0 || !ZMatch(dn, dlist[dcnt - 1])) |
||
818 | dlist[dcnt++] = dn; |
||
819 | else |
||
820 | delete dn; |
||
821 | } |
||
822 | } |
||
823 | |||
824 | // Sort the files in reverse order to get subdirectories first, |
||
825 | // so x/y/z will always be removed before x/y. |
||
826 | qsort((TCHAR*)dlist, dcnt, sizeof(TCHAR*), rcmp); |
||
827 | |||
828 | for (i = 0; i < dcnt; i++) |
||
829 | { |
||
830 | TCHAR *p = dlist[i]; |
||
831 | |||
832 | if (*p == '\0') |
||
833 | continue; |
||
834 | |||
835 | if (i == 0 || !ZMatch(p, dlist[i - 1])) |
||
836 | TrashDir(p); |
||
837 | } |
||
838 | |||
839 | // clean up |
||
840 | for (int i = 0; i < dcnt; i++) |
||
841 | delete[] dlist[i]; |
||
842 | delete[] dlist; |
||
843 | } |
||
844 | |||
845 | return DZ_ERR_GOOD; |
||
846 | } |
||
847 | |||
848 | |||
849 | |||
850 |