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 "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() */