Subversion Repositories autosfx

Rev

Blame | Last modification | View Log | RSS feed

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