7zdecode.cpp

来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 444 行

CPP
444
字号
// 7zDecode.cpp#include "StdAfx.h"#include "7zDecode.h"#include "../../IPassword.h"#include "../../Common/LockedStream.h"#include "../../Common/StreamObjects.h"#include "../../Common/ProgressUtils.h"#include "../../Common/LimitedStreams.h"#include "../Common/FilterCoder.h"#include "7zMethods.h"#ifdef COMPRESS_LZMA#include "../../Compress/LZMA/LZMADecoder.h"static NArchive::N7z::CMethodID k_LZMA = { { 0x3, 0x1, 0x1 }, 3 };#endif#ifdef COMPRESS_PPMD#include "../../Compress/PPMD/PPMDDecoder.h"static NArchive::N7z::CMethodID k_PPMD = { { 0x3, 0x4, 0x1 }, 3 };#endif#ifdef COMPRESS_BCJ_X86#include "../../Compress/Branch/x86.h"static NArchive::N7z::CMethodID k_BCJ_X86 = { { 0x3, 0x3, 0x1, 0x3 }, 4 };#endif#ifdef COMPRESS_BCJ2#include "../../Compress/Branch/x86_2.h"static NArchive::N7z::CMethodID k_BCJ2 = { { 0x3, 0x3, 0x1, 0x1B }, 4 };#endif#ifdef COMPRESS_DEFLATE#ifndef COMPRESS_DEFLATE_DECODER#define COMPRESS_DEFLATE_DECODER#endif#endif#ifdef COMPRESS_DEFLATE_DECODER#include "../../Compress/Deflate/DeflateDecoder.h"static NArchive::N7z::CMethodID k_Deflate = { { 0x4, 0x1, 0x8 }, 3 };#endif#ifdef COMPRESS_BZIP2#ifndef COMPRESS_BZIP2_DECODER#define COMPRESS_BZIP2_DECODER#endif#endif#ifdef COMPRESS_BZIP2_DECODER#include "../../Compress/BZip2/BZip2Decoder.h"static NArchive::N7z::CMethodID k_BZip2 = { { 0x4, 0x2, 0x2 }, 3 };#endif#ifdef COMPRESS_COPY#include "../../Compress/Copy/CopyCoder.h"static NArchive::N7z::CMethodID k_Copy = { { 0x0 }, 1 };#endif#ifdef CRYPTO_7ZAES#include "../../Crypto/7zAES/7zAES.h"static NArchive::N7z::CMethodID k_7zAES = { { 0x6, 0xF1, 0x07, 0x01 }, 4 };#endifnamespace NArchive {namespace N7z {static void ConvertFolderItemInfoToBindInfo(const CFolder &folder,    CBindInfoEx &bindInfo){  bindInfo.Clear();  int i;  for (i = 0; i < folder.BindPairs.Size(); i++)  {    NCoderMixer2::CBindPair bindPair;    bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex;    bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex;    bindInfo.BindPairs.Add(bindPair);  }  UInt32 outStreamIndex = 0;  for (i = 0; i < folder.Coders.Size(); i++)  {    NCoderMixer2::CCoderStreamsInfo coderStreamsInfo;    const CCoderInfo &coderInfo = folder.Coders[i];    coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams;    coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams;    bindInfo.Coders.Add(coderStreamsInfo);    const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front();    bindInfo.CoderMethodIDs.Add(altCoderInfo.MethodID);    for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++)      if (folder.FindBindPairForOutStream(outStreamIndex) < 0)        bindInfo.OutStreams.Add(outStreamIndex);  }  for (i = 0; i < folder.PackStreams.Size(); i++)    bindInfo.InStreams.Add((UInt32)folder.PackStreams[i]);}static bool AreCodersEqual(const NCoderMixer2::CCoderStreamsInfo &a1,     const NCoderMixer2::CCoderStreamsInfo &a2){  return (a1.NumInStreams == a2.NumInStreams) &&    (a1.NumOutStreams == a2.NumOutStreams);}static bool AreBindPairsEqual(const NCoderMixer2::CBindPair &a1, const NCoderMixer2::CBindPair &a2){  return (a1.InIndex == a2.InIndex) &&    (a1.OutIndex == a2.OutIndex);}static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2){  if (a1.Coders.Size() != a2.Coders.Size())    return false;  int i;  for (i = 0; i < a1.Coders.Size(); i++)    if (!AreCodersEqual(a1.Coders[i], a2.Coders[i]))      return false;  if (a1.BindPairs.Size() != a2.BindPairs.Size())    return false;  for (i = 0; i < a1.BindPairs.Size(); i++)    if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i]))      return false;  for (i = 0; i < a1.CoderMethodIDs.Size(); i++)    if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i])      return false;  if (a1.InStreams.Size() != a2.InStreams.Size())    return false;  if (a1.OutStreams.Size() != a2.OutStreams.Size())    return false;  return true;}CDecoder::CDecoder(bool multiThread){  #ifndef _ST_MODE  multiThread = true;  #endif  _multiThread = multiThread;  _bindInfoExPrevIsDefinded = false;  #ifndef EXCLUDE_COM  LoadMethodMap();  #endif}HRESULT CDecoder::Decode(IInStream *inStream,    UInt64 startPos,    const UInt64 *packSizes,    const CFolder &folderInfo,     ISequentialOutStream *outStream,    ICompressProgressInfo *compressProgress    #ifndef _NO_CRYPTO    , ICryptoGetTextPassword *getTextPassword    #endif    #ifdef COMPRESS_MT    , bool mtMode, UInt32 numThreads    #endif    ){  CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;    CLockedInStream lockedInStream;  lockedInStream.Init(inStream);    for (int j = 0; j < folderInfo.PackStreams.Size(); j++)  {    CLockedSequentialInStreamImp *lockedStreamImpSpec = new         CLockedSequentialInStreamImp;    CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec;    lockedStreamImpSpec->Init(&lockedInStream, startPos);    startPos += packSizes[j];        CLimitedSequentialInStream *streamSpec = new         CLimitedSequentialInStream;    CMyComPtr<ISequentialInStream> inStream = streamSpec;    streamSpec->Init(lockedStreamImp, packSizes[j]);    inStreams.Add(inStream);  }    int numCoders = folderInfo.Coders.Size();    CBindInfoEx bindInfo;  ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo);  bool createNewCoders;  if (!_bindInfoExPrevIsDefinded)    createNewCoders = true;  else    createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev);  if (createNewCoders)  {    int i;    _decoders.Clear();    // _decoders2.Clear();        _mixerCoder.Release();    if (_multiThread)    {      _mixerCoderMTSpec = new NCoderMixer2::CCoderMixer2MT;      _mixerCoder = _mixerCoderMTSpec;      _mixerCoderCommon = _mixerCoderMTSpec;    }    else    {      #ifdef _ST_MODE      _mixerCoderSTSpec = new NCoderMixer2::CCoderMixer2ST;      _mixerCoder = _mixerCoderSTSpec;      _mixerCoderCommon = _mixerCoderSTSpec;      #endif    }    _mixerCoderCommon->SetBindInfo(bindInfo);        for (i = 0; i < numCoders; i++)    {      const CCoderInfo &coderInfo = folderInfo.Coders[i];      const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front();      #ifndef EXCLUDE_COM      CMethodInfo methodInfo;      if (!GetMethodInfo(altCoderInfo.MethodID, methodInfo))         return E_NOTIMPL;      #endif      if (coderInfo.IsSimpleCoder())      {        CMyComPtr<ICompressCoder> decoder;        CMyComPtr<ICompressFilter> filter;        #ifdef COMPRESS_LZMA        if (altCoderInfo.MethodID == k_LZMA)          decoder = new NCompress::NLZMA::CDecoder;        #endif        #ifdef COMPRESS_PPMD        if (altCoderInfo.MethodID == k_PPMD)          decoder = new NCompress::NPPMD::CDecoder;        #endif        #ifdef COMPRESS_BCJ_X86        if (altCoderInfo.MethodID == k_BCJ_X86)          filter = new CBCJ_x86_Decoder;        #endif        #ifdef COMPRESS_DEFLATE_DECODER        if (altCoderInfo.MethodID == k_Deflate)          decoder = new NCompress::NDeflate::NDecoder::CCOMCoder;        #endif        #ifdef COMPRESS_BZIP2_DECODER        if (altCoderInfo.MethodID == k_BZip2)          decoder = new NCompress::NBZip2::CDecoder;        #endif        #ifdef COMPRESS_COPY        if (altCoderInfo.MethodID == k_Copy)          decoder = new NCompress::CCopyCoder;        #endif        #ifdef CRYPTO_7ZAES        if (altCoderInfo.MethodID == k_7zAES)          filter = new NCrypto::NSevenZ::CDecoder;        #endif        if (filter)        {          CFilterCoder *coderSpec = new CFilterCoder;          decoder = coderSpec;          coderSpec->Filter = filter;        }        #ifndef EXCLUDE_COM        if (decoder == 0)        {          RINOK(_libraries.CreateCoderSpec(methodInfo.FilePath,               methodInfo.Decoder, &decoder));        }        #endif        if (decoder == 0)          return E_NOTIMPL;        _decoders.Add((IUnknown *)decoder);        if (_multiThread)          _mixerCoderMTSpec->AddCoder(decoder);        #ifdef _ST_MODE        else          _mixerCoderSTSpec->AddCoder(decoder, false);        #endif      }      else      {        CMyComPtr<ICompressCoder2> decoder;        #ifdef COMPRESS_BCJ2        if (altCoderInfo.MethodID == k_BCJ2)          decoder = new CBCJ2_x86_Decoder;        #endif        #ifndef EXCLUDE_COM        if (decoder == 0)        {          RINOK(_libraries.CreateCoder2(methodInfo.FilePath,               methodInfo.Decoder, &decoder));        }        #endif        if (decoder == 0)          return E_NOTIMPL;        _decoders.Add((IUnknown *)decoder);        if (_multiThread)          _mixerCoderMTSpec->AddCoder2(decoder);        #ifdef _ST_MODE        else          _mixerCoderSTSpec->AddCoder2(decoder, false);        #endif      }    }    _bindInfoExPrev = bindInfo;    _bindInfoExPrevIsDefinded = true;  }  int i;  _mixerCoderCommon->ReInit();    UInt32 packStreamIndex = 0, unPackStreamIndex = 0;  UInt32 coderIndex = 0;  // UInt32 coder2Index = 0;    for (i = 0; i < numCoders; i++)  {    const CCoderInfo &coderInfo = folderInfo.Coders[i];    const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front();    CMyComPtr<IUnknown> &decoder = _decoders[coderIndex];        {      CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;      HRESULT result = decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);      if (setDecoderProperties)      {        const CByteBuffer &properties = altCoderInfo.Properties;        size_t size = properties.GetCapacity();        if (size > 0xFFFFFFFF)          return E_NOTIMPL;        if (size > 0)        {          RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)properties, (UInt32)size));        }      }    }    #ifdef COMPRESS_MT    if (mtMode)    {      CMyComPtr<ICompressSetCoderMt> setCoderMt;      decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);      if (setCoderMt)      {        RINOK(setCoderMt->SetNumberOfThreads(numThreads));      }    }    #endif    #ifndef _NO_CRYPTO    {      CMyComPtr<ICryptoSetPassword> cryptoSetPassword;      HRESULT result = decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);      if (cryptoSetPassword)      {        if (getTextPassword == 0)          return E_FAIL;        CMyComBSTR password;        RINOK(getTextPassword->CryptoGetTextPassword(&password));        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));      }    }    #endif    coderIndex++;        UInt32 numInStreams = (UInt32)coderInfo.NumInStreams;    UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams;    CRecordVector<const UInt64 *> packSizesPointers;    CRecordVector<const UInt64 *> unPackSizesPointers;    packSizesPointers.Reserve(numInStreams);    unPackSizesPointers.Reserve(numOutStreams);    UInt32 j;    for (j = 0; j < numOutStreams; j++, unPackStreamIndex++)      unPackSizesPointers.Add(&folderInfo.UnPackSizes[unPackStreamIndex]);        for (j = 0; j < numInStreams; j++, packStreamIndex++)    {      int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex);      if (bindPairIndex >= 0)        packSizesPointers.Add(        &folderInfo.UnPackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]);      else      {        int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex);        if (index < 0)          return E_FAIL;        packSizesPointers.Add(&packSizes[index]);      }    }        _mixerCoderCommon->SetCoderInfo(i,         &packSizesPointers.Front(),         &unPackSizesPointers.Front());  }  UInt32 mainCoder, temp;  bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp);  if (_multiThread)    _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder);  /*  else    _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);;  */    if (numCoders == 0)    return 0;  CRecordVector<ISequentialInStream *> inStreamPointers;  inStreamPointers.Reserve(inStreams.Size());  for (i = 0; i < inStreams.Size(); i++)    inStreamPointers.Add(inStreams[i]);  ISequentialOutStream *outStreamPointer = outStream;  return _mixerCoder->Code(&inStreamPointers.Front(), NULL,     inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress);}}}

⌨️ 快捷键说明

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