Beispiel #1
0
HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize)
{
  Byte temp[4];
  RINOK(ReadStream_FALSE(inStream, temp, 2));
  _ivSize = GetUi16(temp);
  if (_ivSize == 0)
  {
    memset(_iv, 0, 16);
    SetUi32(_iv + 0, crc);
    SetUi64(_iv + 4, unpackSize);
    _ivSize = 12;
  }
  else if (_ivSize == 16)
  {
    RINOK(ReadStream_FALSE(inStream, _iv, _ivSize));
  }
  else
    return E_NOTIMPL;
  RINOK(ReadStream_FALSE(inStream, temp, 4));
  _remSize = GetUi32(temp);
  // const UInt32 kAlign = 16;
  if (_remSize < 16 || _remSize > (1 << 18))
    return E_NOTIMPL;
  if (_remSize > _bufAligned.Size())
  {
    _bufAligned.AllocAtLeast(_remSize);
    if (!(Byte *)_bufAligned)
      return E_OUTOFMEMORY;
  }
  return ReadStream_FALSE(inStream, _bufAligned, _remSize);
}
HRESULT CCabBlockInStream::PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize)
{
  const UInt32 kHeaderSize = 8;
  const UInt32 kReservedMax = 256;
  Byte header[kHeaderSize + kReservedMax];
  RINOK(ReadStream_FALSE(stream, header, kHeaderSize + ReservedSize))
  packSize = GetUi16(header + 4);
  unpackSize = GetUi16(header + 6);
  if (packSize > kBlockSize - _size)
    return S_FALSE;
  RINOK(ReadStream_FALSE(stream, _buf + _size, packSize));
  
  if (MsZip)
  {
    if (_size == 0)
    {
      if (packSize < 2 || _buf[0] != 0x43 || _buf[1] != 0x4B)
        return S_FALSE;
      _pos = 2;
    }
    if (_size + packSize > ((UInt32)1 << 15) + 12) /* v9.31 fix. MSZIP specification */
      return S_FALSE;
  }

  if (GetUi32(header) != 0) // checkSum
    if (CheckSum(header, kHeaderSize + ReservedSize) != CheckSum(_buf + _size, packSize))
      return S_FALSE;

  _size += packSize;
  return S_OK;
}
Beispiel #3
0
HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize)
{
  Byte temp[4];
  RINOK(ReadStream_FALSE(inStream, temp, 2));
  _ivSize = GetUi16(temp);
  if (_ivSize == 0)
  {
    memset(_iv, 0, 16);
    SetUi32(_iv + 0, crc);
    SetUi64(_iv + 4, unpackSize);
    _ivSize = 12;
  }
  else if (_ivSize == 16)
  {
    RINOK(ReadStream_FALSE(inStream, _iv, _ivSize));
  }
  else
    return E_NOTIMPL;
  RINOK(ReadStream_FALSE(inStream, temp, 4));
  _remSize = GetUi32(temp);
  const UInt32 kAlign = 16;
  if (_remSize < 16 || _remSize > (1 << 18))
    return E_NOTIMPL;
  if (_remSize + kAlign > _buf.Size())
  {
    _buf.Alloc(_remSize + kAlign);
    _bufAligned = (Byte *)((ptrdiff_t)((Byte *)_buf + kAlign - 1) & ~(ptrdiff_t)(kAlign - 1));
  }
  return ReadStream_FALSE(inStream, _bufAligned, _remSize);
}
Beispiel #4
0
HRESULT CCabBlockInStream::PreRead(UInt32 &packSize, UInt32 &unpackSize)
{
  CTempCabInBuffer2 inBuffer;
  inBuffer.Pos = 0;
  RINOK(ReadStream_FALSE(_stream, inBuffer.Buffer, kDataBlockHeaderSize))

  UInt32 checkSum = inBuffer.ReadUInt32();
  packSize = inBuffer.ReadUInt16();
  unpackSize = inBuffer.ReadUInt16();
  if (ReservedSize != 0)
  {
    RINOK(ReadStream_FALSE(_stream, _buffer, ReservedSize));
  }
  _pos = 0;
  CCheckSum2 checkSumCalc;
  checkSumCalc.Init();
  UInt32 packSize2 = packSize;
  if (MsZip && _size == 0)
  {
    if (packSize < 2)
      return S_FALSE; // bad block;
    Byte sig[2];
    RINOK(ReadStream_FALSE(_stream, sig, 2));
    if (sig[0] != 0x43 || sig[1] != 0x4B)
      return S_FALSE;
    packSize2 -= 2;
    checkSumCalc.Update(sig, 2);
  }

  if (kBlockSize - _size < packSize2)
    return S_FALSE;

  UInt32 curSize = packSize2;
  if (curSize != 0)
  {
    size_t processedSizeLoc = curSize;
    RINOK(ReadStream(_stream, _buffer + _size, &processedSizeLoc));
    checkSumCalc.Update(_buffer + _size, (UInt32)processedSizeLoc);
    _size += (UInt32)processedSizeLoc;
    if (processedSizeLoc != curSize)
      return S_FALSE;
  }
  TotalPackSize = _size;

  checkSumCalc.FinishDataUpdate();
  
  bool dataError;
  if (checkSum == 0)
    dataError = false;
  else
  {
    checkSumCalc.UpdateUInt32(packSize | (((UInt32)unpackSize) << 16));
    dataError = (checkSumCalc.GetResult() != checkSum);
  }
  DataError |= dataError;
  return dataError ? S_FALSE : S_OK;
}
Beispiel #5
0
HRESULT CHandler::Open2(IInStream *stream)
{
  UInt64 archiveStartPos;
  RINOK(stream->Seek(0, STREAM_SEEK_SET, &archiveStartPos));

  const UInt32 kHeaderSize = 0x1C;
  Byte buf[kHeaderSize];
  RINOK(ReadStream_FALSE(stream, buf, kHeaderSize));

  UInt32 size = Get16(buf + 4);
  // UInt32 ver = Get16(buf + 6); // == 0
  if (Get32(buf) != 0x78617221 || size != kHeaderSize)
    return S_FALSE;

  UInt64 packSize = Get64(buf + 8);
  UInt64 unpackSize = Get64(buf + 0x10);
  // UInt32 checkSumAlogo = Get32(buf + 0x18);

  if (unpackSize >= kXmlSizeMax)
    return S_FALSE;

  _dataStartPos = archiveStartPos + kHeaderSize + packSize;

  char *ss = _xml.GetBuffer((int)unpackSize + 1);

  NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
  CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;

  CLimitedSequentialInStream *inStreamLimSpec = new CLimitedSequentialInStream;
  CMyComPtr<ISequentialInStream> inStreamLim(inStreamLimSpec);
  inStreamLimSpec->SetStream(stream);
  inStreamLimSpec->Init(packSize);

  CBufPtrSeqOutStream *outStreamLimSpec = new CBufPtrSeqOutStream;
  CMyComPtr<ISequentialOutStream> outStreamLim(outStreamLimSpec);
  outStreamLimSpec->Init((Byte *)ss, (size_t)unpackSize);

  RINOK(zlibCoder->Code(inStreamLim, outStreamLim, NULL, NULL, NULL));

  if (outStreamLimSpec->GetPos() != (size_t)unpackSize)
    return S_FALSE;

  ss[(size_t)unpackSize] = 0;
  _xml.ReleaseBuffer();

  CXml xml;
  if (!xml.Parse(_xml))
    return S_FALSE;

  if (!xml.Root.IsTagged("xar") || xml.Root.SubItems.Size() != 1)
    return S_FALSE;
  const CXmlItem &toc = xml.Root.SubItems[0];
  if (!toc.IsTagged("toc"))
    return S_FALSE;
  if (!AddItem(toc, _files, -1))
    return S_FALSE;
  return S_OK;
}
Beispiel #6
0
HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
{
  m_CryptoMode = false;
  RINOK(stream->Seek(0, STREAM_SEEK_SET, &m_StreamStartPosition));
  m_Position = m_StreamStartPosition;

  UInt64 arcStartPos;
  RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize,
      searchHeaderSizeLimit, arcStartPos));
  m_Position = arcStartPos + NHeader::kMarkerSize;
  RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
  Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1];

  RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize));
  AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize);


  UInt32 blockSize = Get16(buf + 5);

  _header.EncryptVersion = 0;
  _header.Flags = Get16(buf + 3);

  UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize;
  if (_header.IsThereEncryptVer())
  {
    if (blockSize <= headerSize)
      return S_FALSE;
    RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1));
    AddToSeekValue(1);
    _header.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize];
    headerSize += 1;
  }
  if (blockSize < headerSize ||
      buf[2] != NHeader::NBlockType::kArchiveHeader ||
      (UInt32)Get16(buf) != (CrcCalc(buf + 2, headerSize - 2) & 0xFFFF))
    return S_FALSE;

  size_t commentSize = blockSize - headerSize; 
  _comment.SetCapacity(commentSize);
  RINOK(ReadStream_FALSE(stream, _comment, commentSize));
  AddToSeekValue(commentSize);
  m_Stream = stream;
  _header.StartPosition = arcStartPos;
  return S_OK;
}
Beispiel #7
0
HRESULT ReadHeader(IInStream *inStream, CHeader &h)
{
  const UInt32 kHeaderSizeMax = 0xD0;
  Byte p[kHeaderSizeMax];
  RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax));
  if (memcmp(p, kSignature, kSignatureSize) != 0)
    return S_FALSE;
  return h.Parse(p);
}
Beispiel #8
0
HRESULT FindSignatureInStream(ISequentialInStream *stream,
    const Byte *signature, unsigned signatureSize,
    const UInt64 *limit, UInt64 &resPos)
{
  resPos = 0;
  CByteBuffer byteBuffer2(signatureSize);
  RINOK(ReadStream_FALSE(stream, byteBuffer2, signatureSize));

  if (memcmp(byteBuffer2, signature, signatureSize) == 0)
    return S_OK;

  const UInt32 kBufferSize = (1 << 16);
  CByteBuffer byteBuffer(kBufferSize);
  Byte *buffer = byteBuffer;
  UInt32 numPrevBytes = signatureSize - 1;
  memcpy(buffer, (const Byte *)byteBuffer2 + 1, numPrevBytes);
  resPos = 1;
  for (;;)
  {
    if (limit != NULL)
      if (resPos > *limit)
        return S_FALSE;
    do
    {
      UInt32 numReadBytes = kBufferSize - numPrevBytes;
      UInt32 processedSize;
      RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
      numPrevBytes += processedSize;
      if (processedSize == 0)
        return S_FALSE;
    }
    while (numPrevBytes < signatureSize);
    UInt32 numTests = numPrevBytes - signatureSize + 1;
    for (UInt32 pos = 0; pos < numTests; pos++)
    {
      Byte b = signature[0];
      for (; buffer[pos] != b && pos < numTests; pos++);
      if (pos == numTests)
        break;
      if (memcmp(buffer + pos, signature, signatureSize) == 0)
      {
        resPos += pos;
        return S_OK;
      }
    }
    resPos += numTests;
    numPrevBytes -= numTests;
    memmove(buffer, buffer + numTests, numPrevBytes);
  }
}
Beispiel #9
0
HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
{
  RINOK(ReadStream_FALSE(stream, _header, kHeaderSize));

  if (TestSignature2(_header))
    return S_OK;

  CByteBuffer byteBuffer;
  const UInt32 kBufferSize = (1 << 16);
  byteBuffer.SetCapacity(kBufferSize);
  Byte *buffer = byteBuffer;
  UInt32 numPrevBytes = kHeaderSize;
  memcpy(buffer, _header, kHeaderSize);
  UInt64 curTestPos = _arhiveBeginStreamPosition;
  for (;;)
  {
    if (searchHeaderSizeLimit != NULL)
      if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
        break;
    do
    {
      UInt32 numReadBytes = kBufferSize - numPrevBytes;
      UInt32 processedSize;
      RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
      numPrevBytes += processedSize;
      if (processedSize == 0)
        return S_FALSE;
    }
    while (numPrevBytes <= kHeaderSize);
    UInt32 numTests = numPrevBytes - kHeaderSize;
    for (UInt32 pos = 0; pos < numTests; pos++)
    {
      for (; buffer[pos] != '7' && pos < numTests; pos++);
      if (pos == numTests)
        break;
      if (TestSignature(buffer + pos))
      {
        memcpy(_header, buffer + pos, kHeaderSize);
        curTestPos += pos;
        _arhiveBeginStreamPosition = curTestPos;
        return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL);
      }
    }
    curTestPos += numTests;
    numPrevBytes -= numTests;
    memmove(buffer, buffer + numTests, numPrevBytes);
  }
  return S_FALSE;
}
Beispiel #10
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;
}
Beispiel #11
0
HRESULT CDecoder::Init(ISequentialInStream *inStream, bool &useFilter)
{
    useFilter = false;

    if (_decoderInStream)
        if (Method != _curMethod)
            Release();
    _curMethod = Method;
    if (!_codecInStream)
    {
        switch (Method)
        {
        // case NMethodType::kCopy: return E_NOTIMPL;
        case NMethodType::kDeflate:
            _codecInStream = new NCompress::NDeflate::NDecoder::CNsisCOMCoder();
            break;
        case NMethodType::kBZip2:
            _codecInStream = new NCompress::NBZip2::CNsisDecoder();
            break;
        case NMethodType::kLZMA:
            _lzmaDecoder = new NCompress::NLzma::CDecoder();
            _codecInStream = _lzmaDecoder;
            break;
        default:
            return E_NOTIMPL;
        }
    }

    if (FilterFlag)
    {
        Byte flag;
        RINOK(ReadStream_FALSE(inStream, &flag, 1));
        if (flag > 1)
            return E_NOTIMPL;
        useFilter = (flag != 0);
    }

    if (!useFilter)
        _decoderInStream = _codecInStream;
    else
    {
        if (!_filterInStream)
        {
            _filter = new CFilterCoder(false);
            _filterInStream = _filter;
            _filter->Filter = new NCompress::NBcj::CCoder(false);
        }
        RINOK(_filter->SetInStream(_codecInStream));
        _decoderInStream = _filterInStream;
    }

    if (Method == NMethodType::kLZMA)
    {
        const unsigned kPropsSize = LZMA_PROPS_SIZE;
        Byte props[kPropsSize];
        RINOK(ReadStream_FALSE(inStream, props, kPropsSize));
        RINOK(_lzmaDecoder->SetDecoderProperties2((const Byte *)props, kPropsSize));
    }

    {
        CMyComPtr<ICompressSetInStream> setInStream;
        _codecInStream.QueryInterface(IID_ICompressSetInStream, &setInStream);
        if (!setInStream)
            return E_NOTIMPL;
        RINOK(setInStream->SetInStream(inStream));
    }

    {
        CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
        _codecInStream.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize);
        if (!setOutStreamSize)
            return E_NOTIMPL;
        RINOK(setOutStreamSize->SetOutStreamSize(NULL));
    }

    if (useFilter)
    {
        RINOK(_filter->SetOutStreamSize(NULL));
    }

    return S_OK;
}
Beispiel #12
0
HRESULT CDecoder::Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize,
                         ISequentialOutStream *realOutStream, ICompressProgressInfo *progress,
                         UInt32 &packSizeRes, UInt32 &unpackSizeRes)
{
    CLimitedSequentialInStream *limitedStreamSpec = NULL;
    CMyComPtr<ISequentialInStream> limitedStream;
    packSizeRes = 0;
    unpackSizeRes = 0;

    if (Solid)
    {
        Byte temp[4];
        size_t processedSize = 4;
        RINOK(Read(temp, &processedSize));
        if (processedSize != 4)
            return S_FALSE;
        StreamPos += processedSize;
        UInt32 size = Get32(temp);
        if (unpackSizeDefined && size != unpackSize)
            return S_FALSE;
        unpackSize = size;
        unpackSizeDefined = true;
    }
    else
    {
        Byte temp[4];
        RINOK(ReadStream_FALSE(InputStream, temp, 4));
        StreamPos += 4;
        UInt32 size = Get32(temp);

        if ((size & kMask_IsCompressed) == 0)
        {
            if (unpackSizeDefined && size != unpackSize)
                return S_FALSE;
            packSizeRes = size;
            if (outBuf)
                outBuf->Alloc(size);

            UInt64 offset = 0;

            while (size > 0)
            {
                UInt32 curSize = (UInt32)MyMin((size_t)size, Buffer.Size());
                UInt32 processedSize;
                RINOK(InputStream->Read(Buffer, curSize, &processedSize));
                if (processedSize == 0)
                    return S_FALSE;
                if (outBuf)
                    memcpy((Byte *)*outBuf + (size_t)offset, Buffer, processedSize);
                offset += processedSize;
                size -= processedSize;
                StreamPos += processedSize;
                unpackSizeRes += processedSize;
                if (realOutStream)
                    RINOK(WriteStream(realOutStream, Buffer, processedSize));
                RINOK(progress->SetRatioInfo(&offset, &offset));
            }

            return S_OK;
        }

        size &= ~kMask_IsCompressed;
        packSizeRes = size;
        limitedStreamSpec = new CLimitedSequentialInStream;
        limitedStream = limitedStreamSpec;
        limitedStreamSpec->SetStream(InputStream);
        limitedStreamSpec->Init(size);
        {
            bool useFilter;
            RINOK(Init(limitedStream, useFilter));
        }
    }

    if (outBuf)
    {
        if (!unpackSizeDefined)
            return S_FALSE;
        outBuf->Alloc(unpackSize);
    }

    UInt64 inSizeStart = 0;
    if (_lzmaDecoder)
        inSizeStart = _lzmaDecoder->GetInputProcessedSize();

    // we don't allow files larger than 4 GB;
    if (!unpackSizeDefined)
        unpackSize = 0xFFFFFFFF;
    UInt32 offset = 0;

    for (;;)
    {
        size_t rem = unpackSize - offset;
        if (rem == 0)
            break;
        size_t size = Buffer.Size();
        if (size > rem)
            size = rem;
        RINOK(Read(Buffer, &size));
        if (size == 0)
        {
            if (unpackSizeDefined)
                return S_FALSE;
            break;
        }
        if (outBuf)
            memcpy((Byte *)*outBuf + (size_t)offset, Buffer, size);
        StreamPos += size;
        offset += (UInt32)size;

        UInt64 inSize = 0; // it can be improved: we need inSize for Deflate and BZip2 too.
        if (_lzmaDecoder)
            inSize = _lzmaDecoder->GetInputProcessedSize() - inSizeStart;
        if (Solid)
            packSizeRes = (UInt32)inSize;
        unpackSizeRes += (UInt32)size;

        UInt64 outSize = offset;
        RINOK(progress->SetRatioInfo(&inSize, &outSize));
        if (realOutStream)
            RINOK(WriteStream(realOutStream, Buffer, size));
    }
    return S_OK;
}
Beispiel #13
0
HRESULT CInArchive::ReadDatabase2(
    DECL_EXTERNAL_CODECS_LOC_VARS
    CArchiveDatabaseEx &db
    #ifndef _NO_CRYPTO
    , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
    #endif
    )
{
  db.Clear();
  db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;

  db.ArchiveInfo.Version.Major = _header[6];
  db.ArchiveInfo.Version.Minor = _header[7];

  if (db.ArchiveInfo.Version.Major != kMajorVersion)
    ThrowUnsupportedVersion();

  UInt32 crcFromArchive = Get32(_header + 8);
  UInt64 nextHeaderOffset = Get64(_header + 0xC);
  UInt64 nextHeaderSize = Get64(_header + 0x14);
  UInt32 nextHeaderCRC = Get32(_header + 0x1C);
  UInt32 crc = CrcCalc(_header + 0xC, 20);

  #ifdef FORMAT_7Z_RECOVERY
  if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
  {
    UInt64 cur, cur2;
    RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
    const int kCheckSize = 500;
    Byte buf[kCheckSize];
    RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2));
    int checkSize = kCheckSize;
    if (cur2 - cur < kCheckSize)
      checkSize = (int)(cur2 - cur);
    RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2));
    
    RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize));

    int i;
    for (i = (int)checkSize - 2; i >= 0; i--)
      if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)
        break;
    if (i < 0)
      return S_FALSE;
    nextHeaderSize = checkSize - i;
    nextHeaderOffset = cur2 - cur + i;
    nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
    RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
  }
  else
  #endif
  {
    if (crc != crcFromArchive)
      ThrowIncorrect();
  }

  db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;

  if (nextHeaderSize == 0)
    return S_OK;

  if (nextHeaderSize > (UInt64)0xFFFFFFFF)
    return S_FALSE;

  if ((Int64)nextHeaderOffset < 0)
    return S_FALSE;

  RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));

  CByteBuffer buffer2;
  buffer2.SetCapacity((size_t)nextHeaderSize);

  RINOK(ReadStream_FALSE(_stream, buffer2, (size_t)nextHeaderSize));
  HeadersSize += kHeaderSize + nextHeaderSize;
  db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize;

  if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC)
    ThrowIncorrect();
  
  CStreamSwitch streamSwitch;
  streamSwitch.Set(this, buffer2);
  
  CObjectVector<CByteBuffer> dataVector;
  
  UInt64 type = ReadID();
  if (type != NID::kHeader)
  {
    if (type != NID::kEncodedHeader)
      ThrowIncorrect();
    HRESULT result = ReadAndDecodePackedStreams(
        EXTERNAL_CODECS_LOC_VARS
        db.ArchiveInfo.StartPositionAfterHeader,
        db.ArchiveInfo.DataStartPosition2,
        dataVector
        #ifndef _NO_CRYPTO
        , getTextPassword, passwordIsDefined
        #endif
        );
    RINOK(result);
    if (dataVector.Size() == 0)
      return S_OK;
    if (dataVector.Size() > 1)
      ThrowIncorrect();
    streamSwitch.Remove();
    streamSwitch.Set(this, dataVector.Front());
    if (ReadID() != NID::kHeader)
      ThrowIncorrect();
  }

  db.HeadersSize = HeadersSize;

  return ReadHeader(
    EXTERNAL_CODECS_LOC_VARS
    db
    #ifndef _NO_CRYPTO
    , getTextPassword, passwordIsDefined
    #endif
    );
}
Beispiel #14
0
HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode,
    ISequentialOutStream *outStream, ICompressProgressInfo *progress)
{
  RINOK(inStream->Seek(resource.Offset, STREAM_SEEK_SET, NULL));

  CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream();
  CMyComPtr<ISequentialInStream> limitedStream = limitedStreamSpec;
  limitedStreamSpec->SetStream(inStream);

  if (!copyCoder)
  {
    copyCoderSpec = new NCompress::CCopyCoder;
    copyCoder = copyCoderSpec;
  }
  if (!resource.IsCompressed())
  {
    if (resource.PackSize != resource.UnpackSize)
      return S_FALSE;
    limitedStreamSpec->Init(resource.PackSize);
    return copyCoder->Code(limitedStreamSpec, outStream, NULL, NULL, progress);
  }
  if (resource.UnpackSize == 0)
    return S_OK;
  UInt64 numChunks = (resource.UnpackSize + kChunkSize - 1) >> kChunkSizeBits;
  unsigned entrySize = ((resource.UnpackSize > (UInt64)1 << 32) ? 8 : 4);
  UInt64 sizesBufSize64 = entrySize * (numChunks - 1);
  size_t sizesBufSize = (size_t)sizesBufSize64;
  if (sizesBufSize != sizesBufSize64)
    return E_OUTOFMEMORY;
  if (sizesBufSize > sizesBuf.GetCapacity())
  {
    sizesBuf.Free();
    sizesBuf.SetCapacity(sizesBufSize);
  }
  RINOK(ReadStream_FALSE(inStream, (Byte *)sizesBuf, sizesBufSize));
  const Byte *p = (const Byte *)sizesBuf;
  
  if (lzxMode && !lzxDecoder)
  {
    lzxDecoderSpec = new NCompress::NLzx::CDecoder(true);
    lzxDecoder = lzxDecoderSpec;
    RINOK(lzxDecoderSpec->SetParams(kChunkSizeBits));
  }
  
  UInt64 baseOffset = resource.Offset + sizesBufSize64;
  UInt64 outProcessed = 0;
  for (UInt32 i = 0; i < (UInt32)numChunks; i++)
  {
    UInt64 offset = 0;
    if (i > 0)
    {
      offset = (entrySize == 4) ? Get32(p): Get64(p);
      p += entrySize;
    }
    UInt64 nextOffset = resource.PackSize - sizesBufSize64;
    if (i + 1 < (UInt32)numChunks)
      nextOffset = (entrySize == 4) ? Get32(p): Get64(p);
    if (nextOffset < offset)
      return S_FALSE;

    RINOK(inStream->Seek(baseOffset + offset, STREAM_SEEK_SET, NULL));
    UInt64 inSize = nextOffset - offset;
    limitedStreamSpec->Init(inSize);

    if (progress)
    {
      RINOK(progress->SetRatioInfo(&offset, &outProcessed));
    }
    
    UInt32 outSize = kChunkSize;
    if (outProcessed + outSize > resource.UnpackSize)
      outSize = (UInt32)(resource.UnpackSize - outProcessed);
    UInt64 outSize64 = outSize;
    if (inSize == outSize)
    {
      RINOK(copyCoder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL));
    }
    else
    {
      if (lzxMode)
      {
        lzxDecoderSpec->SetKeepHistory(false);
        RINOK(lzxDecoder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL));
      }
      else
      {
        RINOK(xpressDecoder.Code(limitedStreamSpec, outStream, outSize));
      }
    }
    outProcessed += outSize;
  }
  return S_OK;
}
Beispiel #15
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;
  }
}