Example #1
0
File: CabIn.cpp Project: bks/qz7
void CMvDatabaseEx::FillSortAndShrink()
{
  Items.Clear();
  StartFolderOfVol.Clear();
  FolderStartFileIndex.Clear();
  int offset = 0;
  for (int v = 0; v < Volumes.Size(); v++)
  {
    const CDatabaseEx &db = Volumes[v];
    int curOffset = offset;
    if (db.IsTherePrevFolder())
      curOffset--;
    StartFolderOfVol.Add(curOffset);
    offset += db.GetNumberOfNewFolders();

    CMvItem mvItem;
    mvItem.VolumeIndex = v;
    for (int i = 0 ; i < db.Items.Size(); i++)
    {
      mvItem.ItemIndex = i;
      Items.Add(mvItem);
    }
  }

  Items.Sort(CompareMvItems, (void *)this);
  int j = 1;
  int i;
  for (i = 1; i < Items.Size(); i++)
    if (!AreItemsEqual(i, i -1))
      Items[j++] = Items[i];
  Items.DeleteFrom(j);

  for (i = 0; i < Items.Size(); i++)
  {
    const CMvItem &mvItem = Items[i];
    int folderIndex = GetFolderIndex(&mvItem);
    if (folderIndex >= FolderStartFileIndex.Size())
      FolderStartFileIndex.Add(i);
  }
}
Example #2
0
HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item)
{
  if (item.FromLocal)
    return S_OK;
  try
  {
    UInt64 offset = ArcInfo.Base + item.LocalHeaderPos;
    if (ArcInfo.Base < 0 && (Int64)offset < 0)
      return S_FALSE;
    RINOK(Seek(offset));
    CItemEx localItem;
    if (ReadUInt32() != NSignature::kLocalFileHeader)
      return S_FALSE;
    ReadLocalItem(localItem);
    if (!AreItemsEqual(localItem, item))
      return S_FALSE;
    item.LocalFullHeaderSize = localItem.LocalFullHeaderSize;
    item.LocalExtra = localItem.LocalExtra;
    item.FromLocal = true;
  }
  catch(...) { return S_FALSE; }
  return S_OK;
}
Example #3
0
HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items, CProgressVirt *progress)
{
  items.Clear();

  // m_Signature must be kLocalFileHeader or kEcd
  // m_Position points to next byte after signature
  RINOK(Stream->Seek(m_Position, STREAM_SEEK_SET, NULL));

  if (!_inBuffer.Create(1 << 15))
    return E_OUTOFMEMORY;
  _inBuffer.SetStream(Stream);

  bool needReadCd = true;
  bool localsWereRead = false;
  if (m_Signature == NSignature::kEcd)
  {
    // It must be empty archive or backware archive
    // we don't support backware archive still

    const unsigned kBufSize = kEcdSize - 4;
    Byte buf[kBufSize];
    SafeReadBytes(buf, kBufSize);
    CEcd ecd;
    ecd.Parse(buf);
    // if (ecd.cdSize != 0)
    // Do we need also to support the case where empty zip archive with PK00 uses cdOffset = 4 ??
    if (!ecd.IsEmptyArc())
      return S_FALSE;

    ArcInfo.Base = ArcInfo.MarkerPos;
    needReadCd = false;
    IsArc = true; // check it: we need more tests?
    RINOK(Stream->Seek(ArcInfo.MarkerPos2 + 4, STREAM_SEEK_SET, &m_Position));
  }

  UInt64 cdSize = 0, cdRelatOffset = 0, cdAbsOffset = 0;
  HRESULT res = S_OK;

  if (needReadCd)
  {
    CItemEx firstItem;
    // try
    {
      try
      {
        if (!ReadLocalItem(firstItem))
          return S_FALSE;
      }
      catch(CUnexpectEnd &)
      {
        return S_FALSE;
      }

      IsArc = true;
      res = ReadCd(items, cdRelatOffset, cdSize, progress);
      if (res == S_OK)
        m_Signature = ReadUInt32();
    }
    // catch() { res = S_FALSE; }
    if (res != S_FALSE && res != S_OK)
      return res;

    if (res == S_OK && items.Size() == 0)
      res = S_FALSE;

    if (res == S_OK)
    {
      // we can't read local items here to keep _inBufMode state
      firstItem.LocalHeaderPos = ArcInfo.MarkerPos2 - ArcInfo.Base;
      int index = FindItem(items, firstItem.LocalHeaderPos);
      if (index == -1)
        res = S_FALSE;
      else if (!AreItemsEqual(firstItem, items[index]))
        res = S_FALSE;
      ArcInfo.CdWasRead = true;
      ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos;
    }
  }

  CObjectVector<CItemEx> cdItems;

  bool needSetBase = false;
  unsigned numCdItems = items.Size();

  if (res == S_FALSE)
  {
    // CD doesn't match firstItem so we clear items and read Locals.
    items.Clear();
    localsWereRead = true;
    _inBufMode = false;
    ArcInfo.Base = ArcInfo.MarkerPos;
    RINOK(Stream->Seek(ArcInfo.MarkerPos2, STREAM_SEEK_SET, &m_Position));
    m_Signature = ReadUInt32();

    RINOK(ReadLocals(items, progress));

    if (m_Signature != NSignature::kCentralFileHeader)
    {
      m_Position -= 4;
      NoCentralDir = true;
      HeadersError = true;
      return S_OK;
    }
    _inBufMode = true;
    _inBuffer.Init();
    cdAbsOffset = m_Position - 4;
    for (;;)
    {
      CItemEx cdItem;
      RINOK(ReadCdItem(cdItem));
      cdItems.Add(cdItem);
      if (progress && cdItems.Size() % 1 == 0)
        RINOK(progress->SetCompletedCD(items.Size()));
      m_Signature = ReadUInt32();
      if (m_Signature != NSignature::kCentralFileHeader)
        break;
    }

    cdSize = (m_Position - 4) - cdAbsOffset;
    needSetBase = true;
    numCdItems = cdItems.Size();

    if (!cdItems.IsEmpty())
    {
      ArcInfo.CdWasRead = true;
      ArcInfo.FirstItemRelatOffset = cdItems[0].LocalHeaderPos;
    }
  }

  CEcd64 ecd64;
  bool isZip64 = false;
  UInt64 ecd64AbsOffset = m_Position - 4;
  if (m_Signature == NSignature::kEcd64)
  {
    IsZip64 = isZip64 = true;
    UInt64 recordSize = ReadUInt64();

    const unsigned kBufSize = kEcd64_MainSize;
    Byte buf[kBufSize];
    SafeReadBytes(buf, kBufSize);
    ecd64.Parse(buf);

    Skip64(recordSize - kEcd64_MainSize);
    m_Signature = ReadUInt32();

    if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0)
      return E_NOTIMPL;

    if (needSetBase)
    {
      ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset;
      cdRelatOffset = ecd64.cdStartOffset;
      needSetBase = false;
    }

    if (ecd64.numEntriesInCDOnThisDisk != numCdItems ||
        ecd64.numEntriesInCD != numCdItems ||
        ecd64.cdSize != cdSize ||
        (ecd64.cdStartOffset != cdRelatOffset &&
        (!items.IsEmpty())))
      return S_FALSE;
  }
  if (m_Signature == NSignature::kEcd64Locator)
  {
    if (!isZip64)
      return S_FALSE;
    /* UInt32 startEndCDDiskNumber = */ ReadUInt32();
    UInt64 ecd64RelatOffset = ReadUInt64();
    /* UInt32 numberOfDisks = */ ReadUInt32();
    if (ecd64AbsOffset != ArcInfo.Base + ecd64RelatOffset)
      return S_FALSE;
    m_Signature = ReadUInt32();
  }
  if (m_Signature != NSignature::kEcd)
    return S_FALSE;

  const unsigned kBufSize = kEcdSize - 4;
  Byte buf[kBufSize];
  SafeReadBytes(buf, kBufSize);
  CEcd ecd;
  ecd.Parse(buf);

  COPY_ECD_ITEM_16(thisDiskNumber);
  COPY_ECD_ITEM_16(startCDDiskNumber);
  COPY_ECD_ITEM_16(numEntriesInCDOnThisDisk);
  COPY_ECD_ITEM_16(numEntriesInCD);
  COPY_ECD_ITEM_32(cdSize);
  COPY_ECD_ITEM_32(cdStartOffset);

  if (needSetBase)
  {
    ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset;
    cdRelatOffset = ecd64.cdStartOffset;
    needSetBase = false;
  }

  if (localsWereRead && (UInt64)ArcInfo.Base != ArcInfo.MarkerPos)
  {
    UInt64 delta = ArcInfo.MarkerPos - ArcInfo.Base;
    for (unsigned i = 0; i < items.Size(); i++)
      items[i].LocalHeaderPos += delta;
  }


  // ---------- merge Central Directory Items ----------

  if (!cdItems.IsEmpty())
  {
    for (unsigned i = 0; i < cdItems.Size(); i++)
    {
      const CItemEx &cdItem = cdItems[i];
      int index = FindItem(items, cdItem.LocalHeaderPos);
      if (index == -1)
      {
        items.Add(cdItem);
        continue;
      }
      CItemEx &item = items[index];
      if (item.Name != cdItem.Name
          // || item.Name.Len() != cdItem.Name.Len()
          || item.PackSize != cdItem.PackSize
          || item.Size != cdItem.Size
          // item.ExtractVersion != cdItem.ExtractVersion
          || !FlagsAreSame(item, cdItem)
          || item.Crc != cdItem.Crc)
        continue;

      // item.LocalHeaderPos = cdItem.LocalHeaderPos;
      // item.Name = cdItem.Name;
      item.MadeByVersion = cdItem.MadeByVersion;
      item.CentralExtra = cdItem.CentralExtra;
      item.InternalAttrib = cdItem.InternalAttrib;
      item.ExternalAttrib = cdItem.ExternalAttrib;
      item.Comment = cdItem.Comment;
      item.FromCentral = cdItem.FromCentral;
    }
  }

  if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0)
    return E_NOTIMPL;

  if (isZip64)
  {
    if (ecd64.numEntriesInCDOnThisDisk != items.Size())
      HeadersError = true;
  }
  else
  {
    // old 7-zip could store 32-bit number of CD items to 16-bit field.
    if ((UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)numCdItems ||
        (UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)items.Size())
      HeadersError = true;
  }

  ReadBuffer(ArcInfo.Comment, ecd.commentSize);
  _inBufMode = false;
  _inBuffer.Free();

  if (
      (UInt16)ecd64.numEntriesInCD != ((UInt16)numCdItems) ||
      (UInt32)ecd64.cdSize != (UInt32)cdSize ||
      ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdRelatOffset &&
        (!items.IsEmpty())))
    return S_FALSE;

  // printf("\nOpen OK");
  return S_OK;
}