cabhandler.cpp

来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 816 行 · 第 1/2 页

CPP
816
字号
  for(;m_CurrentIndex < m_ExtractStatuses->Size(); m_CurrentIndex++)  {    const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];    const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];    UInt64 fileSize = item.Size;    if (fileSize != 0)      return S_OK;    HRESULT result = OpenFile();    m_RealOutStream.Release();    RINOK(result);    RINOK(m_ExtractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));  }  return S_OK;}// This is Write functionHRESULT CCabFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK){  UInt32 realProcessed = 0;  if (processedSize != NULL)   *processedSize = 0;  while(size != 0)  {    if (m_FileIsOpen)    {      UInt32 numBytesToWrite = (UInt32)MyMin(m_RemainFileSize, (UInt64)(size));      HRESULT res = S_OK;      if (numBytesToWrite > 0)      {        if (!isOK)          m_IsOk = false;        if (m_RealOutStream)        {          UInt32 processedSizeLocal = 0;          res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal);          numBytesToWrite = processedSizeLocal;        }      }      realProcessed += numBytesToWrite;      if (processedSize != NULL)        *processedSize = realProcessed;      data = (const void *)((const Byte *)data + numBytesToWrite);      size -= numBytesToWrite;      m_RemainFileSize -= numBytesToWrite;      m_PosInFolder += numBytesToWrite;      if (res != S_OK)        return res;      if (m_RemainFileSize == 0)      {        m_RealOutStream.Release();        RINOK(m_ExtractCallback->SetOperationResult(          m_IsOk ?             NArchive::NExtract::NOperationResult::kOK:            NArchive::NExtract::NOperationResult::kDataError));        m_FileIsOpen = false;      }      if (realProcessed > 0)        break; // with this break this function works as Write-Part    }    else    {      if (m_CurrentIndex >= m_ExtractStatuses->Size())        return E_FAIL;      const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];      const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];      m_RemainFileSize = item.Size;      UInt32 fileOffset = item.Offset;      if (fileOffset < m_PosInFolder)        return E_FAIL;      if (fileOffset > m_PosInFolder)      {        UInt32 numBytesToWrite = (UInt32)MyMin((UInt64)fileOffset - m_PosInFolder, UInt64(size));        realProcessed += numBytesToWrite;        if (processedSize != NULL)          *processedSize = realProcessed;        data = (const void *)((const Byte *)data + numBytesToWrite);        size -= numBytesToWrite;        m_PosInFolder += numBytesToWrite;      }      if (fileOffset == m_PosInFolder)      {        RINOK(OpenFile());        m_FileIsOpen = true;        m_CurrentIndex++;        m_IsOk = true;      }    }  }  return WriteEmptyFiles();}STDMETHODIMP CCabFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize){  return Write2(data, size, processedSize, true);}HRESULT CCabFolderOutStream::FlushCorrupted(){  const UInt32 kBufferSize = (1 << 10);  Byte buffer[kBufferSize];  for (int i = 0; i < kBufferSize; i++)    buffer[i] = 0;  while(true)  {    UInt64 remain = GetRemain();    if (remain == 0)      return S_OK;    UInt32 size = (UInt32)MyMin(remain, (UInt64)kBufferSize);    UInt32 processedSizeLocal = 0;    RINOK(Write2(buffer, size, &processedSizeLocal, false));  }}HRESULT CCabFolderOutStream::Unsupported(){  while(m_CurrentIndex < m_ExtractStatuses->Size())  {    HRESULT result = OpenFile();    if (result != S_FALSE && result != S_OK)      return result;    m_RealOutStream.Release();    RINOK(m_ExtractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));    m_CurrentIndex++;  }  return S_OK;}STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,    Int32 _aTestMode, 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 = (_aTestMode != 0);  UInt64 totalUnPacked = 0;  int lastIndex = 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.IsDirectory())      continue;    int folderIndex = m_Database.GetFolderIndex(&mvItem);    if (folderIndex != lastFolder)      totalUnPacked += lastFolderSize;    lastFolder = folderIndex;    lastFolderSize = item.GetEndOffset();  }  totalUnPacked += lastFolderSize;  extractCallback->SetTotal(totalUnPacked);  totalUnPacked = 0;  NCompress::CCopyCoder *copyCoderSpec = NULL;  CMyComPtr<ICompressCoder> copyCoder;  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.IsDirectory())    {      Int32 askMode= testMode ?           NArchive::NExtract::NAskMode::kTest :          NArchive::NExtract::NAskMode::kExtract;      CMyComPtr<ISequentialOutStream> realOutStream;      RINOK(extractCallback->GetStream(index, &realOutStream, askMode));      RINOK(extractCallback->PrepareOperation(askMode));      realOutStream.Release();      RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));      continue;    }    int folderIndex = m_Database.GetFolderIndex(&mvItem);    if (folderIndex < 0)    {      // If we need previous archive      Int32 askMode= testMode ?           NArchive::NExtract::NAskMode::kTest :          NArchive::NExtract::NAskMode::kExtract;      CMyComPtr<ISequentialOutStream> realOutStream;      RINOK(extractCallback->GetStream(index, &realOutStream, askMode));      RINOK(extractCallback->PrepareOperation(askMode));      realOutStream.Release();      RINOK(extractCallback->SetOperationResult(NArchive::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.IsDirectory())        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();    }    RINOK(extractCallback->SetCompleted(&totalUnPacked));        CCabFolderOutStream *cabFolderOutStream = new CCabFolderOutStream;    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:        if(copyCoderSpec == NULL)        {          copyCoderSpec = new NCompress::CCopyCoder;          copyCoder = copyCoderSpec;        }        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();        RINOK(extractCallback->SetCompleted(&totalUnPacked2));        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, cabBlockInStreamSpec->GetAlign());            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::GetNumberOfItems(UInt32 *numItems){  COM_TRY_BEGIN  *numItems = m_Database.Items.Size();  return S_OK;  COM_TRY_END}}}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?