Subversion Repositories autosfx

Rev

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