Пример #1
0
HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo)
{
  if (offset >= ((UInt64)1 << 63))
    return S_FALSE;
  RINOK(Seek(offset));
  Byte buf[kEcd64_FullSize];

  RINOK(ReadStream_FALSE(Stream, buf, kEcd64_FullSize));

  if (Get32(buf) != NSignature::kEcd64)
    return S_FALSE;
  UInt64 mainSize = Get64(buf + 4);
  if (mainSize < kEcd64_MainSize || mainSize > ((UInt64)1 << 32))
    return S_FALSE;
  cdInfo.ParseEcd64(buf);
  return S_OK;
}
Пример #2
0
HRESULT CInArchive::FindCd(CCdInfo &cdInfo)
{
  UInt64 endPosition;
  RINOK(Stream->Seek(0, STREAM_SEEK_END, &endPosition));

  const UInt32 kBufSizeMax = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize;
  UInt32 bufSize = (endPosition < kBufSizeMax) ? (UInt32)endPosition : kBufSizeMax;
  if (bufSize < kEcdSize)
    return S_FALSE;
  CByteArr byteBuffer(bufSize);

  UInt64 startPosition = endPosition - bufSize;
  RINOK(Stream->Seek(startPosition, STREAM_SEEK_SET, &m_Position));
  if (m_Position != startPosition)
    return S_FALSE;

  RINOK(ReadStream_FALSE(Stream, byteBuffer, bufSize));

  const Byte *buf = byteBuffer;
  for (UInt32 i = bufSize - kEcdSize;; i--)
  {
    if (buf[i] != 0x50)
    {
      if (i == 0) return S_FALSE;
      i--;
      if (buf[i] != 0x50)
      {
        if (i == 0) return S_FALSE;
        continue;
      }
    }
    if (Get32(buf + i) == NSignature::kEcd)
    {
      if (i >= kEcd64_FullSize + kEcd64Locator_Size)
      {
        const Byte *locator = buf + i - kEcd64Locator_Size;
        if (Get32(locator) == NSignature::kEcd64Locator &&
            Get32(locator + 4) == 0) // number of the disk with the start of the zip64 ECD
        {
          // Most of the zip64 use fixed size Zip64 ECD

          UInt64 ecd64Offset = Get64(locator + 8);
          UInt64 absEcd64 = endPosition - bufSize + i - (kEcd64Locator_Size + kEcd64_FullSize);
          {
            const Byte *ecd64 = locator - kEcd64_FullSize;
            if (Get32(ecd64) == NSignature::kEcd64 &&
                Get64(ecd64 + 4) == kEcd64_MainSize)
            {
              cdInfo.ParseEcd64(ecd64);
              ArcInfo.Base = absEcd64 - ecd64Offset;
              return S_OK;
            }
          }

          // some zip64 use variable size Zip64 ECD.
          // we try to find it
          if (absEcd64 != ecd64Offset)
          {
            if (TryEcd64(ecd64Offset, cdInfo) == S_OK)
            {
              ArcInfo.Base = 0;
              return S_OK;
            }
          }
          if (ArcInfo.MarkerPos != 0 &&
              ArcInfo.MarkerPos + ecd64Offset != absEcd64)
          {
            if (TryEcd64(ArcInfo.MarkerPos + ecd64Offset, cdInfo) == S_OK)
            {
              ArcInfo.Base = ArcInfo.MarkerPos;
              return S_OK;
            }
          }
        }
      }
      if (Get32(buf + i + 4) == 0) // ThisDiskNumber, StartCentralDirectoryDiskNumber;
      {
        cdInfo.ParseEcd(buf + i);
        UInt64 absEcdPos = endPosition - bufSize + i;
        UInt64 cdEnd = cdInfo.Size + cdInfo.Offset;
        ArcInfo.Base = 0;
        if (absEcdPos != cdEnd)
        {
          /*
          if (cdInfo.Offset <= 16 && cdInfo.Size != 0)
          {
            // here we support some rare ZIP files with Central directory at the start
            ArcInfo.Base = 0;
          }
          else
          */
          ArcInfo.Base = absEcdPos - cdEnd;
        }
        return S_OK;
      }
    }
    if (i == 0)
      return S_FALSE;
  }
}