Subversion Repositories autosfx

Rev

Blame | Last modification | View Log | RSS feed

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