rarhandler.cpp

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

CPP
943
字号
      if (_archives.IsEmpty())        archive.GetArchiveInfo(_archiveInfo);           CItemEx item;      while(true)      {        HRESULT result = archive.GetNextItem(item, getTextPassword);        if (result == S_FALSE)          break;        RINOK(result);        if (item.IgnoreItem())          continue;        bool needAdd = true;        if (item.IsSplitBefore())        {          if (!_refItems.IsEmpty())          {            CRefItem &refItem = _refItems.Back();            refItem.NumItems++;            needAdd = false;          }        }        if (needAdd)        {          CRefItem refItem;          refItem.ItemIndex = _items.Size();          refItem.NumItems = 1;          refItem.VolumeIndex = _archives.Size();          _refItems.Add(refItem);        }        _items.Add(item);        if (openArchiveCallback != NULL)        {          UInt64 numFiles = _items.Size();          RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));        }      }      _archives.Add(archive);    }  }  catch(...)  {    return S_FALSE;  }  return S_OK;  COM_TRY_END}STDMETHODIMP CHandler::Close(){  COM_TRY_BEGIN  _refItems.Clear();  _items.Clear();  _archives.Clear();  return S_OK;  COM_TRY_END}struct CMethodItem{  Byte RarUnPackVersion;  CMyComPtr<ICompressCoder> Coder;};STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,    Int32 _aTestMode, IArchiveExtractCallback *_anExtractCallback){  COM_TRY_BEGIN  CMyComPtr<ICryptoGetTextPassword> getTextPassword;  bool testMode = (_aTestMode != 0);  CMyComPtr<IArchiveExtractCallback> extractCallback = _anExtractCallback;  UInt64 censoredTotalUnPacked = 0,         // censoredTotalPacked = 0,        importantTotalUnPacked = 0;         // importantTotalPacked = 0;  bool allFilesMode = (numItems == UInt32(-1));  if (allFilesMode)    numItems = _refItems.Size();  if(numItems == 0)    return S_OK;  int lastIndex = 0;  CRecordVector<int> importantIndexes;  CRecordVector<bool> extractStatuses;  for(UInt32 t = 0; t < numItems; t++)  {    int index = allFilesMode ? t : indices[t];    const CRefItem &refItem = _refItems[index];    const CItemEx &item = _items[refItem.ItemIndex];    censoredTotalUnPacked += item.UnPackSize;    // censoredTotalPacked += item.PackSize;    int j;    for(j = lastIndex; j <= index; j++)      // if(!_items[_refItems[j].ItemIndex].IsSolid())      if(!IsSolid(j))        lastIndex = j;    for(j = lastIndex; j <= index; j++)    {      const CRefItem &refItem = _refItems[j];      const CItemEx &item = _items[refItem.ItemIndex];      // const CItemEx &item = _items[j];      importantTotalUnPacked += item.UnPackSize;      // importantTotalPacked += item.PackSize;      importantIndexes.Add(j);      extractStatuses.Add(j == index);    }    lastIndex = index + 1;  }  extractCallback->SetTotal(importantTotalUnPacked);  UInt64 currentImportantTotalUnPacked = 0;  UInt64 currentImportantTotalPacked = 0;  UInt64 currentUnPackSize, currentPackSize;  /*  CSysString path = GetCodecsFolderPrefix() + TEXT("Rar29.dll");  TCHAR compressLibPath[MAX_PATH + 64];  if (!GetCompressFolderPrefix(compressLibPath))    return ::GetLastError();  lstrcat(compressLibPath, TEXT("Rar29.dll"));  */  N7z::LoadMethodMap();  CCoderLibraries libraries;  CObjectVector<CMethodItem> methodItems;  /*  CCoderLibrary compressLib;  CMyComPtr<ICompressCoder> decoder15;  CMyComPtr<ICompressCoder> decoder20;  CMyComPtr<ICompressCoder> decoder29;  */  NCompress::CCopyCoder *copyCoderSpec = NULL;  CMyComPtr<ICompressCoder> copyCoder;  // CCoderMixer *mixerCoderSpec;  // CMyComPtr<ICompressCoder> mixerCoder;  // bool mixerCoderStoreMethod;  // int mixerCryptoVersion;  CFilterCoder *filterStreamSpec = new CFilterCoder;  CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec;  NCrypto::NRar20::CDecoder *rar20CryptoDecoderSpec;  CMyComPtr<ICompressFilter> rar20CryptoDecoder;  NCrypto::NRar29::CDecoder *rar29CryptoDecoderSpec;  CMyComPtr<ICompressFilter> rar29CryptoDecoder;  CFolderInStream *folderInStreamSpec = NULL;  CMyComPtr<ISequentialInStream> folderInStream;  for(int i = 0; i < importantIndexes.Size(); i++,       currentImportantTotalUnPacked += currentUnPackSize,      currentImportantTotalPacked += currentPackSize)  {    RINOK(extractCallback->SetCompleted(        &currentImportantTotalUnPacked));    CMyComPtr<ISequentialOutStream> realOutStream;    Int32 askMode;    if(extractStatuses[i])      askMode = testMode ? NArchive::NExtract::NAskMode::kTest :          NArchive::NExtract::NAskMode::kExtract;    else      askMode = NArchive::NExtract::NAskMode::kSkip;    UInt32 index = importantIndexes[i];    const CRefItem &refItem = _refItems[index];    const CItemEx &item = _items[refItem.ItemIndex];    currentUnPackSize = item.UnPackSize;    currentPackSize = GetPackSize(index);    if(item.IgnoreItem())      continue;    RINOK(extractCallback->GetStream(index, &realOutStream, askMode));    if(item.IsDirectory())    {      RINOK(extractCallback->PrepareOperation(askMode));      RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));      continue;    }    bool mustBeProcessedAnywhere = false;    if(i < importantIndexes.Size() - 1)    {      // const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]];      // const CItemEx &nextItemInfo = _items[nextRefItem.ItemIndex];      // mustBeProcessedAnywhere = nextItemInfo.IsSolid();      mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]);    }        if (!mustBeProcessedAnywhere && !testMode && !realOutStream)      continue;        if (!realOutStream && !testMode)      askMode = NArchive::NExtract::NAskMode::kSkip;    RINOK(extractCallback->PrepareOperation(askMode));    COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;    CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);    outStreamSpec->Init(realOutStream);    realOutStream.Release();        UInt64 packedPos = currentImportantTotalPacked;    UInt64 unpackedPos = currentImportantTotalUnPacked;    /*    for (int partIndex = 0; partIndex < 1; partIndex++)    {    CMyComPtr<ISequentialInStream> inStream;    // item redefinition    const CItemEx &item = _items[refItem.ItemIndex + partIndex];    NArchive::NRar::CInArchive &archive = _archives[refItem.VolumeIndex + partIndex];    inStream.Attach(archive.CreateLimitedStream(item.GetDataPosition(),      item.PackSize));    */    if (!folderInStream)    {      folderInStreamSpec = new CFolderInStream;      folderInStream = folderInStreamSpec;    }    folderInStreamSpec->Init(&_archives, &_items, refItem);        CLocalProgress *localProgressSpec = new CLocalProgress;    CMyComPtr<ICompressProgressInfo> progress = localProgressSpec;    localProgressSpec->Init(extractCallback, false);        CLocalCompressProgressInfo *localCompressProgressSpec =         new CLocalCompressProgressInfo;    CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec;    localCompressProgressSpec->Init(progress,       &packedPos,      &unpackedPos);    UInt64 packSize = currentPackSize;    // packedPos += item.PackSize;    // unpackedPos += 0;        CMyComPtr<ISequentialInStream> inStream;    if (item.IsEncrypted())    {      CMyComPtr<ICryptoSetPassword> cryptoSetPassword;      if (item.UnPackVersion >= 29)      {        if (!rar29CryptoDecoder)        {          rar29CryptoDecoderSpec = new NCrypto::NRar29::CDecoder;          rar29CryptoDecoder = rar29CryptoDecoderSpec;          // RINOK(rar29CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar29Decoder));        }        rar29CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);        CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties;        RINOK(rar29CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,             &cryptoProperties));        RINOK(cryptoProperties->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0));        filterStreamSpec->Filter = rar29CryptoDecoder;      }      else if (item.UnPackVersion >= 20)      {        if (!rar20CryptoDecoder)        {          rar20CryptoDecoderSpec = new NCrypto::NRar20::CDecoder;          rar20CryptoDecoder = rar20CryptoDecoderSpec;          // RINOK(rar20CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar20Decoder));        }        filterStreamSpec->Filter = rar20CryptoDecoder;      }      else      {        outStream.Release();        RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));        continue;      }      RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword,           &cryptoSetPassword));      if (!getTextPassword)        extractCallback.QueryInterface(IID_ICryptoGetTextPassword,           &getTextPassword);      if (getTextPassword)      {        CMyComBSTR password;        RINOK(getTextPassword->CryptoGetTextPassword(&password));        if (item.UnPackVersion >= 29)        {          CByteBuffer buffer;          UString unicodePassword(password);          const UInt32 sizeInBytes = unicodePassword.Length() * 2;          buffer.SetCapacity(sizeInBytes);          for (int i = 0; i < unicodePassword.Length(); i++)          {            wchar_t c = unicodePassword[i];            ((Byte *)buffer)[i * 2] = (Byte)c;            ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);          }          RINOK(cryptoSetPassword->CryptoSetPassword(            (const Byte *)buffer, sizeInBytes));        }        else        {          AString oemPassword = UnicodeStringToMultiByte(            (const wchar_t *)password, CP_OEMCP);          RINOK(cryptoSetPassword->CryptoSetPassword(            (const Byte *)(const char *)oemPassword, oemPassword.Length()));        }      }      else      {        RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));      }      filterStreamSpec->SetInStream(folderInStream);      inStream = filterStream;    }    else    {      inStream = folderInStream;    }    CMyComPtr<ICompressCoder> commonCoder;    switch(item.Method)    {      case '0':      {        if(copyCoderSpec == NULL)        {          copyCoderSpec = new NCompress::CCopyCoder;          copyCoder = copyCoderSpec;        }        commonCoder = copyCoder;        break;      }      case '1':      case '2':      case '3':      case '4':      case '5':      {        /*        if (item.UnPackVersion >= 29)        {          outStream.Release();          RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));          continue;        }        */        int m;        for (m = 0; m < methodItems.Size(); m++)          if (methodItems[m].RarUnPackVersion == item.UnPackVersion)            break;        if (m == methodItems.Size())        {          CMethodItem mi;          mi.RarUnPackVersion = item.UnPackVersion;          N7z::CMethodID methodID = { { 0x04, 0x03 } , 3 };          Byte myID;          if (item.UnPackVersion < 20)            myID = 1;          else if (item.UnPackVersion < 29)            myID = 2;          else            myID = 3;          methodID.ID[2] = myID;          N7z::CMethodInfo methodInfo;          if (!N7z::GetMethodInfo(methodID, methodInfo))          {            RINOK(extractCallback->SetOperationResult(              NArchive::NExtract::NOperationResult::kUnSupportedMethod));            continue;          }          RINOK(libraries.CreateCoder(methodInfo.FilePath,             methodInfo.Decoder, &mi.Coder));          m = methodItems.Add(mi);        }        CMyComPtr<ICompressCoder> decoder = methodItems[m].Coder;        CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties;        RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties2,             &compressSetDecoderProperties));                Byte isSolid =           (IsSolid(index) || item.IsSplitBefore()) ? 1: 0;        RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1));                  commonCoder = decoder;        break;      }      default:        outStream.Release();        RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));        continue;    }    HRESULT result = commonCoder->Code(inStream, outStream,      &packSize, &item.UnPackSize, compressProgress);    if (item.IsEncrypted())      filterStreamSpec->ReleaseInStream();    if (result == S_FALSE)    {      outStream.Release();      RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kDataError));      continue;    }    if (result != S_OK)      return result;    /*    if (refItem.NumItems == 1 &&         !item.IsSplitBefore() && !item.IsSplitAfter())    */    {      const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];      bool crcOK = outStreamSpec->GetCRC() == lastItem.FileCRC;      outStream.Release();      RINOK(extractCallback->SetOperationResult(crcOK ? NArchive::NExtract::NOperationResult::kOK:          NArchive::NExtract::NOperationResult::kCRCError));    }    /*    else    {      bool crcOK = true;      for (int partIndex = 0; partIndex < refItem.NumItems; partIndex++)      {        const CItemEx &item = _items[refItem.ItemIndex + partIndex];        if (item.FileCRC != folderInStreamSpec->CRCs[partIndex])        {          crcOK = false;          break;        }      }      RINOK(extractCallback->SetOperationResult(crcOK ? NArchive::NExtract::NOperationResult::kOK:          NArchive::NExtract::NOperationResult::kCRCError));    }    */  }  return S_OK;  COM_TRY_END}/*STDMETHODIMP CHandler::ExtractAllItems(Int32 testMode,      IArchiveExtractCallback *extractCallback){  COM_TRY_BEGIN  CRecordVector<UInt32> indices;  indices.Reserve(_refItems.Size());  for(int i = 0; i < _refItems.Size(); i++)    indices.Add(i);  return Extract(&indices.Front(), _refItems.Size(), testMode, extractCallback);  COM_TRY_END}*/}}

⌨️ 快捷键说明

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