7zhandlerout.cpp

来自「著名的7zip的压缩算法,压缩比最高,但是压缩时间也比较长!」· C++ 代码 · 共 1,124 行 · 第 1/3 页

CPP
1,124
字号
// 7z/OutHandler.cpp

#include "StdAfx.h"

#include "7zHandler.h"
#include "7zOut.h"
#include "7zUpdate.h"
#include "7zMethods.h"

#include "../../../Windows/PropVariant.h"

#include "../../../Common/ComTry.h"
#include "../../../Common/StringToInt.h"
#include "../../IPassword.h"
#include "../../ICoder.h"

#include "../Common/ItemNameUtils.h"
#include "../Common/ParseProperties.h"

using namespace NWindows;

namespace NArchive {
namespace N7z {

#ifdef COMPRESS_LZMA
static CMethodID k_LZMA = { { 0x3, 0x1, 0x1 }, 3 };
#endif

#ifdef COMPRESS_PPMD
static CMethodID k_PPMD = { { 0x3, 0x4, 0x1 }, 3 };
#endif

#ifdef COMPRESS_BCJ_X86
static CMethodID k_BCJ_X86 = { { 0x3, 0x3, 0x1, 0x3 }, 4 };
#endif

#ifdef COMPRESS_BCJ2
static CMethodID k_BCJ2 = { { 0x3, 0x3, 0x1, 0x1B }, 4 };
#endif

#ifdef COMPRESS_COPY
static CMethodID k_Copy = { { 0x0 }, 1 };
#endif

#ifdef COMPRESS_DEFLATE
#ifndef COMPRESS_DEFLATE_ENCODER
#define COMPRESS_DEFLATE_ENCODER
#endif
#endif

#ifdef COMPRESS_DEFLATE_ENCODER
static CMethodID k_Deflate = { { 0x4, 0x1, 0x8 }, 3 };
#endif

#ifdef COMPRESS_BZIP2
#ifndef COMPRESS_BZIP2_ENCODER
#define COMPRESS_BZIP2_ENCODER
#endif
#endif

#ifdef COMPRESS_BZIP2_ENCODER
static CMethodID k_BZip2 = { { 0x4, 0x2, 0x2 }, 3 };
#endif

const wchar_t *kCopyMethod = L"Copy";
const wchar_t *kLZMAMethodName = L"LZMA";
const wchar_t *kBZip2MethodName = L"BZip2";
const wchar_t *kPpmdMethodName = L"PPMd";
const wchar_t *kDeflateMethodName = L"Deflate";
const wchar_t *kDeflate64MethodName = L"Deflate64";

static const wchar_t *kLzmaMatchFinderX1 = L"HC4";
static const wchar_t *kLzmaMatchFinderX5 = L"BT4";

static const UInt32 kLzmaAlgorithmX1 = 0;
static const UInt32 kLzmaAlgorithmX5 = 1;

static const UInt32 kLzmaDicSizeX1 = 1 << 16;
static const UInt32 kLzmaDicSizeX3 = 1 << 20;
static const UInt32 kLzmaDicSizeX5 = 1 << 22;
static const UInt32 kLzmaDicSizeX7 = 1 << 24;
static const UInt32 kLzmaDicSizeX9 = 1 << 26;

static const UInt32 kLzmaFastBytesX1 = 32;
static const UInt32 kLzmaFastBytesX7 = 64;

static const UInt32 kPpmdMemSizeX1 = (1 << 22);
static const UInt32 kPpmdMemSizeX5 = (1 << 24);
static const UInt32 kPpmdMemSizeX7 = (1 << 26);
static const UInt32 kPpmdMemSizeX9 = (192 << 20);

static const UInt32 kPpmdOrderX1 = 4;
static const UInt32 kPpmdOrderX5 = 6;
static const UInt32 kPpmdOrderX7 = 16;
static const UInt32 kPpmdOrderX9 = 32;

static const UInt32 kDeflateFastBytesX1 = 32;
static const UInt32 kDeflateFastBytesX7 = 64;
static const UInt32 kDeflateFastBytesX9 = 128;

static const UInt32 kDeflatePassesX1 = 1;
static const UInt32 kDeflatePassesX7 = 3;
static const UInt32 kDeflatePassesX9 = 10;

static const UInt32 kBZip2NumPassesX1 = 1;
static const UInt32 kBZip2NumPassesX7 = 2;
static const UInt32 kBZip2NumPassesX9 = 7;

static const UInt32 kBZip2DicSizeX1 = 100000;
static const UInt32 kBZip2DicSizeX3 = 500000;
static const UInt32 kBZip2DicSizeX5 = 900000;

const wchar_t *kDefaultMethodName = kLZMAMethodName;

static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2";
static const UInt32 kDictionaryForHeaders = 1 << 20;
static const UInt32 kNumFastBytesForHeaders = 273;
static const UInt32 kAlgorithmForHeaders = kLzmaAlgorithmX5;

static bool IsCopyMethod(const UString &methodName)
  { return (methodName.CompareNoCase(kCopyMethod) == 0); }

static bool IsLZMAMethod(const UString &methodName)
  { return (methodName.CompareNoCase(kLZMAMethodName) == 0); }
static bool IsLZMethod(const UString &methodName)
  { return IsLZMAMethod(methodName); }

static bool IsBZip2Method(const UString &methodName)
  { return (methodName.CompareNoCase(kBZip2MethodName) == 0); }

static bool IsPpmdMethod(const UString &methodName)
  { return (methodName.CompareNoCase(kPpmdMethodName) == 0); }

static bool IsDeflateMethod(const UString &methodName)
  { return (methodName.CompareNoCase(kDeflateMethodName) == 0) || 
  (methodName.CompareNoCase(kDeflate64MethodName) == 0); }

STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
{
  *type = NFileTimeType::kWindows;
  return S_OK;
}

HRESULT CHandler::SetPassword(CCompressionMethodMode &methodMode,
    IArchiveUpdateCallback *updateCallback)
{
  CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
  if (!getTextPassword)
  {
    CMyComPtr<IArchiveUpdateCallback> udateCallback2(updateCallback);
    udateCallback2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword);
  }
  
  if (getTextPassword)
  {
    CMyComBSTR password;
    Int32 passwordIsDefined;
    RINOK(getTextPassword->CryptoGetTextPassword2(
        &passwordIsDefined, &password));
    if (methodMode.PasswordIsDefined = IntToBool(passwordIsDefined))
      methodMode.Password = password;
  }
  else
    methodMode.PasswordIsDefined = false;
  return S_OK;
}

struct CNameToPropID
{
  PROPID PropID;
  VARTYPE VarType;
  const wchar_t *Name;
};

CNameToPropID g_NameToPropID[] = 
{
  { NCoderPropID::kOrder, VT_UI4, L"O" },
  { NCoderPropID::kPosStateBits, VT_UI4, L"PB" },
  { NCoderPropID::kLitContextBits, VT_UI4, L"LC" },
  { NCoderPropID::kLitPosBits, VT_UI4, L"LP" },

  { NCoderPropID::kNumPasses, VT_UI4, L"Pass" },
  { NCoderPropID::kNumFastBytes, VT_UI4, L"fb" },
  { NCoderPropID::kMatchFinderCycles, VT_UI4, L"mc" },
  { NCoderPropID::kAlgorithm, VT_UI4, L"a" },
  { NCoderPropID::kMatchFinder, VT_BSTR, L"mf" },
  { NCoderPropID::kNumThreads, VT_UI4, L"mt" }
};

bool ConvertProperty(PROPVARIANT srcProp, VARTYPE varType, 
    NCOM::CPropVariant &destProp)
{
  if (varType == srcProp.vt)
  {
    destProp = srcProp;
    return true;
  }
  if (varType == VT_UI1)
  {
    if(srcProp.vt == VT_UI4)
    {
      UInt32 value = srcProp.ulVal;
      if (value > 0xFF)
        return false;
      destProp = Byte(value);
      return true;
    }
  }
  return false;
}
    
const int kNumNameToPropIDItems = sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]);

int FindPropIdFromStringName(const UString &name)
{
  for (int i = 0; i < kNumNameToPropIDItems; i++)
    if (name.CompareNoCase(g_NameToPropID[i].Name) == 0)
      return i;
  return -1;
}

HRESULT CHandler::SetCompressionMethod(
    CCompressionMethodMode &methodMode,
    CCompressionMethodMode &headerMethod)
{
  HRESULT res = SetCompressionMethod(methodMode, _methods
  #ifdef COMPRESS_MT
  , _numThreads
  #endif
  );
  RINOK(res);
  methodMode.Binds = _binds;
  if (_compressHeadersFull)
    _compressHeaders = true;

  if (_compressHeaders)
  {
    // headerMethod.Methods.Add(methodMode.Methods.Back());

    CObjectVector<COneMethodInfo> headerMethodInfoVector;
    COneMethodInfo oneMethodInfo;
    oneMethodInfo.MethodName = kLZMAMethodName;
    {
      CProperty property;
      property.PropID = NCoderPropID::kMatchFinder;
      property.Value = kLzmaMatchFinderForHeaders;
      oneMethodInfo.CoderProperties.Add(property);
    }
    {
      CProperty property;
      property.PropID = NCoderPropID::kAlgorithm;
      property.Value = kAlgorithmForHeaders;
      oneMethodInfo.CoderProperties.Add(property);
    }
    {
      CProperty property;
      property.PropID = NCoderPropID::kNumFastBytes;
      property.Value = UInt32(kNumFastBytesForHeaders);
      oneMethodInfo.CoderProperties.Add(property);
    }
    {
      CProperty property;
      property.PropID = NCoderPropID::kDictionarySize;
      property.Value = UInt32(kDictionaryForHeaders);
      oneMethodInfo.CoderProperties.Add(property);
    }
    headerMethodInfoVector.Add(oneMethodInfo);
    HRESULT res = SetCompressionMethod(headerMethod, headerMethodInfoVector
      #ifdef COMPRESS_MT
      ,1
      #endif
    );
    RINOK(res);
  }
  return S_OK;
}

static void SetOneMethodProp(COneMethodInfo &oneMethodInfo, PROPID propID, 
    const NWindows::NCOM::CPropVariant &value)
{
  int j;
  for (j = 0; j < oneMethodInfo.CoderProperties.Size(); j++)
    if (oneMethodInfo.CoderProperties[j].PropID == propID)
      break;
  if (j != oneMethodInfo.CoderProperties.Size())
    return;
  CProperty property;
  property.PropID = propID;
  property.Value = value;
  oneMethodInfo.CoderProperties.Add(property);
}

HRESULT CHandler::SetCompressionMethod(
    CCompressionMethodMode &methodMode,
    CObjectVector<COneMethodInfo> &methodsInfo
    #ifdef COMPRESS_MT
    , UInt32 numThreads
    #endif
    )
{
  #ifndef EXCLUDE_COM
  /*
  CObjectVector<CMethodInfo2> methodInfoVector;
  if (!NRegistryInfo::EnumerateAllMethods(methodInfoVector))
    return E_FAIL;
  */
  #endif
 

  UInt32 level = _level;
  
  if (methodsInfo.IsEmpty())
  {
    COneMethodInfo oneMethodInfo;
    oneMethodInfo.MethodName = ((level == 0) ? kCopyMethod : kDefaultMethodName);
    methodsInfo.Add(oneMethodInfo);
  }

  bool needSolid = false;
  for(int i = 0; i < methodsInfo.Size(); i++)
  {
    COneMethodInfo &oneMethodInfo = methodsInfo[i];
    if (oneMethodInfo.MethodName.IsEmpty())
      oneMethodInfo.MethodName = kDefaultMethodName;

    if (!IsCopyMethod(oneMethodInfo.MethodName))
      needSolid = true;
    
    if (IsLZMAMethod(oneMethodInfo.MethodName))
    {
      UInt32 dicSize = 
                  (level >= 9 ? kLzmaDicSizeX9 : 
                  (level >= 7 ? kLzmaDicSizeX7 : 
                  (level >= 5 ? kLzmaDicSizeX5 : 
                  (level >= 3 ? kLzmaDicSizeX3 : 
                                kLzmaDicSizeX1)))); 

      UInt32 algorithm = 
                    (level >= 5 ? kLzmaAlgorithmX5 : 
                                  kLzmaAlgorithmX1); 

      UInt32 fastBytes = 
                    (level >= 7 ? kLzmaFastBytesX7 : 
                                  kLzmaFastBytesX1); 

      const wchar_t *matchFinder = 
                      (level >= 5 ? kLzmaMatchFinderX5 : 
                                    kLzmaMatchFinderX1); 

      SetOneMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
      SetOneMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algorithm);
      SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
      SetOneMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder);
      #ifdef COMPRESS_MT
      SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
      #endif
    }
    else if (IsDeflateMethod(oneMethodInfo.MethodName))
    {
      UInt32 fastBytes = 
                    (level >= 9 ? kDeflateFastBytesX9 : 
                    (level >= 7 ? kDeflateFastBytesX7 : 
                                  kDeflateFastBytesX1));

      UInt32 numPasses = 
                    (level >= 9 ? kDeflatePassesX9 :  
                    (level >= 7 ? kDeflatePassesX7 : 
                                  kDeflatePassesX1));

      SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
      SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
    }
    else if (IsBZip2Method(oneMethodInfo.MethodName))
    {
      UInt32 numPasses = 

⌨️ 快捷键说明

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