Пример #1
1
bool LZMADecodeFile ( const char *fromFile, const char *toFile, CProgressInfo7Zip *progress )
{
	CMyComPtr<ISequentialInStream> inStream;
	CInFileStream *inStreamSpec = new CInFileStream;
	inStream = inStreamSpec;

	if ( !inStreamSpec->Open ( GetSystemString(fromFile) ) )
		return false;

	CMyComPtr<ISequentialOutStream> outStream;
	COutFileStream *outStreamSpec = new COutFileStream;
	outStream = outStreamSpec;
	if ( !outStreamSpec->Create ( GetSystemString(toFile), true ) )
		return false;


	NCompress::NLZMA::CDecoder *decoderSpec = new NCompress::NLZMA::CDecoder;

	CMyComPtr<ICompressCoder> decoder = decoderSpec;

	const UInt32 kPropertiesSize = 5;
	Byte properties[kPropertiesSize];
	UInt32 processedSize;
	
	if ( ReadStream (inStream, properties, kPropertiesSize, &processedSize) != S_OK )
		return false;

	if ( processedSize != kPropertiesSize )
		return false;

	if ( decoderSpec->SetDecoderProperties2(properties, kPropertiesSize) != S_OK )
		return false;

	UInt64 fileSize = 0;
	for (int i = 0; i < 8; i++)
	{
	  Byte b;
	  if ( inStream->Read(&b, 1, &processedSize) != S_OK )
		  return false;

	  if ( processedSize != 1 )
		  return false;
	  fileSize |= ((UInt64)b) << (8 * i);
	}

	if ( progress )
	{
		progress->Init();
		progress->ApprovedStart = 1 << 21;
		progress->SetMax ( fileSize );
	}

	if ( decoder->Code(inStream, outStream, 0, &fileSize, progress) != S_OK )
		// decoder error
		return false;

	return true;
}
Пример #2
0
HRESULT UpdateArchive(UInt64 unpackSize,
    ISequentialOutStream *outStream,
    int indexInClient,
    UInt32 dictionary,
    UInt32 numPasses,
    #ifdef COMPRESS_MT
    UInt32 numThreads,
    #endif
    IArchiveUpdateCallback *updateCallback)
{
  RINOK(updateCallback->SetTotal(unpackSize));
  UInt64 complexity = 0;
  RINOK(updateCallback->SetCompleted(&complexity));

  CMyComPtr<ISequentialInStream> fileInStream;

  RINOK(updateCallback->GetStream(indexInClient, &fileInStream));

  CLocalProgress *localProgressSpec = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
  localProgressSpec->Init(updateCallback, true);
  
  #ifndef COMPRESS_BZIP2
  CCoderLibrary lib;
  #endif
  CMyComPtr<ICompressCoder> encoder;
  #ifdef COMPRESS_BZIP2
  encoder = new NCompress::NBZip2::CEncoder;
  #else
  RINOK(lib.LoadAndCreateCoder(GetBZip2CodecPath(),
      CLSID_CCompressBZip2Encoder, &encoder));
  #endif

  CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
  encoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties);
  if (setCoderProperties)
  {
    NWindows::NCOM::CPropVariant properties[] = 
    {
      dictionary, 
      numPasses
      #ifdef COMPRESS_MT
      , numThreads
      #endif
    };
    PROPID propIDs[] = 
    {
      NCoderPropID::kDictionarySize,
      NCoderPropID::kNumPasses
      #ifdef COMPRESS_MT
      , NCoderPropID::kNumThreads
      #endif
    };
    RINOK(setCoderProperties->SetCoderProperties(propIDs, properties, sizeof(propIDs) / sizeof(propIDs[0])));
  }
  
  RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress));
  
  return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
}
Пример #3
0
HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress)
{
  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
  RINOK(copyCoder->Code(inStream, outStream, NULL, &size, progress));
  return copyCoderSpec->TotalSize == size ? S_OK : E_FAIL;
}
Пример #4
0
unsigned char *LZMADecodeData ( unsigned char *fromData, long fromSize, long &toSize, CProgressInfo7Zip *progress )
{
	CMyComPtr<ISequentialInStream> inStream;
	CInDataStream *inStreamSpec = new CInDataStream;
	inStream = inStreamSpec;

	inStreamSpec->LoadData ( fromData, fromSize );

	NCompress::NLZMA::CDecoder *decoderSpec = new NCompress::NLZMA::CDecoder;

	CMyComPtr<ICompressCoder> decoder = decoderSpec;

	const UInt32 kPropertiesSize = 5;
	Byte properties[kPropertiesSize];
	UInt32 processedSize;
	
	if ( ReadStream (inStream, properties, kPropertiesSize, &processedSize) != S_OK )
		return NULL;

	if ( processedSize != kPropertiesSize )
		return NULL;

	if ( decoderSpec->SetDecoderProperties2(properties, kPropertiesSize) != S_OK )
		return NULL;

	UInt64 fileSize = 0;
	for (int i = 0; i < 8; i++)
	{
	  Byte b;
	  if ( inStream->Read(&b, 1, &processedSize) != S_OK )
		  return NULL;

	  if ( processedSize != 1 )
		  return NULL;
	  fileSize |= ((UInt64)b) << (8 * i);
	}

	CMyComPtr<ISequentialOutStream> outStream;
	COutDataStream *outStreamSpec = new COutDataStream;
	outStream = outStreamSpec;
	outStreamSpec->Create ( fileSize );

//	CProgressInfo *progressInfoSpec = new CProgressInfo;
//	CMyComPtr<ICompressProgressInfo> progressInfo = progress;

	if ( progress )
	{
		progress->Init();
		progress->ApprovedStart = 1 << 21;
		progress->SetMax ( fileSize );
	}

	if ( decoder->Code(inStream, outStream, 0, &fileSize, progress) != S_OK )
		// decoder error
		return NULL;

	toSize = outStreamSpec->GetCurrentSize ();
	return outStreamSpec->GetData ();
}
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
    Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
{
  COM_TRY_BEGIN
  bool testMode = (_aTestMode != 0);
  bool allFilesMode = (numItems == UInt32(-1));
  if (allFilesMode)
    numItems = _sections.Size();
  if (numItems == 0)
    return S_OK;
  UInt64 totalSize = 0;
  UInt32 i;
  for (i = 0; i < numItems; i++)
    totalSize += _sections[allFilesMode ? i : indices[i]].GetPackSize();
  extractCallback->SetTotal(totalSize);

  UInt64 currentTotalSize = 0;
  UInt64 currentItemSize;
  
  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

  CLocalProgress *lps = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> progress = lps;
  lps->Init(extractCallback, false);

  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
  CMyComPtr<ISequentialInStream> inStream(streamSpec);
  streamSpec->SetStream(_inStream);

  for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
  {
    lps->InSize = lps->OutSize = currentTotalSize;
    RINOK(lps->SetCur());
    Int32 askMode = testMode ?
        NArchive::NExtract::NAskMode::kTest :
        NArchive::NExtract::NAskMode::kExtract;
    UInt32 index = allFilesMode ? i : indices[i];
    const CSection &item = _sections[index];
    currentItemSize = item.GetPackSize();

    CMyComPtr<ISequentialOutStream> outStream;
    RINOK(extractCallback->GetStream(index, &outStream, askMode));
    if (!testMode && !outStream)
      continue;
    
    RINOK(extractCallback->PrepareOperation(askMode));
    RINOK(_inStream->Seek(item.Pa, STREAM_SEEK_SET, NULL));
    streamSpec->Init(currentItemSize);
    RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
    outStream.Release();
    RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ?
        NArchive::NExtract::NOperationResult::kOK:
        NArchive::NExtract::NOperationResult::kDataError));
  }
  return S_OK;
  COM_TRY_END
}
Пример #6
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;
}
Пример #7
0
static HRESULT CopyBlock(ISequentialInStream *inStream, 
    ISequentialOutStream *outStream, ICompressProgressInfo *progress,
    UInt64 *totalSize = NULL)
{
  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
  HRESULT result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
  if (totalSize != NULL)
    *totalSize = copyCoderSpec->TotalSize;
  return result;
}
Пример #8
0
static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream,
	UInt64 position, UInt64 size, ICompressProgressInfo *progress)
{
	RINOK(inStream->Seek(position, STREAM_SEEK_SET, 0));
	CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
	CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
	streamSpec->SetStream(inStream);
	streamSpec->Init(size);

	NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
	CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
	RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
	return (copyCoderSpec->TotalSize == size ? S_OK : E_FAIL);
}
Пример #9
0
unsigned char *LZMAEncodeData ( unsigned char *fromData, long fromSize, long &toSize, CProgressInfo7Zip *progress )
{
	bool eos = false;

	CMyComPtr<ISequentialInStream> inStream;
	CInDataStream *inStreamSpec = new CInDataStream;
	inStream = inStreamSpec;
	inStreamSpec->LoadData ( fromData, fromSize );

	CMyComPtr<ISequentialOutStream> outStream;
	COutDataStream *outStreamSpec = new COutDataStream;
	outStream = outStreamSpec;
	outStreamSpec->Create ( toSize );

    NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder;
    CMyComPtr<ICompressCoder> encoder = encoderSpec;

	UInt32 dictionary = 1 << 21;
    UInt32 posStateBits = 2;
    UInt32 litContextBits = 3; // for normal files
    // UInt32 litContextBits = 0; // for 32-bit data
    UInt32 litPosBits = 0;
    // UInt32 litPosBits = 2; // for 32-bit data
    UInt32 algorithm = 2;
    UInt32 numFastBytes = 128;
    UInt32 matchFinderCycles = 16 + numFastBytes / 2;
    bool matchFinderCyclesDefined = false;

    //bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
 
    PROPID propIDs[] = 
    {
      NCoderPropID::kDictionarySize,
      NCoderPropID::kPosStateBits,
      NCoderPropID::kLitContextBits,
      NCoderPropID::kLitPosBits,
      NCoderPropID::kAlgorithm,
      NCoderPropID::kNumFastBytes,
      NCoderPropID::kMatchFinder,
      NCoderPropID::kEndMarker,
      NCoderPropID::kMatchFinderCycles
    };
    const int kNumPropsMax = sizeof(propIDs) / sizeof(propIDs[0]);

	UString mf = L"BT4";

    PROPVARIANT properties[kNumPropsMax];
    for (int p = 0; p < 6; p++)
      properties[p].vt = VT_UI4;

    properties[0].ulVal = UInt32(dictionary);
    properties[1].ulVal = UInt32(posStateBits);
    properties[2].ulVal = UInt32(litContextBits);
    properties[3].ulVal = UInt32(litPosBits);
    properties[4].ulVal = UInt32(algorithm);
    properties[5].ulVal = UInt32(numFastBytes);

    properties[8].vt = VT_UI4;
    properties[8].ulVal = UInt32(matchFinderCycles);
    
    properties[6].vt = VT_BSTR;
    properties[6].bstrVal = (BSTR)(const wchar_t *)mf;

    properties[7].vt = VT_BOOL;
    properties[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;

    int numProps = kNumPropsMax;
    if (!matchFinderCyclesDefined)
      numProps--;

    if ( encoderSpec->SetCoderProperties(propIDs, properties, numProps) != S_OK )
		return NULL;
    encoderSpec->WriteCoderProperties(outStream);

	UInt64 fileSize = 0;
	inStreamSpec->GetSize ( &fileSize );

    for (int i = 0; i < 8; i++)
    {
      Byte b = Byte(fileSize >> (8 * i));
      if (outStream->Write(&b, 1, 0) != S_OK)
		  return NULL;
    }

//	CProgressInfo *progressInfoSpec = new CProgressInfo;
	//CMyComPtr<ICompressProgressInfo> progressInfo = progress;

	if ( progress )
	{
		progress->ApprovedStart = 1 << 21;
		progress->SetMax ( fileSize );
		progress->SetIn ( true );
	}

    HRESULT result = encoder->Code(inStream, outStream, 0, 0, progress );

//	delete progressInfo;
    if (result == E_OUTOFMEMORY)
		return NULL;

    else if (result != S_OK)
		return NULL;

	toSize = outStreamSpec->GetCurrentSize();
	return outStreamSpec->GetData ();
}
Пример #10
0
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
    Int32 testMode, IArchiveExtractCallback *extractCallback)
{
  COM_TRY_BEGIN
  bool allFilesMode = (numItems == (UInt32)(Int32)-1);
  if (allFilesMode)
    numItems = _archive.Refs.Size();
  if (numItems == 0)
    return S_OK;
  UInt64 totalSize = 0;
  UInt32 i;
  for (i = 0; i < numItems; i++)
  {
    UInt32 index = (allFilesMode ? i : indices[i]);
    if (index < (UInt32)_archive.Refs.Size())
    {
      const CRef &ref = _archive.Refs[index];
      const CDir &item = ref.Dir->_subItems[ref.Index];
      if (!item.IsDir())
        totalSize += ref.TotalSize;
    }
    else
      totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size());
  }
  extractCallback->SetTotal(totalSize);

  UInt64 currentTotalSize = 0;
  UInt64 currentItemSize;
  
  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

  CLocalProgress *lps = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> progress = lps;
  lps->Init(extractCallback, false);

  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
  CMyComPtr<ISequentialInStream> inStream(streamSpec);
  streamSpec->SetStream(_stream);

  for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
  {
    lps->InSize = lps->OutSize = currentTotalSize;
    RINOK(lps->SetCur());
    currentItemSize = 0;
    CMyComPtr<ISequentialOutStream> realOutStream;
    Int32 askMode = testMode ?
        NExtract::NAskMode::kTest :
        NExtract::NAskMode::kExtract;
    UInt32 index = allFilesMode ? i : indices[i];
    
    RINOK(extractCallback->GetStream(index, &realOutStream, askMode));

    UInt64 blockIndex;
    if (index < (UInt32)_archive.Refs.Size())
    {
      const CRef &ref = _archive.Refs[index];
      const CDir &item = ref.Dir->_subItems[ref.Index];
      if (item.IsDir())
      {
        RINOK(extractCallback->PrepareOperation(askMode));
        RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
        continue;
      }
      currentItemSize = ref.TotalSize;
      blockIndex = item.ExtentLocation;
    }
    else
    {
      unsigned bootIndex = index - _archive.Refs.Size();
      const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
      currentItemSize = _archive.GetBootItemSize(bootIndex);
      blockIndex = be.LoadRBA;
    }
   

    if (!testMode && !realOutStream)
      continue;

    RINOK(extractCallback->PrepareOperation(askMode));

    bool isOK = true;
    if (index < (UInt32)_archive.Refs.Size())
    {
      const CRef &ref = _archive.Refs[index];
      UInt64 offset = 0;
      for (UInt32 e = 0; e < ref.NumExtents; e++)
      {
        lps->InSize = lps->OutSize = currentTotalSize + offset;
        const CDir &item2 = ref.Dir->_subItems[ref.Index + e];
        RINOK(_stream->Seek((UInt64)item2.ExtentLocation * kBlockSize, STREAM_SEEK_SET, NULL));
        streamSpec->Init(item2.Size);
        RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
        if (copyCoderSpec->TotalSize != item2.Size)
        {
          isOK = false;
          break;
        }
        offset += item2.Size;
      }
    }
    else
    {
      RINOK(_stream->Seek((UInt64)blockIndex * kBlockSize, STREAM_SEEK_SET, NULL));
      streamSpec->Init(currentItemSize);
      RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
      if (copyCoderSpec->TotalSize != currentItemSize)
        isOK = false;
    }
    realOutStream.Release();
    RINOK(extractCallback->SetOperationResult(isOK ?
        NExtract::NOperationResult::kOK:
        NExtract::NOperationResult::kDataError));
  }
  return S_OK;
  COM_TRY_END
}
Пример #11
0
HRESULT UpdateArchive(
    DECL_EXTERNAL_CODECS_LOC_VARS
    IInStream * /* inStream */, 
    UInt64 unpackSize,
    ISequentialOutStream *outStream,
    const CItem &newItem,
    const CCompressionMethodMode &compressionMethod,
    int indexInClient,
    IArchiveUpdateCallback *updateCallback)
{
  UInt64 complexity = unpackSize;

  RINOK(updateCallback->SetTotal(complexity));

  CMyComPtr<ICompressCoder> deflateEncoder;
  
  complexity = 0;
  RINOK(updateCallback->SetCompleted(&complexity));

  CMyComPtr<ISequentialInStream> fileInStream;

  RINOK(updateCallback->GetStream(indexInClient, &fileInStream));

  CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC;
  CMyComPtr<ISequentialInStream> crcStream(inStreamSpec);
  inStreamSpec->SetStream(fileInStream);
  inStreamSpec->Init();

  CLocalProgress *lps = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> progress = lps;
  lps->Init(updateCallback, true);
  
  COutArchive outArchive;
  outArchive.Create(outStream);

  CItem item = newItem;
  item.CompressionMethod = NFileHeader::NCompressionMethod::kDeflate;
  item.ExtraFlags = 0;
  item.HostOS = kHostOS;

  RINOK(outArchive.WriteHeader(item));

  {
    RINOK(CreateCoder(
        EXTERNAL_CODECS_LOC_VARS
        kMethodId_Deflate, deflateEncoder, true));
    if (!deflateEncoder)
      return E_NOTIMPL;

    NWindows::NCOM::CPropVariant properties[] = 
    { 
      compressionMethod.Algo, 
      compressionMethod.NumPasses, 
      compressionMethod.NumFastBytes,
      compressionMethod.NumMatchFinderCycles
    };
    PROPID propIDs[] = 
    { 
      NCoderPropID::kAlgorithm,
      NCoderPropID::kNumPasses, 
      NCoderPropID::kNumFastBytes,
      NCoderPropID::kMatchFinderCycles
    };
    int numProps = sizeof(propIDs) / sizeof(propIDs[0]);
    if (!compressionMethod.NumMatchFinderCyclesDefined)
      numProps--;
    CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
    RINOK(deflateEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties));
    RINOK(setCoderProperties->SetCoderProperties(propIDs, properties, numProps));
  }
  RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress));

  item.FileCRC = inStreamSpec->GetCRC();
  item.UnPackSize32 = (UInt32)inStreamSpec->GetSize();
  RINOK(outArchive.WritePostHeader(item));
  return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
}
Пример #12
0
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
    Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
{
  COM_TRY_BEGIN
  bool allFilesMode = (numItems == (UInt32)-1);
  if (allFilesMode)
    numItems = m_Database.Items.Size();
  if(numItems == 0)
    return S_OK;
  bool testMode = (testModeSpec != 0);
  UInt64 totalUnPacked = 0;

  UInt32 i;
  int lastFolder = -2;
  UInt64 lastFolderSize = 0;
  for(i = 0; i < numItems; i++)
  {
    int index = allFilesMode ? i : indices[i];
    const CMvItem &mvItem = m_Database.Items[index];
    const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
    if (item.IsDir())
      continue;
    int folderIndex = m_Database.GetFolderIndex(&mvItem);
    if (folderIndex != lastFolder)
      totalUnPacked += lastFolderSize;
    lastFolder = folderIndex;
    lastFolderSize = item.GetEndOffset();
  }
  totalUnPacked += lastFolderSize;

  extractCallback->SetTotal(totalUnPacked);

  totalUnPacked = 0;

  UInt64 totalPacked = 0;

  CLocalProgress *lps = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> progress = lps;
  lps->Init(extractCallback, false);

  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

  NCompress::NDeflate::NDecoder::CCOMCoder *deflateDecoderSpec = NULL;
  CMyComPtr<ICompressCoder> deflateDecoder;

  NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL;
  CMyComPtr<ICompressCoder> lzxDecoder;

  NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL;
  CMyComPtr<ICompressCoder> quantumDecoder;

  CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream();
  CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec;
  if (!cabBlockInStreamSpec->Create())
    return E_OUTOFMEMORY;

  CRecordVector<bool> extractStatuses;
  for(i = 0; i < numItems;)
  {
    int index = allFilesMode ? i : indices[i];

    const CMvItem &mvItem = m_Database.Items[index];
    const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
    int itemIndex = mvItem.ItemIndex;
    const CItem &item = db.Items[itemIndex];

    i++;
    if (item.IsDir())
    {
      Int32 askMode = testMode ?
          NExtract::NAskMode::kTest :
          NExtract::NAskMode::kExtract;
      CMyComPtr<ISequentialOutStream> realOutStream;
      RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
      RINOK(extractCallback->PrepareOperation(askMode));
      realOutStream.Release();
      RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
      continue;
    }
    int folderIndex = m_Database.GetFolderIndex(&mvItem);
    if (folderIndex < 0)
    {
      // If we need previous archive
      Int32 askMode= testMode ?
          NExtract::NAskMode::kTest :
          NExtract::NAskMode::kExtract;
      CMyComPtr<ISequentialOutStream> realOutStream;
      RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
      RINOK(extractCallback->PrepareOperation(askMode));
      realOutStream.Release();
      RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError));
      continue;
    }
    int startIndex2 = m_Database.FolderStartFileIndex[folderIndex];
    int startIndex = startIndex2;
    extractStatuses.Clear();
    for (; startIndex < index; startIndex++)
      extractStatuses.Add(false);
    extractStatuses.Add(true);
    startIndex++;
    UInt64 curUnpack = item.GetEndOffset();
    for(;i < numItems; i++)
    {
      int indexNext = allFilesMode ? i : indices[i];
      const CMvItem &mvItem = m_Database.Items[indexNext];
      const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
      if (item.IsDir())
        continue;
      int newFolderIndex = m_Database.GetFolderIndex(&mvItem);

      if (newFolderIndex != folderIndex)
        break;
      for (; startIndex < indexNext; startIndex++)
        extractStatuses.Add(false);
      extractStatuses.Add(true);
      startIndex++;
      curUnpack = item.GetEndOffset();
    }

    lps->OutSize = totalUnPacked;
    lps->InSize = totalPacked;
    RINOK(lps->SetCur());

    CFolderOutStream *cabFolderOutStream = new CFolderOutStream;
    CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream);

    const CFolder &folder = db.Folders[item.GetFolderIndex(db.Folders.Size())];

    cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2,
        curUnpack, extractCallback, testMode);

    cabBlockInStreamSpec->MsZip = false;
    switch(folder.GetCompressionMethod())
    {
      case NHeader::NCompressionMethodMajor::kNone:
        break;
      case NHeader::NCompressionMethodMajor::kMSZip:
        if(deflateDecoderSpec == NULL)
        {
          deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder;
          deflateDecoder = deflateDecoderSpec;
        }
        cabBlockInStreamSpec->MsZip = true;
        break;
      case NHeader::NCompressionMethodMajor::kLZX:
        if(lzxDecoderSpec == NULL)
        {
          lzxDecoderSpec = new NCompress::NLzx::CDecoder;
          lzxDecoder = lzxDecoderSpec;
        }
        RINOK(lzxDecoderSpec->SetParams(folder.CompressionTypeMinor));
        break;
      case NHeader::NCompressionMethodMajor::kQuantum:
        if(quantumDecoderSpec == NULL)
        {
          quantumDecoderSpec = new NCompress::NQuantum::CDecoder;
          quantumDecoder = quantumDecoderSpec;
        }
        quantumDecoderSpec->SetParams(folder.CompressionTypeMinor);
        break;
      default:
      {
        RINOK(cabFolderOutStream->Unsupported());
        totalUnPacked += curUnpack;
        continue;
      }
    }

    cabBlockInStreamSpec->InitForNewFolder();

    HRESULT res = S_OK;

    {
      int volIndex = mvItem.VolumeIndex;
      int locFolderIndex = item.GetFolderIndex(db.Folders.Size());
      bool keepHistory = false;
      bool keepInputBuffer = false;
      for (UInt32 f = 0; cabFolderOutStream->GetRemain() != 0;)
      {
        if (volIndex >= m_Database.Volumes.Size())
        {
          res = S_FALSE;
          break;
        }

        const CDatabaseEx &db = m_Database.Volumes[volIndex];
        const CFolder &folder = db.Folders[locFolderIndex];
        if (f == 0)
        {
          cabBlockInStreamSpec->SetStream(db.Stream);
          cabBlockInStreamSpec->ReservedSize = db.ArchiveInfo.GetDataBlockReserveSize();
          RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL));
        }
        if (f == folder.NumDataBlocks)
        {
          volIndex++;
          locFolderIndex = 0;
          f = 0;
          continue;
        }
        f++;

        cabBlockInStreamSpec->DataError = false;
        
        if (!keepInputBuffer)
          cabBlockInStreamSpec->InitForNewBlock();

        UInt32 packSize, unpackSize;
        res = cabBlockInStreamSpec->PreRead(packSize, unpackSize);
        if (res == S_FALSE)
          break;
        RINOK(res);
        keepInputBuffer = (unpackSize == 0);
        if (keepInputBuffer)
          continue;

        UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFolder();
        totalPacked += packSize;

        lps->OutSize = totalUnPacked2;
        lps->InSize = totalPacked;
        RINOK(lps->SetCur());

        UInt64 unpackRemain = cabFolderOutStream->GetRemain();

        const UInt32 kBlockSizeMax = (1 << 15);
        if (unpackRemain > kBlockSizeMax)
          unpackRemain = kBlockSizeMax;
        if (unpackRemain > unpackSize)
          unpackRemain  = unpackSize;
   
        switch(folder.GetCompressionMethod())
        {
          case NHeader::NCompressionMethodMajor::kNone:
            res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
            break;
          case NHeader::NCompressionMethodMajor::kMSZip:
            deflateDecoderSpec->SetKeepHistory(keepHistory);
            res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
            break;
          case NHeader::NCompressionMethodMajor::kLZX:
            lzxDecoderSpec->SetKeepHistory(keepHistory);
            res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
            break;
          case NHeader::NCompressionMethodMajor::kQuantum:
            quantumDecoderSpec->SetKeepHistory(keepHistory);
            res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
          break;
        }
        if (res != S_OK)
        {
          if (res != S_FALSE)
            RINOK(res);
          break;
        }
        keepHistory = true;
      }
      if (res == S_OK)
      {
        RINOK(cabFolderOutStream->WriteEmptyFiles());
      }
    }
    if (res != S_OK || cabFolderOutStream->GetRemain() != 0)
    {
      RINOK(cabFolderOutStream->FlushCorrupted());
    }
    totalUnPacked += curUnpack;
  }
  return S_OK;
  COM_TRY_END
}
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
                               Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
{
    COM_TRY_BEGIN
    bool testMode = (_aTestMode != 0);
    bool allFilesMode = (numItems == UInt32(-1));
    if (allFilesMode)
        numItems = _db.Refs.Size();
    if (numItems == 0)
        return S_OK;
    UInt32 i;
    UInt64 totalSize = 0;
    for(i = 0; i < numItems; i++)
    {
        const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did];
        if (!item.IsDir())
            totalSize += item.Size;
    }
    RINOK(extractCallback->SetTotal(totalSize));

    UInt64 totalPackSize;
    totalSize = totalPackSize = 0;

    NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
    CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

    CLocalProgress *lps = new CLocalProgress;
    CMyComPtr<ICompressProgressInfo> progress = lps;
    lps->Init(extractCallback, false);

    for (i = 0; i < numItems; i++)
    {
        lps->InSize = totalPackSize;
        lps->OutSize = totalSize;
        RINOK(lps->SetCur());
        Int32 index = allFilesMode ? i : indices[i];
        const CItem &item = _db.Items[_db.Refs[index].Did];

        CMyComPtr<ISequentialOutStream> outStream;
        Int32 askMode = testMode ?
                        NArchive::NExtract::NAskMode::kTest :
                        NArchive::NExtract::NAskMode::kExtract;
        RINOK(extractCallback->GetStream(index, &outStream, askMode));

        if (item.IsDir())
        {
            RINOK(extractCallback->PrepareOperation(askMode));
            RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
            continue;
        }

        totalPackSize += _db.GetItemPackSize(item.Size);
        totalSize += item.Size;

        if (!testMode && (!outStream))
            continue;
        RINOK(extractCallback->PrepareOperation(askMode));
        Int32 res = NArchive::NExtract::NOperationResult::kDataError;
        CMyComPtr<ISequentialInStream> inStream;
        HRESULT hres = GetStream(index, &inStream);
        if (hres == S_FALSE)
            res = NArchive::NExtract::NOperationResult::kDataError;
        else if (hres == E_NOTIMPL)
            res = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
        else
        {
            RINOK(hres);
            if (inStream)
            {
                RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
                if (copyCoderSpec->TotalSize == item.Size)
                    res = NArchive::NExtract::NOperationResult::kOK;
            }
        }
        outStream.Release();
        RINOK(extractCallback->SetOperationResult(res));
    }
    return S_OK;
    COM_TRY_END
}
Пример #14
0
int main2(int n, const char *args[])
{
	if (strcmp(args[n - 1], "-notitle") == 0)
		n--; 
	else {
		fprintf(stderr,
			"\nt5lzma 1.00 Copyright (C) 2004 H.Kawai\n"
			" --- based : LZMA 4.03 Copyright (c) 1999-2004 Igor Pavlov  2004-06-18\n"
		);
	}

  if (n == 1)
  {
    PrintHelp();
    return 0;
  }

  if (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4)
  {
    fprintf(stderr, "Unsupported base types. Edit Common/Types.h and recompile");
    return 1;
  }   

  UStringVector commandStrings;
  WriteArgumentsToStringList(n, args, commandStrings);
  CParser parser(kNumSwitches);
  try
  {
    parser.ParseStrings(kSwitchForms, commandStrings);
  }
  catch(...) 
  {
    IncorrectCommand();
  }

  if(parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
  {
    PrintHelp();
    return 0;
  }
  const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;

  int paramIndex = 0;
  if (paramIndex >= nonSwitchStrings.Size())
    IncorrectCommand();
  const UString &command = nonSwitchStrings[paramIndex++]; 

  if (command.CompareNoCase(L"b") == 0)
  {
    UInt32 dictionary = 1 << 21;
    if(parser[NKey::kDictionary].ThereIs)
    {
      UInt32 dicLog;
      if (!GetNumber(parser[NKey::kDictionary].PostStrings[0], dicLog))
        IncorrectCommand();
      dictionary = 1 << dicLog;
    }
    const UInt32 kNumDefaultItereations = 10;
    UInt32 numIterations = kNumDefaultItereations;
    {
      if (paramIndex < nonSwitchStrings.Size())
        if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations))
          numIterations = kNumDefaultItereations;
    }
    return LzmaBenchmark(numIterations, dictionary);
  }

  bool encodeMode;
  if (command.CompareNoCase(L"e") == 0)
    encodeMode = true;
  else if (command.CompareNoCase(L"d") == 0)
    encodeMode = false;
  else
    IncorrectCommand();

  bool stdInMode = parser[NKey::kStdIn].ThereIs;
  bool stdOutMode = parser[NKey::kStdOut].ThereIs;

  CMyComPtr<ISequentialInStream> inStream;
  CInFileStream *inStreamSpec = 0;
  if (stdInMode)
  {
    inStream = new CStdInFileStream;
    MY_SET_BINARY_MODE(stdin);
  }
  else
  {
    if (paramIndex >= nonSwitchStrings.Size())
      IncorrectCommand();
    const UString &inputName = nonSwitchStrings[paramIndex++]; 
    inStreamSpec = new CInFileStream;
    inStream = inStreamSpec;
    if (!inStreamSpec->Open(GetSystemString(inputName)))
    {
      fprintf(stderr, "\nError: can not open input file %s\n", 
          (const char *)GetOemString(inputName));
      return 1;
    }
  }

  CMyComPtr<ISequentialOutStream> outStream;
  if (stdOutMode)
  {
    outStream = new CStdOutFileStream;
    MY_SET_BINARY_MODE(stdout);
  }
  else
  {
    if (paramIndex >= nonSwitchStrings.Size())
      IncorrectCommand();
    const UString &outputName = nonSwitchStrings[paramIndex++]; 
    COutFileStream *outStreamSpec = new COutFileStream;
    outStream = outStreamSpec;
    if (!outStreamSpec->Open(GetSystemString(outputName)))
    {
      fprintf(stderr, "\nError: can not open output file %s\n", 
        (const char *)GetOemString(outputName));
      return 1;
    }
  }

  UInt64 fileSize;
  if (encodeMode)
  {
    NCompress::NLZMA::CEncoder *encoderSpec = 
      new NCompress::NLZMA::CEncoder;
    CMyComPtr<ICompressCoder> encoder = encoderSpec;

    UInt32 dictionary = 1 << 23;
    UInt32 posStateBits = 0;
    // UInt32 posStateBits = 2;
    // UInt32 litContextBits = 3; // for normal files
    UInt32 litContextBits = 0; // for 32-bit data
    UInt32 litPosBits = 0;
    // UInt32 litPosBits = 2; // for 32-bit data
    UInt32 algorithm = 2;
    UInt32 numFastBytes = 128;
    UString mf = L"BT4";

    bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
 
    if(parser[NKey::kMode].ThereIs)
      if (!GetNumber(parser[NKey::kMode].PostStrings[0], algorithm))
        IncorrectCommand();

    if(parser[NKey::kDictionary].ThereIs)
    {
      UInt32 dicLog;
      if (!GetNumber(parser[NKey::kDictionary].PostStrings[0], dicLog))
        IncorrectCommand();
      dictionary = 1 << dicLog;
    }
    if(parser[NKey::kFastBytes].ThereIs)
      if (!GetNumber(parser[NKey::kFastBytes].PostStrings[0], numFastBytes))
        IncorrectCommand();
    if(parser[NKey::kLitContext].ThereIs)
      if (!GetNumber(parser[NKey::kLitContext].PostStrings[0], litContextBits))
        IncorrectCommand();
    if(parser[NKey::kLitPos].ThereIs)
      if (!GetNumber(parser[NKey::kLitPos].PostStrings[0], litPosBits))
        IncorrectCommand();
    if(parser[NKey::kPosBits].ThereIs)
      if (!GetNumber(parser[NKey::kPosBits].PostStrings[0], posStateBits))
        IncorrectCommand();

    if (parser[NKey::kMatchFinder].ThereIs)
      mf = parser[NKey::kMatchFinder].PostStrings[0];

    PROPID propIDs[] = 
    {
      NCoderPropID::kDictionarySize,
      NCoderPropID::kPosStateBits,
      NCoderPropID::kLitContextBits,
      NCoderPropID::kLitPosBits,
      NCoderPropID::kAlgorithm,
      NCoderPropID::kNumFastBytes,
      NCoderPropID::kMatchFinder,
      NCoderPropID::kEndMarker
    };
    const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
    /*
    NWindows::NCOM::CPropVariant properties[kNumProps];
    properties[0] = UInt32(dictionary);
    properties[1] = UInt32(posStateBits);
    properties[2] = UInt32(litContextBits);
   
    properties[3] = UInt32(litPosBits);
    properties[4] = UInt32(algorithm);
    properties[5] = UInt32(numFastBytes);
    properties[6] = mf;
    properties[7] = eos;
    */
    PROPVARIANT properties[kNumProps];
    for (int p = 0; p < 6; p++)
      properties[p].vt = VT_UI4;
    properties[0].ulVal = UInt32(dictionary);
    properties[1].ulVal = UInt32(posStateBits);
    properties[2].ulVal = UInt32(litContextBits);
    properties[3].ulVal = UInt32(litPosBits);
    properties[4].ulVal = UInt32(algorithm);
    properties[5].ulVal = UInt32(numFastBytes);
    
    properties[6].vt = VT_BSTR;
    properties[6].bstrVal = (BSTR)(const wchar_t *)mf;

    properties[7].vt = VT_BOOL;
    properties[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;

    if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
      IncorrectCommand();
    encoderSpec->WriteCoderProperties(outStream);

    if (eos || stdInMode)
      fileSize = (UInt64)(Int64)-1;
    else
      inStreamSpec->File.GetLength(fileSize);

    for (int i = 0; i < 8; i++)
    {
      Byte b = Byte(fileSize >> (8 * i));
      if (outStream->Write(&b, sizeof(b), 0) != S_OK)
      {
        fprintf(stderr, "Write error");
        return 1;
      }
    }
    HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
    if (result == E_OUTOFMEMORY)
    {
      fprintf(stderr, "\nError: Can not allocate memory\n");
      return 1;
    }   
    else if (result != S_OK)
    {
      fprintf(stderr, "\nEncoder error = %X\n", result);
      return 1;
    }   
  }
  else
  {
Пример #15
0
int main2(int numArgs, const char *args[])
{
  NT_CHECK

  PrintMessage("\nLZMA " MY_VERSION_COPYRIGHT_DATE "\n");

  if (numArgs == 1)
  {
    PrintHelp();
    return 0;
  }

  bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4);
  if (unsupportedTypes)
  {
    PrintMessage("Unsupported base types. Edit Common/Types.h and recompile");
    return 1;
  }

  UStringVector commandStrings;
  WriteArgumentsToStringList(numArgs, args, commandStrings);
  CParser parser(kNumSwitches);
  try
  {
    parser.ParseStrings(kSwitchForms, commandStrings);
  }
  catch(...)
  {
    IncorrectCommand();
  }

  if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
  {
    PrintHelp();
    return 0;
  }
  const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;

  int paramIndex = 0;
  if (paramIndex >= nonSwitchStrings.Size())
    IncorrectCommand();
  const UString &command = nonSwitchStrings[paramIndex++];

  CObjectVector<CProperty> props;
  bool dictDefined = false;
  UInt32 dict = (UInt32)(Int32)-1;
  if (parser[NKey::kDict].ThereIs)
  {
    UInt32 dicLog;
    const UString &s = parser[NKey::kDict].PostStrings[0];
    if (!GetNumber(s, dicLog))
      IncorrectCommand();
    dict = 1 << dicLog;
    dictDefined = true;
    CProperty prop;
    prop.Name = L"d";
    prop.Value = s;
    props.Add(prop);
  }
  if (parser[NKey::kLevel].ThereIs)
  {
    UInt32 level = 5;
    const UString &s = parser[NKey::kLevel].PostStrings[0];
    if (!GetNumber(s, level))
      IncorrectCommand();
    CProperty prop;
    prop.Name = L"x";
    prop.Value = s;
    props.Add(prop);
  }
  UString mf = L"BT4";
  if (parser[NKey::kMatchFinder].ThereIs)
    mf = parser[NKey::kMatchFinder].PostStrings[0];

  UInt32 numThreads = (UInt32)(Int32)-1;

  #ifndef _7ZIP_ST
  if (parser[NKey::kMultiThread].ThereIs)
  {
    UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
    const UString &s = parser[NKey::kMultiThread].PostStrings[0];
    if (s.IsEmpty())
      numThreads = numCPUs;
    else
      if (!GetNumber(s, numThreads))
        IncorrectCommand();
    CProperty prop;
    prop.Name = L"mt";
    prop.Value = s;
    props.Add(prop);
  }
  #endif

  if (parser[NKey::kMethod].ThereIs)
  {
    UString s = parser[NKey::kMethod].PostStrings[0];
    if (s.IsEmpty() || s[0] != '=')
      IncorrectCommand();
    CProperty prop;
    prop.Name = L"m";
    prop.Value = s.Mid(1);
    props.Add(prop);
  }

  if (command.CompareNoCase(L"b") == 0)
  {
    const UInt32 kNumDefaultItereations = 1;
    UInt32 numIterations = kNumDefaultItereations;
    {
      if (paramIndex < nonSwitchStrings.Size())
        if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations))
          numIterations = kNumDefaultItereations;
    }
    HRESULT res = BenchCon(props, numIterations, stderr);
    if (res != S_OK)
    {
      if (res != E_ABORT)
      {
        PrintMessage("Benchmark Error");
        return 1;
      }
    }
    return 0;
  }

  if (numThreads == (UInt32)(Int32)-1)
    numThreads = 1;

  bool encodeMode = false;
  if (command.CompareNoCase(L"e") == 0)
    encodeMode = true;
  else if (command.CompareNoCase(L"d") == 0)
    encodeMode = false;
  else
    IncorrectCommand();

  bool stdInMode = parser[NKey::kStdIn].ThereIs;
  bool stdOutMode = parser[NKey::kStdOut].ThereIs;

  CMyComPtr<ISequentialInStream> inStream;
  CInFileStream *inStreamSpec = 0;
  if (stdInMode)
  {
    inStream = new CStdInFileStream;
    MY_SET_BINARY_MODE(stdin);
  }
  else
  {
    if (paramIndex >= nonSwitchStrings.Size())
      IncorrectCommand();
    const UString &inputName = nonSwitchStrings[paramIndex++];
    inStreamSpec = new CInFileStream;
    inStream = inStreamSpec;
    if (!inStreamSpec->Open(us2fs(inputName)))
    {
      fprintf(stderr, "\nError: can not open input file %s\n",
          (const char *)GetOemString(inputName));
      return 1;
    }
  }

  CMyComPtr<ISequentialOutStream> outStream;
  COutFileStream *outStreamSpec = NULL;
  if (stdOutMode)
  {
    outStream = new CStdOutFileStream;
    MY_SET_BINARY_MODE(stdout);
  }
  else
  {
    if (paramIndex >= nonSwitchStrings.Size())
      IncorrectCommand();
    const UString &outputName = nonSwitchStrings[paramIndex++];
    outStreamSpec = new COutFileStream;
    outStream = outStreamSpec;
    if (!outStreamSpec->Create(us2fs(outputName), true))
    {
      fprintf(stderr, "\nError: can not open output file %s\n",
        (const char *)GetOemString(outputName));
      return 1;
    }
  }

  if (parser[NKey::kFilter86].ThereIs)
  {
    // -f86 switch is for x86 filtered mode: BCJ + LZMA.
    if (parser[NKey::kEOS].ThereIs || stdInMode)
      throw "Can not use stdin in this mode";
    UInt64 fileSize;
    inStreamSpec->File.GetLength(fileSize);
    if (fileSize > 0xF0000000)
      throw "File is too big";
    size_t inSize = (size_t)fileSize;
    Byte *inBuffer = 0;
    if (inSize != 0)
    {
      inBuffer = (Byte *)MyAlloc((size_t)inSize);
      if (inBuffer == 0)
        throw kCantAllocate;
    }
    
    if (ReadStream_FAIL(inStream, inBuffer, inSize) != S_OK)
      throw "Can not read";

    Byte *outBuffer = 0;
    size_t outSize;
    if (encodeMode)
    {
      // we allocate 105% of original size for output buffer
      outSize = (size_t)fileSize / 20 * 21 + (1 << 16);
      if (outSize != 0)
      {
        outBuffer = (Byte *)MyAlloc((size_t)outSize);
        if (outBuffer == 0)
          throw kCantAllocate;
      }
      if (!dictDefined)
        dict = 1 << 23;
      int res = Lzma86_Encode(outBuffer, &outSize, inBuffer, inSize,
          5, dict, parser[NKey::kFilter86].PostCharIndex == 0 ? SZ_FILTER_YES : SZ_FILTER_AUTO);
      if (res != 0)
      {
        fprintf(stderr, "\nEncoder error = %d\n", (int)res);
        return 1;
      }
    }
    else
    {
      UInt64 outSize64;
      if (Lzma86_GetUnpackSize(inBuffer, inSize, &outSize64) != 0)
        throw "data error";
      outSize = (size_t)outSize64;
      if (outSize != outSize64)
        throw "too big";
      if (outSize != 0)
      {
        outBuffer = (Byte *)MyAlloc(outSize);
        if (outBuffer == 0)
          throw kCantAllocate;
      }
      int res = Lzma86_Decode(outBuffer, &outSize, inBuffer, &inSize);
      if (inSize != (size_t)fileSize)
        throw "incorrect processed size";
      if (res != 0)
        throw "LzmaDecoder error";
    }
    if (WriteStream(outStream, outBuffer, outSize) != S_OK)
      throw kWriteError;
    MyFree(outBuffer);
    MyFree(inBuffer);
    return 0;
  }


  UInt64 fileSize;
  if (encodeMode)
  {
    NCompress::NLzma::CEncoder *encoderSpec = new NCompress::NLzma::CEncoder;
    CMyComPtr<ICompressCoder> encoder = encoderSpec;

    if (!dictDefined)
      dict = 1 << 23;

    UInt32 pb = 2;
    UInt32 lc = 3; // = 0; for 32-bit data
    UInt32 lp = 0; // = 2; for 32-bit data
    UInt32 algo = 1;
    UInt32 fb = 128;
    UInt32 mc = 16 + fb / 2;
    bool mcDefined = false;

    bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
 
    ParseUInt32(parser, NKey::kAlgo, algo);
    ParseUInt32(parser, NKey::kFb, fb);
    ParseUInt32(parser, NKey::kLc, lc);
    ParseUInt32(parser, NKey::kLp, lp);
    ParseUInt32(parser, NKey::kPb, pb);

    mcDefined = parser[NKey::kMc].ThereIs;
    if (mcDefined)
      if (!GetNumber(parser[NKey::kMc].PostStrings[0], mc))
        IncorrectCommand();
    
    const PROPID propIDs[] =
    {
      NCoderPropID::kDictionarySize,
      NCoderPropID::kPosStateBits,
      NCoderPropID::kLitContextBits,
      NCoderPropID::kLitPosBits,
      NCoderPropID::kAlgorithm,
      NCoderPropID::kNumFastBytes,
      NCoderPropID::kMatchFinder,
      NCoderPropID::kEndMarker,
      NCoderPropID::kNumThreads,
      NCoderPropID::kMatchFinderCycles,
    };
    const int kNumPropsMax = sizeof(propIDs) / sizeof(propIDs[0]);

    PROPVARIANT props[kNumPropsMax];
    for (int p = 0; p < 6; p++)
      props[p].vt = VT_UI4;

    props[0].ulVal = (UInt32)dict;
    props[1].ulVal = (UInt32)pb;
    props[2].ulVal = (UInt32)lc;
    props[3].ulVal = (UInt32)lp;
    props[4].ulVal = (UInt32)algo;
    props[5].ulVal = (UInt32)fb;

    props[6].vt = VT_BSTR;
    props[6].bstrVal = const_cast<BSTR>((const wchar_t *)mf);

    props[7].vt = VT_BOOL;
    props[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;

    props[8].vt = VT_UI4;
    props[8].ulVal = (UInt32)numThreads;

    // it must be last in property list
    props[9].vt = VT_UI4;
    props[9].ulVal = (UInt32)mc;

    int numProps = kNumPropsMax;
    if (!mcDefined)
      numProps--;

    if (encoderSpec->SetCoderProperties(propIDs, props, numProps) != S_OK)
      IncorrectCommand();
    encoderSpec->WriteCoderProperties(outStream);

    if (eos || stdInMode)
      fileSize = (UInt64)(Int64)-1;
    else
      inStreamSpec->File.GetLength(fileSize);

    for (int i = 0; i < 8; i++)
    {
      Byte b = Byte(fileSize >> (8 * i));
      if (outStream->Write(&b, 1, 0) != S_OK)
      {
        PrintMessage(kWriteError);
        return 1;
      }
    }
    HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
    if (result == E_OUTOFMEMORY)
    {
      PrintMessage("\nError: Can not allocate memory\n");
      return 1;
    }
    else if (result != S_OK)
    {
      fprintf(stderr, "\nEncoder error = %X\n", (unsigned int)result);
      return 1;
    }
  }
  else
  {
Пример #16
0
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
    Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
{
  COM_TRY_BEGIN
  bool testMode = (_aTestMode != 0);
  bool allFilesMode = (numItems == UInt32(-1));
  if (allFilesMode)
    numItems = _archive.Refs.Size();
  if(numItems == 0)
    return S_OK;
  UInt64 totalSize = 0;
  UInt32 i;
  for(i = 0; i < numItems; i++)
  {
    UInt32 index = (allFilesMode ? i : indices[i]);
    if (index < (UInt32)_archive.Refs.Size())
    {
      const CRef &ref = _archive.Refs[index];
      const CDir &item = ref.Dir->_subItems[ref.Index];
      totalSize += item.DataLength;
    }
    else
    {
      totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size());
    }
  }
  extractCallback->SetTotal(totalSize);

  UInt64 currentTotalSize = 0;
  UInt64 currentItemSize;
  
  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

  CLocalProgress *lps = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> progress = lps;
  lps->Init(extractCallback, false);

  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
  CMyComPtr<ISequentialInStream> inStream(streamSpec);
  streamSpec->SetStream(_inStream);

  for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
  {
    lps->InSize = lps->OutSize = currentTotalSize;
    RINOK(lps->SetCur());
    currentItemSize = 0;
    CMyComPtr<ISequentialOutStream> realOutStream;
    Int32 askMode;
    askMode = testMode ? NArchive::NExtract::NAskMode::kTest : NArchive::NExtract::NAskMode::kExtract;
    UInt32 index = allFilesMode ? i : indices[i];
    
    RINOK(extractCallback->GetStream(index, &realOutStream, askMode));

    UInt64 blockIndex;
    if (index < (UInt32)_archive.Refs.Size())
    {
      const CRef &ref = _archive.Refs[index];
      const CDir &item = ref.Dir->_subItems[ref.Index];
      if(item.IsDir())
      {
        RINOK(extractCallback->PrepareOperation(askMode));
        RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
        continue;
      }
      currentItemSize = item.DataLength;
      blockIndex = item.ExtentLocation;
    }
    else
    {
      int bootIndex = index - _archive.Refs.Size();
      const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
      currentItemSize = _archive.GetBootItemSize(bootIndex);
      blockIndex = be.LoadRBA;
    }
   
    if (!testMode && (!realOutStream))
      continue;
    RINOK(extractCallback->PrepareOperation(askMode));
    if (testMode)
    {
      RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
      continue;
    }
    RINOK(_inStream->Seek(blockIndex * _archive.BlockSize, STREAM_SEEK_SET, NULL));
    streamSpec->Init(currentItemSize);
    RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
    realOutStream.Release();
    RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == currentItemSize) ?
        NArchive::NExtract::NOperationResult::kOK:
        NArchive::NExtract::NOperationResult::kDataError));
  }
  return S_OK;
  COM_TRY_END
}
Пример #17
0
HRESULT CHandler::Open2(IInStream *stream)
{
  const UInt32 kHeaderSize = 0x1C;
  Byte buf[kHeaderSize];
  RINOK(ReadStream_FALSE(stream, buf, kHeaderSize));

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

  UInt64 packSize = Get64(buf + 8);
  UInt64 unpackSize = Get64(buf + 0x10);

  // _checkSumAlgo = Get32(buf + 0x18);

  if (packSize >= kXmlPackSizeMax ||
      unpackSize >= kXmlSizeMax)
    return S_FALSE;

  _dataStartPos = kHeaderSize + packSize;
  _phySize = _dataStartPos;

  _xml.Alloc((size_t)unpackSize + 1);
  _xmlLen = (size_t)unpackSize;
  
  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(_xml, (size_t)unpackSize);

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

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

  _xml[(size_t)unpackSize] = 0;
  if (strlen((const char *)(const Byte *)_xml) != unpackSize) return S_FALSE;

  CXml xml;
  if (!xml.Parse((const char *)(const Byte *)_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;

  UInt64 totalPackSize = 0;
  unsigned numMainFiles = 0;
  
  FOR_VECTOR (i, _files)
  {
    const CFile &file = _files[i];
    file.UpdateTotalPackSize(totalPackSize);
    if (file.Name == "Payload" || file.Name == "Content")
    {
      _mainSubfile = i;
      numMainFiles++;
    }
    else if (file.Name == "PackageInfo")
      _is_pkg = true;
  }

  if (numMainFiles > 1)
    _mainSubfile = -1;
  
  _phySize = _dataStartPos + totalPackSize;

  return S_OK;
}
Пример #18
0
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
    Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
{
  COM_TRY_BEGIN
  bool allFilesMode = (numItems == (UInt32)-1);

  if (allFilesMode)
    numItems = m_Database.NewFormat ? 1:
      (m_Database.LowLevel ?
      m_Database.Items.Size():
      m_Database.Indices.Size());
  if (numItems == 0)
    return S_OK;
  bool testMode = (testModeSpec != 0);

  UInt64 currentTotalSize = 0;

  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
  UInt32 i;

  CLocalProgress *lps = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> progress = lps;
  lps->Init(extractCallback, false);

  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
  CMyComPtr<ISequentialInStream> inStream(streamSpec);
  streamSpec->SetStream(m_Stream);

  if (m_Database.LowLevel)
  {
    UInt64 currentItemSize = 0;
    UInt64 totalSize = 0;
    if (m_Database.NewFormat)
      totalSize = m_Database.NewFormatString.Length();
    else
      for (i = 0; i < numItems; i++)
        totalSize += m_Database.Items[allFilesMode ? i : indices[i]].Size;
    extractCallback->SetTotal(totalSize);
    
    for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
    {
      currentItemSize = 0;
      lps->InSize = currentTotalSize; // Change it
      lps->OutSize = currentTotalSize;

      RINOK(lps->SetCur());
      CMyComPtr<ISequentialOutStream> realOutStream;
      Int32 askMode= testMode ?
          NExtract::NAskMode::kTest :
          NExtract::NAskMode::kExtract;
      Int32 index = allFilesMode ? i : indices[i];
      RINOK(extractCallback->GetStream(index, &realOutStream, askMode));

      if (m_Database.NewFormat)
      {
        if (index != 0)
          return E_FAIL;
        if (!testMode && !realOutStream)
          continue;
        if (!testMode)
        {
          UInt32 size = m_Database.NewFormatString.Length();
          RINOK(WriteStream(realOutStream, (const char *)m_Database.NewFormatString, size));
        }
        RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
        continue;
      }
      const CItem &item = m_Database.Items[index];
      
      currentItemSize = item.Size;
      
      if (!testMode && !realOutStream)
        continue;
      RINOK(extractCallback->PrepareOperation(askMode));
      if (item.Section != 0)
      {
        RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
        continue;
      }

      if (testMode)
      {
        RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
        continue;
      }
      
      RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL));
      streamSpec->Init(item.Size);
      
      RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
      realOutStream.Release();
      RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
          NExtract::NOperationResult::kOK:
          NExtract::NOperationResult::kDataError));
    }
    return S_OK;
  }
  
  UInt64 lastFolderIndex = ((UInt64)0 - 1);
  for (i = 0; i < numItems; i++)
  {
    UInt32 index = allFilesMode ? i : indices[i];
    int entryIndex = m_Database.Indices[index];
    const CItem &item = m_Database.Items[entryIndex];
    UInt64 sectionIndex = item.Section;
    if (item.IsDir() || item.Size == 0)
      continue;
    if (sectionIndex == 0)
    {
      currentTotalSize += item.Size;
      continue;
    }
    const CSectionInfo &section = m_Database.Sections[(int)item.Section];
    if (section.IsLzx())
    {
      const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo;
      UInt64 folderIndex = m_Database.GetFolder(index);
      if (lastFolderIndex == folderIndex)
        folderIndex++;
      lastFolderIndex = m_Database.GetLastFolder(index);
      for (; folderIndex <= lastFolderIndex; folderIndex++)
        currentTotalSize += lzxInfo.GetFolderSize();
    }
  }

  RINOK(extractCallback->SetTotal(currentTotalSize));

  NCompress::NLzx::CDecoder *lzxDecoderSpec = 0;
  CMyComPtr<ICompressCoder> lzxDecoder;
  CChmFolderOutStream *chmFolderOutStream = 0;
  CMyComPtr<ISequentialOutStream> outStream;

  currentTotalSize = 0;

  CRecordVector<bool> extractStatuses;
  for (i = 0; i < numItems;)
  {
    RINOK(extractCallback->SetCompleted(&currentTotalSize));
    UInt32 index = allFilesMode ? i : indices[i];
    i++;
    int entryIndex = m_Database.Indices[index];
    const CItem &item = m_Database.Items[entryIndex];
    UInt64 sectionIndex = item.Section;
    Int32 askMode= testMode ?
        NExtract::NAskMode::kTest :
        NExtract::NAskMode::kExtract;
    if (item.IsDir())
    {
      CMyComPtr<ISequentialOutStream> realOutStream;
      RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
      RINOK(extractCallback->PrepareOperation(askMode));
      realOutStream.Release();
      RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
      continue;
    }

    lps->InSize = currentTotalSize; // Change it
    lps->OutSize = currentTotalSize;

    if (item.Size == 0 || sectionIndex == 0)
    {
      CMyComPtr<ISequentialOutStream> realOutStream;
      RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
      if (!testMode && !realOutStream)
        continue;
      RINOK(extractCallback->PrepareOperation(askMode));
      Int32 opRes = NExtract::NOperationResult::kOK;
      if (!testMode && item.Size != 0)
      {
        RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL));
        streamSpec->Init(item.Size);
        RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
        if (copyCoderSpec->TotalSize != item.Size)
          opRes = NExtract::NOperationResult::kDataError;
      }
      realOutStream.Release();
      RINOK(extractCallback->SetOperationResult(opRes));
      currentTotalSize += item.Size;
      continue;
    }
  
    const CSectionInfo &section = m_Database.Sections[(int)sectionIndex];

    if (!section.IsLzx())
    {
      CMyComPtr<ISequentialOutStream> realOutStream;
      RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
      if (!testMode && !realOutStream)
        continue;
      RINOK(extractCallback->PrepareOperation(askMode));
      RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
      continue;
    }

    const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo;

    if (chmFolderOutStream == 0)
    {
      chmFolderOutStream = new CChmFolderOutStream;
      outStream = chmFolderOutStream;
    }

    chmFolderOutStream->Init(&m_Database, extractCallback, testMode);

    if (lzxDecoderSpec == NULL)
    {
      lzxDecoderSpec = new NCompress::NLzx::CDecoder;
      lzxDecoder = lzxDecoderSpec;
    }

    UInt64 folderIndex = m_Database.GetFolder(index);

    UInt64 compressedPos = m_Database.ContentOffset + section.Offset;
    UInt32 numDictBits = lzxInfo.GetNumDictBits();
    RINOK(lzxDecoderSpec->SetParams(numDictBits));

    const CItem *lastItem = &item;
    extractStatuses.Clear();
    extractStatuses.Add(true);

    for (;; folderIndex++)
    {
      RINOK(extractCallback->SetCompleted(&currentTotalSize));

      UInt64 startPos = lzxInfo.GetFolderPos(folderIndex);
      UInt64 finishPos = lastItem->Offset + lastItem->Size;
      UInt64 limitFolderIndex = lzxInfo.GetFolder(finishPos);

      lastFolderIndex = m_Database.GetLastFolder(index);
      UInt64 folderSize = lzxInfo.GetFolderSize();
      UInt64 unPackSize = folderSize;
      if (extractStatuses.IsEmpty())
        chmFolderOutStream->m_StartIndex = index + 1;
      else
        chmFolderOutStream->m_StartIndex = index;
      if (limitFolderIndex == folderIndex)
      {
        for (; i < numItems; i++)
        {
          UInt32 nextIndex = allFilesMode ? i : indices[i];
          int entryIndex = m_Database.Indices[nextIndex];
          const CItem &nextItem = m_Database.Items[entryIndex];
          if (nextItem.Section != sectionIndex)
            break;
          UInt64 nextFolderIndex = m_Database.GetFolder(nextIndex);
          if (nextFolderIndex != folderIndex)
            break;
          for (index++; index < nextIndex; index++)
            extractStatuses.Add(false);
          extractStatuses.Add(true);
          index = nextIndex;
          lastItem = &nextItem;
          if (nextItem.Size != 0)
            finishPos = nextItem.Offset + nextItem.Size;
          lastFolderIndex = m_Database.GetLastFolder(index);
        }
      }
      unPackSize = MyMin(finishPos - startPos, unPackSize);

      chmFolderOutStream->m_FolderSize = folderSize;
      chmFolderOutStream->m_PosInFolder = 0;
      chmFolderOutStream->m_PosInSection = startPos;
      chmFolderOutStream->m_ExtractStatuses = &extractStatuses;
      chmFolderOutStream->m_NumFiles = extractStatuses.Size();
      chmFolderOutStream->m_CurrentIndex = 0;
      try
      {
        UInt64 startBlock = lzxInfo.GetBlockIndexFromFolderIndex(folderIndex);
        const CResetTable &rt = lzxInfo.ResetTable;
        UInt32 numBlocks = (UInt32)rt.GetNumBlocks(unPackSize);
        for (UInt32 b = 0; b < numBlocks; b++)
        {
          UInt64 completedSize = currentTotalSize + chmFolderOutStream->m_PosInSection - startPos;
          RINOK(extractCallback->SetCompleted(&completedSize));
          UInt64 bCur = startBlock + b;
          if (bCur >= rt.ResetOffsets.Size())
            return E_FAIL;
          UInt64 offset = rt.ResetOffsets[(int)bCur];
          UInt64 compressedSize;
          rt.GetCompressedSizeOfBlock(bCur, compressedSize);
          UInt64 rem = finishPos - chmFolderOutStream->m_PosInSection;
          if (rem > rt.BlockSize)
            rem = rt.BlockSize;
          RINOK(m_Stream->Seek(compressedPos + offset, STREAM_SEEK_SET, NULL));
          streamSpec->SetStream(m_Stream);
          streamSpec->Init(compressedSize);
          lzxDecoderSpec->SetKeepHistory(b > 0);
          HRESULT res = lzxDecoder->Code(inStream, outStream, NULL, &rem, NULL);
          if (res != S_OK)
          {
            if (res != S_FALSE)
              return res;
            throw 1;
          }
        }
      }
      catch(...)
      {
        RINOK(chmFolderOutStream->FlushCorrupted(unPackSize));
      }
      currentTotalSize += folderSize;
      if (folderIndex == lastFolderIndex)
        break;
      extractStatuses.Clear();
    }
  }
  return S_OK;
  COM_TRY_END
}
Пример #19
0
int main2(int n, const char *args[])
{
  fprintf(stderr, "\nLZMA 4.27 Copyright (c) 1999-2005 Igor Pavlov  2005-08-07\n");

  if (n == 1)
  {
    PrintHelp();
    return 0;
  }

  if (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4)
  {
    fprintf(stderr, "Unsupported base types. Edit Common/Types.h and recompile");
    return 1;
  }   

  UStringVector commandStrings;
  WriteArgumentsToStringList(n, args, commandStrings);
  CParser parser(kNumSwitches);
  try
  {
    parser.ParseStrings(kSwitchForms, commandStrings);
  }
  catch(...) 
  {
    IncorrectCommand();
  }

  if(parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
  {
    PrintHelp();
    return 0;
  }
  const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;

  int paramIndex = 0;
  if (paramIndex >= nonSwitchStrings.Size())
    IncorrectCommand();
  const UString &command = nonSwitchStrings[paramIndex++]; 

  bool dictionaryIsDefined = false;
  UInt32 dictionary = 1 << 21;
  if(parser[NKey::kDictionary].ThereIs)
  {
    UInt32 dicLog;
    if (!GetNumber(parser[NKey::kDictionary].PostStrings[0], dicLog))
      IncorrectCommand();
    dictionary = 1 << dicLog;
    dictionaryIsDefined = true;
  }
  UString mf = L"BT4";
  if (parser[NKey::kMatchFinder].ThereIs)
    mf = parser[NKey::kMatchFinder].PostStrings[0];

  if (command.CompareNoCase(L"b") == 0)
  {
    const UInt32 kNumDefaultItereations = 10;
    UInt32 numIterations = kNumDefaultItereations;
    {
      if (paramIndex < nonSwitchStrings.Size())
        if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations))
          numIterations = kNumDefaultItereations;
    }
    return LzmaBenchmark(stderr, numIterations, dictionary, 
        mf.CompareNoCase(L"BT4") == 0);
  }

  bool encodeMode = false;
  if (command.CompareNoCase(L"e") == 0)
    encodeMode = true;
  else if (command.CompareNoCase(L"d") == 0)
    encodeMode = false;
  else
    IncorrectCommand();

  bool stdInMode = parser[NKey::kStdIn].ThereIs;
  bool stdOutMode = parser[NKey::kStdOut].ThereIs;

  CMyComPtr<ISequentialInStream> inStream;
  CInFileStream *inStreamSpec = 0;
  if (stdInMode)
  {
    inStream = new CStdInFileStream;
    MY_SET_BINARY_MODE(stdin);
  }
  else
  {
    if (paramIndex >= nonSwitchStrings.Size())
      IncorrectCommand();
    const UString &inputName = nonSwitchStrings[paramIndex++]; 
    inStreamSpec = new CInFileStream;
    inStream = inStreamSpec;
    if (!inStreamSpec->Open(GetSystemString(inputName)))
    {
      fprintf(stderr, "\nError: can not open input file %s\n", 
          (const char *)GetOemString(inputName));
      return 1;
    }
  }

  CMyComPtr<ISequentialOutStream> outStream;
  if (stdOutMode)
  {
    outStream = new CStdOutFileStream;
    MY_SET_BINARY_MODE(stdout);
  }
  else
  {
    if (paramIndex >= nonSwitchStrings.Size())
      IncorrectCommand();
    const UString &outputName = nonSwitchStrings[paramIndex++]; 
    COutFileStream *outStreamSpec = new COutFileStream;
    outStream = outStreamSpec;
    if (!outStreamSpec->Create(GetSystemString(outputName), true))
    {
      fprintf(stderr, "\nError: can not open output file %s\n", 
        (const char *)GetOemString(outputName));
      return 1;
    }
  }

  if (parser[NKey::kFilter86].ThereIs)
  {
    // -f86 switch is for x86 filtered mode: BCJ + LZMA.
    if (parser[NKey::kEOS].ThereIs || stdInMode)
      throw "Can not use stdin in this mode";
    UInt64 fileSize;
    inStreamSpec->File.GetLength(fileSize);
    if (fileSize > 0xF0000000)
      throw "File is too big";
    UInt32 inSize = (UInt32)fileSize;
    Byte *inBuffer = 0;
    if (inSize != 0)
    {
      inBuffer = (Byte *)MyAlloc((size_t)inSize); 
      if (inBuffer == 0)
        throw kCantAllocate;
    }
    
    UInt32 processedSize;
    if (inStream->Read(inBuffer, (UInt32)inSize, &processedSize) != S_OK)
      throw "Can not read";
    if ((UInt32)inSize != processedSize)
      throw "Read size error";

    Byte *outBuffer = 0;
    size_t outSizeProcessed;
    if (encodeMode)
    {
      // we allocate 105% of original size for output buffer
      size_t outSize = (size_t)fileSize / 20 * 21 + (1 << 16);
      if (outSize != 0)
      {
        outBuffer = (Byte *)MyAlloc((size_t)outSize); 
        if (outBuffer == 0)
          throw kCantAllocate;
      }
      if (!dictionaryIsDefined)
        dictionary = 1 << 23;
      int res = LzmaRamEncode(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, 
          dictionary, SZ_FILTER_AUTO);
      if (res != 0)
      {
        fprintf(stderr, "\nEncoder error = %d\n", (int)res);
        return 1;
      }
    }
    else
    {
      size_t outSize;
      if (LzmaRamGetUncompressedSize(inBuffer, inSize, &outSize) != 0)
        throw "data error";
      if (outSize != 0)
      {
        outBuffer = (Byte *)MyAlloc(outSize); 
        if (outBuffer == 0)
          throw kCantAllocate;
      }
      int res = LzmaRamDecompress(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, malloc, free);
      if (res != 0)
        throw "LzmaDecoder error";
    }
    if (outStream->Write(outBuffer, (UInt32)outSizeProcessed, &processedSize) != S_OK)
      throw "Can not write";
    MyFree(outBuffer);
    MyFree(inBuffer);
    return 0;
  }


  UInt64 fileSize;
  if (encodeMode)
  {
    NCompress::NLZMA::CEncoder *encoderSpec = 
      new NCompress::NLZMA::CEncoder;
    CMyComPtr<ICompressCoder> encoder = encoderSpec;

    if (!dictionaryIsDefined)
      dictionary = 1 << 23;

    UInt32 posStateBits = 2;
    UInt32 litContextBits = 3; // for normal files
    // UInt32 litContextBits = 0; // for 32-bit data
    UInt32 litPosBits = 0;
    // UInt32 litPosBits = 2; // for 32-bit data
    UInt32 algorithm = 2;
    UInt32 numFastBytes = 128;

    bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
 
    if(parser[NKey::kMode].ThereIs)
      if (!GetNumber(parser[NKey::kMode].PostStrings[0], algorithm))
        IncorrectCommand();

    if(parser[NKey::kFastBytes].ThereIs)
      if (!GetNumber(parser[NKey::kFastBytes].PostStrings[0], numFastBytes))
        IncorrectCommand();
    if(parser[NKey::kLitContext].ThereIs)
      if (!GetNumber(parser[NKey::kLitContext].PostStrings[0], litContextBits))
        IncorrectCommand();
    if(parser[NKey::kLitPos].ThereIs)
      if (!GetNumber(parser[NKey::kLitPos].PostStrings[0], litPosBits))
        IncorrectCommand();
    if(parser[NKey::kPosBits].ThereIs)
      if (!GetNumber(parser[NKey::kPosBits].PostStrings[0], posStateBits))
        IncorrectCommand();

    PROPID propIDs[] = 
    {
      NCoderPropID::kDictionarySize,
      NCoderPropID::kPosStateBits,
      NCoderPropID::kLitContextBits,
      NCoderPropID::kLitPosBits,
      NCoderPropID::kAlgorithm,
      NCoderPropID::kNumFastBytes,
      NCoderPropID::kMatchFinder,
      NCoderPropID::kEndMarker
    };
    const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
    /*
    NWindows::NCOM::CPropVariant properties[kNumProps];
    properties[0] = UInt32(dictionary);
    properties[1] = UInt32(posStateBits);
    properties[2] = UInt32(litContextBits);
   
    properties[3] = UInt32(litPosBits);
    properties[4] = UInt32(algorithm);
    properties[5] = UInt32(numFastBytes);
    properties[6] = mf;
    properties[7] = eos;
    */
    PROPVARIANT properties[kNumProps];
    for (int p = 0; p < 6; p++)
      properties[p].vt = VT_UI4;
    properties[0].ulVal = UInt32(dictionary);
    properties[1].ulVal = UInt32(posStateBits);
    properties[2].ulVal = UInt32(litContextBits);
    properties[3].ulVal = UInt32(litPosBits);
    properties[4].ulVal = UInt32(algorithm);
    properties[5].ulVal = UInt32(numFastBytes);
    
    properties[6].vt = VT_BSTR;
    properties[6].bstrVal = (BSTR)(const wchar_t *)mf;

    properties[7].vt = VT_BOOL;
    properties[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;

    if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
      IncorrectCommand();
    encoderSpec->WriteCoderProperties(outStream);

    if (eos || stdInMode)
      fileSize = (UInt64)(Int64)-1;
    else
      inStreamSpec->File.GetLength(fileSize);

    for (int i = 0; i < 8; i++)
    {
      Byte b = Byte(fileSize >> (8 * i));
      if (outStream->Write(&b, sizeof(b), 0) != S_OK)
      {
        fprintf(stderr, "Write error");
        return 1;
      }
    }
    HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
    if (result == E_OUTOFMEMORY)
    {
      fprintf(stderr, "\nError: Can not allocate memory\n");
      return 1;
    }   
    else if (result != S_OK)
    {
      fprintf(stderr, "\nEncoder error = %X\n", (unsigned int)result);
      return 1;
    }   
  }
  else
  {
Пример #20
0
static HRESULT CopyStreams(ISequentialInStream *inStream, ISequentialOutStream *outStream)
{
  CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
  return copyCoder->Code(inStream, outStream, NULL, NULL, NULL);
}
Пример #21
0
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
    const CObjectVector<NArchive::NTar::CItemEx> &inputItems,
    const CObjectVector<CUpdateItem> &updateItems,
    UINT codePage,
    IArchiveUpdateCallback *updateCallback)
{
  COutArchive outArchive;
  outArchive.Create(outStream);
  outArchive.Pos = 0;

  CMyComPtr<IOutStream> outSeekStream;
  outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream);

  UInt64 complexity = 0;

  unsigned i;
  for (i = 0; i < updateItems.Size(); i++)
  {
    const CUpdateItem &ui = updateItems[i];
    if (ui.NewData)
      complexity += ui.Size;
    else
      complexity += inputItems[ui.IndexInArchive].GetFullSize();
  }

  RINOK(updateCallback->SetTotal(complexity));

  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

  CLocalProgress *lps = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> progress = lps;
  lps->Init(updateCallback, true);

  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
  CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
  streamSpec->SetStream(inStream);

  complexity = 0;

  for (i = 0; i < updateItems.Size(); i++)
  {
    lps->InSize = lps->OutSize = complexity;
    RINOK(lps->SetCur());

    const CUpdateItem &ui = updateItems[i];
    CItem item;
    if (ui.NewProps)
    {
      item.Mode = ui.Mode;
      item.Name = ui.Name;
      item.User = ui.User;
      item.Group = ui.Group;
      if (ui.IsDir)
      {
        item.LinkFlag = NFileHeader::NLinkFlag::kDirectory;
        item.PackSize = 0;
      }
      else
      {
        item.LinkFlag = NFileHeader::NLinkFlag::kNormal;
        item.PackSize = ui.Size;
      }
      item.MTime = ui.MTime;
      item.DeviceMajorDefined = false;
      item.DeviceMinorDefined = false;
      item.UID = 0;
      item.GID = 0;
      memcpy(item.Magic, NFileHeader::NMagic::kUsTar_00, 8);
    }
    else
      item = inputItems[ui.IndexInArchive];

    AString symLink;
    if (ui.NewData || ui.NewProps)
    {
      RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink, codePage, true));
      if (!symLink.IsEmpty())
      {
        item.LinkFlag = NFileHeader::NLinkFlag::kSymLink;
        item.LinkName = symLink;
      }
    }

    if (ui.NewData)
    {
      item.SparseBlocks.Clear();
      item.PackSize = ui.Size;
      item.Size = ui.Size;
      if (ui.Size == (UInt64)(Int64)-1)
        return E_INVALIDARG;

      CMyComPtr<ISequentialInStream> fileInStream;

      bool needWrite = true;
      if (!symLink.IsEmpty())
      {
        item.PackSize = 0;
        item.Size = 0;
      }
      else
      {
        HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
        if (res == S_FALSE)
          needWrite = false;
        else
        {
          RINOK(res);

          if (fileInStream)
          {
            CMyComPtr<IStreamGetProps> getProps;
            fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
            if (getProps)
            {
              FILETIME mTime;
              UInt64 size2;
              if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK)
              {
                item.PackSize = size2;
                item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);;
              }
            }
          }
          {
            AString hardLink;
            RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, codePage, true));
            if (!hardLink.IsEmpty())
            {
              item.LinkFlag = NFileHeader::NLinkFlag::kHardLink;
              item.LinkName = hardLink;
              item.PackSize = 0;
              item.Size = 0;
              fileInStream.Release();
            }
          }
        }
      }

      if (needWrite)
      {
        UInt64 fileHeaderStartPos = outArchive.Pos;
        RINOK(outArchive.WriteHeader(item));
        if (fileInStream)
        {
          RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress));
          outArchive.Pos += copyCoderSpec->TotalSize;
          if (copyCoderSpec->TotalSize != item.PackSize)
          {
            if (!outSeekStream)
              return E_FAIL;
            UInt64 backOffset = outArchive.Pos - fileHeaderStartPos;
            RINOK(outSeekStream->Seek(-(Int64)backOffset, STREAM_SEEK_CUR, NULL));
            outArchive.Pos = fileHeaderStartPos;
            item.PackSize = copyCoderSpec->TotalSize;
            RINOK(outArchive.WriteHeader(item));
            RINOK(outSeekStream->Seek(item.PackSize, STREAM_SEEK_CUR, NULL));
            outArchive.Pos += item.PackSize;
          }
          RINOK(outArchive.FillDataResidual(item.PackSize));
        }
      }
      complexity += item.PackSize;
      RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
    }
    else
    {
      const CItemEx &existItem = inputItems[ui.IndexInArchive];
      UInt64 size;
      if (ui.NewProps)
      {
        // memcpy(item.Magic, NFileHeader::NMagic::kEmpty, 8);

        if (!symLink.IsEmpty())
        {
          item.PackSize = 0;
          item.Size = 0;
        }
        else
        {
          if (ui.IsDir == existItem.IsDir())
            item.LinkFlag = existItem.LinkFlag;

          item.SparseBlocks = existItem.SparseBlocks;
          item.Size = existItem.Size;
          item.PackSize = existItem.PackSize;
        }

        item.DeviceMajorDefined = existItem.DeviceMajorDefined;
        item.DeviceMinorDefined = existItem.DeviceMinorDefined;
        item.DeviceMajor = existItem.DeviceMajor;
        item.DeviceMinor = existItem.DeviceMinor;
        item.UID = existItem.UID;
        item.GID = existItem.GID;

        RINOK(outArchive.WriteHeader(item));
        RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL));
        size = existItem.PackSize;
      }
      else
      {
        RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL));
        size = existItem.GetFullSize();
      }
      streamSpec->Init(size);

      RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
      if (copyCoderSpec->TotalSize != size)
        return E_FAIL;
      outArchive.Pos += size;
      RINOK(outArchive.FillDataResidual(existItem.PackSize));
      complexity += size;
    }
  }
  lps->InSize = lps->OutSize = complexity;
  RINOK(lps->SetCur());
  return outArchive.WriteFinishHeader();
}
Пример #22
0
HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
{
  CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
  return copyCoder->Code(inStream, outStream, NULL, NULL, progress);
}
Пример #23
0
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
    Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
{
  COM_TRY_BEGIN
  bool allFilesMode = (numItems == (UInt32)(Int32)-1);
  if (allFilesMode)
    numItems = m_Database.Items.Size();
  if (numItems == 0)
    return S_OK;
  bool testMode = (testModeSpec != 0);
  UInt64 totalUnPacked = 0;

  UInt32 i;
  int lastFolder = -2;
  UInt64 lastFolderSize = 0;
  
  for (i = 0; i < numItems; i++)
  {
    unsigned index = allFilesMode ? i : indices[i];
    const CMvItem &mvItem = m_Database.Items[index];
    const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
    if (item.IsDir())
      continue;
    int folderIndex = m_Database.GetFolderIndex(&mvItem);
    if (folderIndex != lastFolder)
      totalUnPacked += lastFolderSize;
    lastFolder = folderIndex;
    lastFolderSize = item.GetEndOffset();
  }
  
  totalUnPacked += lastFolderSize;

  extractCallback->SetTotal(totalUnPacked);

  totalUnPacked = 0;

  UInt64 totalPacked = 0;

  CLocalProgress *lps = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> progress = lps;
  lps->Init(extractCallback, false);

  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

  NCompress::NDeflate::NDecoder::CCOMCoder *deflateDecoderSpec = NULL;
  CMyComPtr<ICompressCoder> deflateDecoder;

  NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL;
  CMyComPtr<ICompressCoder> lzxDecoder;

  NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL;
  CMyComPtr<ICompressCoder> quantumDecoder;

  CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream();
  CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec;
  if (!cabBlockInStreamSpec->Create())
    return E_OUTOFMEMORY;

  CRecordVector<bool> extractStatuses;
  
  for (i = 0; i < numItems;)
  {
    unsigned index = allFilesMode ? i : indices[i];

    const CMvItem &mvItem = m_Database.Items[index];
    const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
    unsigned itemIndex = mvItem.ItemIndex;
    const CItem &item = db.Items[itemIndex];

    i++;
    if (item.IsDir())
    {
      Int32 askMode = testMode ?
          NExtract::NAskMode::kTest :
          NExtract::NAskMode::kExtract;
      CMyComPtr<ISequentialOutStream> realOutStream;
      RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
      RINOK(extractCallback->PrepareOperation(askMode));
      realOutStream.Release();
      RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
      continue;
    }
    
    int folderIndex = m_Database.GetFolderIndex(&mvItem);
    
    if (folderIndex < 0)
    {
      // If we need previous archive
      Int32 askMode= testMode ?
          NExtract::NAskMode::kTest :
          NExtract::NAskMode::kExtract;
      CMyComPtr<ISequentialOutStream> realOutStream;
      RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
      RINOK(extractCallback->PrepareOperation(askMode));
      realOutStream.Release();
      RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError));
      continue;
    }
    
    unsigned startIndex2 = m_Database.FolderStartFileIndex[folderIndex];
    unsigned startIndex = startIndex2;
    extractStatuses.Clear();
    for (; startIndex < index; startIndex++)
      extractStatuses.Add(false);
    extractStatuses.Add(true);
    startIndex++;
    UInt64 curUnpack = item.GetEndOffset();
    
    for (; i < numItems; i++)
    {
      unsigned indexNext = allFilesMode ? i : indices[i];
      const CMvItem &mvItem = m_Database.Items[indexNext];
      const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
      if (item.IsDir())
        continue;
      int newFolderIndex = m_Database.GetFolderIndex(&mvItem);

      if (newFolderIndex != folderIndex)
        break;
      for (; startIndex < indexNext; startIndex++)
        extractStatuses.Add(false);
      extractStatuses.Add(true);
      startIndex++;
      curUnpack = item.GetEndOffset();
    }

    lps->OutSize = totalUnPacked;
    lps->InSize = totalPacked;
    RINOK(lps->SetCur());

    CFolderOutStream *cabFolderOutStream = new CFolderOutStream;
    CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream);

    const CFolder &folder = db.Folders[item.GetFolderIndex(db.Folders.Size())];

    cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2,
        curUnpack, extractCallback, testMode);

    cabBlockInStreamSpec->MsZip = false;
    HRESULT res = S_OK;
    
    switch (folder.GetMethod())
    {
      case NHeader::NMethod::kNone:
        break;
      case NHeader::NMethod::kMSZip:
        if (!deflateDecoder)
        {
          deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder;
          deflateDecoder = deflateDecoderSpec;
        }
        cabBlockInStreamSpec->MsZip = true;
        break;
      case NHeader::NMethod::kLZX:
        if (!lzxDecoder)
        {
          lzxDecoderSpec = new NCompress::NLzx::CDecoder;
          lzxDecoder = lzxDecoderSpec;
        }
        res = lzxDecoderSpec->SetParams(folder.MethodMinor);
        break;
      case NHeader::NMethod::kQuantum:
        if (!quantumDecoder)
        {
          quantumDecoderSpec = new NCompress::NQuantum::CDecoder;
          quantumDecoder = quantumDecoderSpec;
        }
        res = quantumDecoderSpec->SetParams(folder.MethodMinor);
        break;
      default:
        res = E_INVALIDARG;
        break;
    }

    if (res == E_INVALIDARG)
    {
      RINOK(cabFolderOutStream->Unsupported());
      totalUnPacked += curUnpack;
      continue;
    }
    RINOK(res);

    {
      unsigned volIndex = mvItem.VolumeIndex;
      int locFolderIndex = item.GetFolderIndex(db.Folders.Size());
      bool keepHistory = false;
      bool keepInputBuffer = false;
      
      for (UInt32 bl = 0; cabFolderOutStream->GetRemain() != 0;)
      {
        if (volIndex >= m_Database.Volumes.Size())
        {
          res = S_FALSE;
          break;
        }

        const CDatabaseEx &db = m_Database.Volumes[volIndex];
        const CFolder &folder = db.Folders[locFolderIndex];
        
        if (bl == 0)
        {
          cabBlockInStreamSpec->ReservedSize = db.ArcInfo.GetDataBlockReserveSize();
          RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL));
        }
        
        if (bl == folder.NumDataBlocks)
        {
          /*
            CFolder::NumDataBlocks (CFFOLDER::cCFData in CAB specification) is 16-bit.
            But there are some big CAB archives from MS that contain more
            than (0xFFFF) CFDATA blocks in folder.
            Old cab extracting software can show error (or ask next volume)
            but cab extracting library in new Windows ignores this error.
            15.00 : We also try to ignore such error, if archive is not multi-volume.
          */
          if (m_Database.Volumes.Size() > 1)
          {
            volIndex++;
            locFolderIndex = 0;
            bl = 0;
            continue;
          }
        }
        bl++;

        if (!keepInputBuffer)
          cabBlockInStreamSpec->InitForNewBlock();

        UInt32 packSize, unpackSize;
        res = cabBlockInStreamSpec->PreRead(db.Stream, packSize, unpackSize);
        if (res == S_FALSE)
          break;
        RINOK(res);
        keepInputBuffer = (unpackSize == 0);
        if (keepInputBuffer)
          continue;

        UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFolder();
        totalPacked += packSize;

        lps->OutSize = totalUnPacked2;
        lps->InSize = totalPacked;
        RINOK(lps->SetCur());

        UInt64 unpackRemain = cabFolderOutStream->GetRemain();

        const UInt32 kBlockSizeMax = (1 << 15);
        if (unpackRemain > kBlockSizeMax)
          unpackRemain = kBlockSizeMax;
        if (unpackRemain > unpackSize)
          unpackRemain = unpackSize;

        switch (folder.GetMethod())
        {
          case NHeader::NMethod::kNone:
            res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
            break;
          case NHeader::NMethod::kMSZip:
            deflateDecoderSpec->Set_KeepHistory(keepHistory);
            /* v9.31: now we follow MSZIP specification that requires to finish deflate stream at the end of each block.
               But PyCabArc can create CAB archives that doesn't have finish marker at the end of block.
               Cabarc probably ignores such errors in cab archives.
               Maybe we also should ignore that error?
               Or we should extract full file and show the warning? */
            deflateDecoderSpec->Set_NeedFinishInput(true);
            res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
            if (res == S_OK)
            {
              if (!deflateDecoderSpec->IsFinished())
                res = S_FALSE;
              if (!deflateDecoderSpec->IsFinalBlock())
                res = S_FALSE;
            }

            break;
          case NHeader::NMethod::kLZX:
            lzxDecoderSpec->SetKeepHistory(keepHistory);
            res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
            break;
          case NHeader::NMethod::kQuantum:
            quantumDecoderSpec->SetKeepHistory(keepHistory);
            res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
          break;
        }
      
        if (res != S_OK)
        {
          if (res != S_FALSE)
            RINOK(res);
          break;
        }
        
        keepHistory = true;
      }
      
      if (res == S_OK)
      {
        RINOK(cabFolderOutStream->WriteEmptyFiles());
      }
    }
    if (res != S_OK || cabFolderOutStream->GetRemain() != 0)
    {
      RINOK(cabFolderOutStream->FlushCorrupted());
    }
    totalUnPacked += curUnpack;
  }

  return S_OK;
  COM_TRY_END
}
Пример #24
0
int main2(int n, const char *args[])
{
  #ifdef _WIN32
  g_IsNT = IsItWindowsNT();
  #endif

  fprintf(stderr, "\nLZMA " MY_VERSION_COPYRIGHT_DATE "\n");

  if (n == 1)
  {
	PrintHelp();
	return 0;
  }

  bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4);
  if (unsupportedTypes)
  {
	fprintf(stderr, "Unsupported base types. Edit Common/Types.h and recompile");
	return 1;
  }   

  UStringVector commandStrings;
  WriteArgumentsToStringList(n, args, commandStrings);
  CParser parser(kNumSwitches);
  try
  {
	parser.ParseStrings(kSwitchForms, commandStrings);
  }
  catch(...) 
  {
	IncorrectCommand();
  }

  if(parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
  {
	PrintHelp();
	return 0;
  }
  const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;

  int paramIndex = 0;
  if (paramIndex >= nonSwitchStrings.Size())
	IncorrectCommand();
  const UString &command = nonSwitchStrings[paramIndex++]; 

  bool dictionaryIsDefined = false;
  UInt32 dictionary = (UInt32)-1;
  if(parser[NKey::kDictionary].ThereIs)
  {
	UInt32 dicLog;
	if (!GetNumber(parser[NKey::kDictionary].PostStrings[0], dicLog))
	  IncorrectCommand();
	dictionary = 1 << dicLog;
	dictionaryIsDefined = true;
  }
  UString mf = L"BT4";
  if (parser[NKey::kMatchFinder].ThereIs)
	mf = parser[NKey::kMatchFinder].PostStrings[0];

  UInt32 numThreads = (UInt32)-1;

  #ifdef COMPRESS_MF_MT
  if (parser[NKey::kMultiThread].ThereIs)
  {
	UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
	const UString &s = parser[NKey::kMultiThread].PostStrings[0];
	if (s.IsEmpty())
	  numThreads = numCPUs;
	else
	  if (!GetNumber(s, numThreads))
		IncorrectCommand();
  }
  #endif

  if (command.CompareNoCase(L"b") == 0)
  {
	const UInt32 kNumDefaultItereations = 1;
	UInt32 numIterations = kNumDefaultItereations;
	{
	  if (paramIndex < nonSwitchStrings.Size())
		if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations))
		  numIterations = kNumDefaultItereations;
	}
	return LzmaBenchCon(stderr, numIterations, numThreads, dictionary);
  }

  if (numThreads == (UInt32)-1)
	numThreads = 1;

  bool encodeMode = false;
  if (command.CompareNoCase(L"e") == 0)
	encodeMode = true;
  else if (command.CompareNoCase(L"d") == 0)
	encodeMode = false;
  else
	IncorrectCommand();

  bool stdInMode = parser[NKey::kStdIn].ThereIs;
  bool stdOutMode = parser[NKey::kStdOut].ThereIs;

  CMyComPtr<ISequentialInStream> inStream;
  CInFileStream *inStreamSpec = 0;
  if (stdInMode)
  {
	inStream = new CStdInFileStream;
	MY_SET_BINARY_MODE(stdin);
  }
  else
  {
	if (paramIndex >= nonSwitchStrings.Size())
	  IncorrectCommand();
	const UString &inputName = nonSwitchStrings[paramIndex++]; 
	inStreamSpec = new CInFileStream;
	inStream = inStreamSpec;
	if (!inStreamSpec->Open(GetSystemString(inputName)))
	{
	  fprintf(stderr, "\nError: can not open input file %s\n", 
		  (const char *)GetOemString(inputName));
	  return 1;
	}
  }

  CMyComPtr<ISequentialOutStream> outStream;
  COutFileStream *outStreamSpec = NULL;
  if (stdOutMode)
  {
	outStream = new CStdOutFileStream;
	MY_SET_BINARY_MODE(stdout);
  }
  else
  {
	if (paramIndex >= nonSwitchStrings.Size())
	  IncorrectCommand();
	const UString &outputName = nonSwitchStrings[paramIndex++]; 
	outStreamSpec = new COutFileStream;
	outStream = outStreamSpec;
	if (!outStreamSpec->Create(GetSystemString(outputName), true))
	{
	  fprintf(stderr, "\nError: can not open output file %s\n", 
		(const char *)GetOemString(outputName));
	  return 1;
	}
  }

  if (parser[NKey::kFilter86].ThereIs)
  {
	// -f86 switch is for x86 filtered mode: BCJ + LZMA.
	if (parser[NKey::kEOS].ThereIs || stdInMode)
	  throw "Can not use stdin in this mode";
	UInt64 fileSize;
	inStreamSpec->File.GetLength(fileSize);
	if (fileSize > 0xF0000000)
	  throw "File is too big";
	UInt32 inSize = (UInt32)fileSize;
	Byte *inBuffer = 0;
	if (inSize != 0)
	{
	  inBuffer = (Byte *)MyAlloc((size_t)inSize); 
	  if (inBuffer == 0)
		throw kCantAllocate;
	}
	
	UInt32 processedSize;
	if (ReadStream(inStream, inBuffer, (UInt32)inSize, &processedSize) != S_OK)
	  throw "Can not read";
	if ((UInt32)inSize != processedSize)
	  throw "Read size error";

	Byte *outBuffer = 0;
	size_t outSizeProcessed;
	if (encodeMode)
	{
	  // we allocate 105% of original size for output buffer
	  size_t outSize = (size_t)fileSize / 20 * 21 + (1 << 16);
	  if (outSize != 0)
	  {
		outBuffer = (Byte *)MyAlloc((size_t)outSize); 
		if (outBuffer == 0)
		  throw kCantAllocate;
	  }
	  if (!dictionaryIsDefined)
		dictionary = 1 << 23;
	  int res = LzmaRamEncode(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, 
		  dictionary, parser[NKey::kFilter86].PostCharIndex == 0 ? SZ_FILTER_YES : SZ_FILTER_AUTO);
	  if (res != 0)
	  {
		fprintf(stderr, "\nEncoder error = %d\n", (int)res);
		return 1;
	  }
	}
	else
	{
	  size_t outSize;
	  if (LzmaRamGetUncompressedSize(inBuffer, inSize, &outSize) != 0)
		throw "data error";
	  if (outSize != 0)
	  {
		outBuffer = (Byte *)MyAlloc(outSize); 
		if (outBuffer == 0)
		  throw kCantAllocate;
	  }
	  int res = LzmaRamDecompress(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, malloc, free);
	  if (res != 0)
		throw "LzmaDecoder error";
	}
	if (WriteStream(outStream, outBuffer, (UInt32)outSizeProcessed, &processedSize) != S_OK)
	  throw kWriteError;
	MyFree(outBuffer);
	MyFree(inBuffer);
	return 0;
  }


  UInt64 fileSize;
  if (encodeMode)
  {
	NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder;
	CMyComPtr<ICompressCoder> encoder = encoderSpec;

	if (!dictionaryIsDefined)
	  dictionary = 1 << 23;

	UInt32 posStateBits = 2;
	UInt32 litContextBits = 3; // for normal files
	// UInt32 litContextBits = 0; // for 32-bit data
	UInt32 litPosBits = 0;
	// UInt32 litPosBits = 2; // for 32-bit data
	UInt32 algorithm = 1;
	UInt32 numFastBytes = 128;
	UInt32 matchFinderCycles = 16 + numFastBytes / 2;
	bool matchFinderCyclesDefined = false;

	bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
 
	if(parser[NKey::kMode].ThereIs)
	  if (!GetNumber(parser[NKey::kMode].PostStrings[0], algorithm))
		IncorrectCommand();

	if(parser[NKey::kFastBytes].ThereIs)
	  if (!GetNumber(parser[NKey::kFastBytes].PostStrings[0], numFastBytes))
		IncorrectCommand();
	matchFinderCyclesDefined = parser[NKey::kMatchFinderCycles].ThereIs;
	if (matchFinderCyclesDefined)
	  if (!GetNumber(parser[NKey::kMatchFinderCycles].PostStrings[0], matchFinderCycles))
		IncorrectCommand();
	if(parser[NKey::kLitContext].ThereIs)
	  if (!GetNumber(parser[NKey::kLitContext].PostStrings[0], litContextBits))
		IncorrectCommand();
	if(parser[NKey::kLitPos].ThereIs)
	  if (!GetNumber(parser[NKey::kLitPos].PostStrings[0], litPosBits))
		IncorrectCommand();
	if(parser[NKey::kPosBits].ThereIs)
	  if (!GetNumber(parser[NKey::kPosBits].PostStrings[0], posStateBits))
		IncorrectCommand();

	PROPID propIDs[] = 
	{
	  NCoderPropID::kDictionarySize,
	  NCoderPropID::kPosStateBits,
	  NCoderPropID::kLitContextBits,
	  NCoderPropID::kLitPosBits,
	  NCoderPropID::kAlgorithm,
	  NCoderPropID::kNumFastBytes,
	  NCoderPropID::kMatchFinder,
	  NCoderPropID::kEndMarker,
	  NCoderPropID::kNumThreads,
	  NCoderPropID::kMatchFinderCycles,
	};
	const int kNumPropsMax = sizeof(propIDs) / sizeof(propIDs[0]);

	PROPVARIANT properties[kNumPropsMax];
	for (int p = 0; p < 6; p++)
	  properties[p].vt = VT_UI4;

	properties[0].ulVal = (UInt32)dictionary;
	properties[1].ulVal = (UInt32)posStateBits;
	properties[2].ulVal = (UInt32)litContextBits;
	properties[3].ulVal = (UInt32)litPosBits;
	properties[4].ulVal = (UInt32)algorithm;
	properties[5].ulVal = (UInt32)numFastBytes;

	properties[6].vt = VT_BSTR;
	properties[6].bstrVal = (BSTR)(const wchar_t *)mf;

	properties[7].vt = VT_BOOL;
	properties[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;

	properties[8].vt = VT_UI4;
	properties[8].ulVal = (UInt32)numThreads;

	// it must be last in property list
	properties[9].vt = VT_UI4;
	properties[9].ulVal = (UInt32)matchFinderCycles;

	int numProps = kNumPropsMax;
	if (!matchFinderCyclesDefined)
	  numProps--;

	if (encoderSpec->SetCoderProperties(propIDs, properties, numProps) != S_OK)
	  IncorrectCommand();
	encoderSpec->WriteCoderProperties(outStream);

	if (eos || stdInMode)
	  fileSize = (UInt64)(Int64)-1;
	else
	  inStreamSpec->File.GetLength(fileSize);

	for (int i = 0; i < 8; i++)
	{
	  Byte b = Byte(fileSize >> (8 * i));
	  if (outStream->Write(&b, 1, 0) != S_OK)
	  {
		fprintf(stderr, kWriteError);
		return 1;
	  }
	}
	HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
	if (result == E_OUTOFMEMORY)
	{
	  fprintf(stderr, "\nError: Can not allocate memory\n");
	  return 1;
	}   
	else if (result != S_OK)
	{
	  fprintf(stderr, "\nEncoder error = %X\n", (unsigned int)result);
	  return 1;
	}   
  }
  else
  {
Пример #25
0
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
    const CObjectVector<NArchive::NTar::CItemEx> &inputItems,
    const CObjectVector<CUpdateItem> &updateItems,
    IArchiveUpdateCallback *updateCallback)
{
  COutArchive outArchive;
  outArchive.Create(outStream);

  UInt64 complexity = 0;

  int i;
  for(i = 0; i < updateItems.Size(); i++)
  {
    const CUpdateItem &ui = updateItems[i];
    if (ui.NewData)
      complexity += ui.Size;
    else
      complexity += inputItems[ui.IndexInArchive].GetFullSize();
  }

  RINOK(updateCallback->SetTotal(complexity));

  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

  CLocalProgress *lps = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> progress = lps;
  lps->Init(updateCallback, true);

  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
  CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
  streamSpec->SetStream(inStream);

  complexity = 0;

  for(i = 0; i < updateItems.Size(); i++)
  {
    lps->InSize = lps->OutSize = complexity;
    RINOK(lps->SetCur());

    const CUpdateItem &ui = updateItems[i];
    CItem item;
    if (ui.NewProperties)
    {
      item.Mode = 0777;
      item.Name = (ui.Name);
      if (ui.IsDir)
      {
        item.LinkFlag = NFileHeader::NLinkFlag::kDirectory;
        item.Size = 0;
      }
      else
      {
        item.LinkFlag = NFileHeader::NLinkFlag::kNormal;
        item.Size = ui.Size;
      }
      item.MTime = ui.Time;
      item.DeviceMajorDefined = false;
      item.DeviceMinorDefined = false;
      item.UID = 0;
      item.GID = 0;
      memmove(item.Magic, NFileHeader::NMagic::kEmpty, 8);
    }
    else
    {
      const CItemEx &existItemInfo = inputItems[ui.IndexInArchive];
      item = existItemInfo;
    }
    if (ui.NewData)
    {
      item.Size = ui.Size;
      if (item.Size == UInt64(Int64(-1)))
        return E_INVALIDARG;
    }
    else
    {
      const CItemEx &existItemInfo = inputItems[ui.IndexInArchive];
      item.Size = existItemInfo.Size;
    }
  
    if (ui.NewData)
    {
      CMyComPtr<ISequentialInStream> fileInStream;
      HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
      if (res != S_FALSE)
      {
        RINOK(res);
        RINOK(outArchive.WriteHeader(item));
        if (!ui.IsDir)
        {
          RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress));
          if (copyCoderSpec->TotalSize != item.Size)
            return E_FAIL;
          RINOK(outArchive.FillDataResidual(item.Size));
        }
      }
      complexity += ui.Size;
      RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
    }
    else
    {
      const CItemEx &existItemInfo = inputItems[ui.IndexInArchive];
      UInt64 size;
      if (ui.NewProperties)
      {
        RINOK(outArchive.WriteHeader(item));
        RINOK(inStream->Seek(existItemInfo.GetDataPosition(), STREAM_SEEK_SET, NULL));
        size = existItemInfo.Size;
      }
      else
      {
        RINOK(inStream->Seek(existItemInfo.HeaderPosition, STREAM_SEEK_SET, NULL));
        size = existItemInfo.GetFullSize();
      }
      streamSpec->Init(size);

      RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
      if (copyCoderSpec->TotalSize != size)
        return E_FAIL;
      RINOK(outArchive.FillDataResidual(existItemInfo.Size));
      complexity += size;
    }
  }
  return outArchive.WriteFinishHeader();
}