⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rarhandler.cpp

📁 7-Zip 3.11的源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
        }
        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;
    for(int 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;

  CMyComPtr<ICompressCoder> rar20CryptoDecoder;
  CMyComPtr<ICompressCoder> 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;
    
    if (item.IsEncrypted())
    {
      CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
      if (item.UnPackVersion >= 29)
      {
        if (!rar29CryptoDecoder)
        {
          rar29CryptoDecoder = new NCrypto::NRar29::CDecoder();
          // RINOK(rar29CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar29Decoder));
        }
        CMyComPtr<ICompressSetDecoderProperties> cryptoProperties;
        RINOK(rar29CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties, 
            &cryptoProperties));
        CSequentialInStreamImp *inStreamSpec = new CSequentialInStreamImp;
        CMyComPtr<ISequentialInStream> inStreamProperties(inStreamSpec);
        inStreamSpec->Init(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0);
        RINOK(cryptoProperties->SetDecoderProperties(inStreamProperties));
        RINOK(rar29CryptoDecoder.QueryInterface(IID_ICryptoSetPassword, 
            &cryptoSetPassword));
      }
      else if (item.UnPackVersion >= 20)
      {
        if (!rar20CryptoDecoder)
        {
          rar20CryptoDecoder = new NCrypto::NRar20::CDecoder();
          // RINOK(rar20CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar20Decoder));
        }
        RINOK(rar20CryptoDecoder.QueryInterface(IID_ICryptoSetPassword, 
            &cryptoSetPassword));
      }
      else
      {
        outStream.Release();
        RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
        continue;
      }

      if (!getTextPassword)
        extractCallback.QueryInterface(IID_ICryptoGetTextPassword, 
          &getTextPassword);
      if (getTextPassword)
      {
        CMyComBSTR password;
        RINOK(getTextPassword->CryptoGetTextPassword(&password));
        if (item.UnPackVersion >= 29)
        {
          RINOK(cryptoSetPassword->CryptoSetPassword(
            (const BYTE *)(const wchar_t *)password, 
            password.Length() * sizeof(wchar_t)));
        }
        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));
      }
    }
    switch(item.Method)
    {
      case '0':
      {
        if(copyCoderSpec == NULL)
        {
          copyCoderSpec = new NCompress::CCopyCoder;
          copyCoder = copyCoderSpec;
        }
        
        if (item.IsEncrypted())
        {
          {
            if (!mixerCoder || !mixerCoderStoreMethod || 
                item.UnPackVersion != mixerCryptoVersion)
            {
              mixerCoder.Release();
              mixerCoderSpec = new CCoderMixer;
              mixerCoder = mixerCoderSpec;
              if (item.UnPackVersion >= 29)
                mixerCoderSpec->AddCoder(rar29CryptoDecoder);
              else
                mixerCoderSpec->AddCoder(rar20CryptoDecoder);
              mixerCoderSpec->AddCoder(copyCoder);
              mixerCoderSpec->FinishAddingCoders();
              mixerCoderStoreMethod = true;
              mixerCryptoVersion = item.UnPackVersion;
            }
            mixerCoderSpec->ReInit();
            mixerCoderSpec->SetCoderInfo(0, &packSize, &item.UnPackSize);
            mixerCoderSpec->SetCoderInfo(1, &item.UnPackSize, &item.UnPackSize);
            mixerCoderSpec->SetProgressCoderIndex(1);
            
            RINOK(mixerCoder->Code(folderInStream, outStream,
              NULL, NULL, compressProgress));
          }
        }
        else
        {
          RINOK(copyCoder->Code(folderInStream, outStream,
              NULL, NULL, compressProgress));
        }
        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<ICompressSetDecoderProperties> compressSetDecoderProperties;
        RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties, 
            &compressSetDecoderProperties));
        
        BYTE isSolid = (
          // item.IsSolid() 
          IsSolid(index)
          || 
          item.IsSplitBefore())
            ? 1: 0;

        CSequentialInStreamImp *inStreamSpec = new CSequentialInStreamImp;
        CMyComPtr<ISequentialInStream> inStreamProperties(inStreamSpec);
        inStreamSpec->Init(&isSolid, 1);
        RINOK(compressSetDecoderProperties->SetDecoderProperties(inStreamProperties));
          
        HRESULT result;
        if (item.IsEncrypted())
        {
          if (!mixerCoder || mixerCoderStoreMethod)
          {
            mixerCoder.Release();
            mixerCoderSpec = new CCoderMixer;
            mixerCoder = mixerCoderSpec;
            if (item.UnPackVersion >= 29)
              mixerCoderSpec->AddCoder(rar29CryptoDecoder);
            else
              mixerCoderSpec->AddCoder(rar20CryptoDecoder);
            mixerCoderSpec->AddCoder(decoder);
            mixerCoderSpec->FinishAddingCoders();
            mixerCoderStoreMethod = false;
          }
          mixerCoderSpec->ReInit();
          mixerCoderSpec->SetCoderInfo(1, &packSize, 
              &item.UnPackSize);
          mixerCoderSpec->SetProgressCoderIndex(1);
          result = mixerCoder->Code(folderInStream, outStream, 
              NULL, NULL, compressProgress);
        }
        else
        {
          result = decoder->Code(folderInStream, outStream,
              &packSize, &item.UnPackSize, compressProgress);
        }
        if (result == S_FALSE)
        {
          outStream.Release();
          RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kDataError));
          continue;
        }
        if (result != S_OK)
          return result;
        break;
      }
      default:
        outStream.Release();
        RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
        continue;
    }

    /*
    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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -