rarhandler.cpp

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

CPP
943
字号
// RarHandler.cpp#include "StdAfx.h"#include "RarHandler.h"#include "Common/StringConvert.h"#include "Common/ComTry.h"#include "Common/IntToString.h"#include "Windows/PropVariant.h"#include "Windows/Time.h"#include "../../IPassword.h"#include "../../Common//ProgressUtils.h"#include "../../Compress/Copy/CopyCoder.h"#include "../../Crypto/Rar20/Rar20Cipher.h"#include "../../Crypto/RarAES/RarAES.h"#include "../Common/OutStreamWithCRC.h"#include "../Common/CoderLoader.h"#include "../Common/CodecsPath.h"#include "../Common/FilterCoder.h"#include "../Common/ItemNameUtils.h"#include "../7z/7zMethods.h"using namespace NWindows;using namespace NTime;// {23170F69-40C1-278B-0403-010000000000}DEFINE_GUID(CLSID_CCompressRar15Decoder, 0x23170F69, 0x40C1, 0x278B, 0x04, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00);// {23170F69-40C1-278B-0403-020000000000}DEFINE_GUID(CLSID_CCompressRar20Decoder, 0x23170F69, 0x40C1, 0x278B, 0x04, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00);// {23170F69-40C1-278B-0403-030000000000}DEFINE_GUID(CLSID_CCompressRar29Decoder, 0x23170F69, 0x40C1, 0x278B, 0x04, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00);namespace NArchive {namespace NRar {static const wchar_t *kHostOS[] ={  L"MS DOS",  L"OS/2",  L"Win32",  L"Unix",  L"Mac OS",  L"BeOS"};static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);static const wchar_t *kUnknownOS = L"Unknown";enum // PropID{  kpidUnPackVersion = kpidUserDefined};STATPROPSTG kProperties[] = {  { NULL, kpidPath, VT_BSTR},  { NULL, kpidIsFolder, VT_BOOL},  { NULL, kpidSize, VT_UI8},  { NULL, kpidPackedSize, VT_UI8},  { NULL, kpidLastWriteTime, VT_FILETIME},  { NULL, kpidCreationTime, VT_FILETIME},  { NULL, kpidLastAccessTime, VT_FILETIME},  { NULL, kpidAttributes, VT_UI4},  { NULL, kpidEncrypted, VT_BOOL},  { NULL, kpidSolid, VT_BOOL},  { NULL, kpidCommented, VT_BOOL},  { NULL, kpidSplitBefore, VT_BOOL},  { NULL, kpidSplitAfter, VT_BOOL},  { NULL, kpidCRC, VT_UI4},  { NULL, kpidHostOS, VT_BSTR},  { NULL, kpidMethod, VT_BSTR}  // { NULL, kpidDictionarySize, VT_UI4},  // { L"UnPack Version", kpidUnPackVersion, VT_UI1}};STATPROPSTG kArchiveProperties[] = {  { NULL, kpidSolid, VT_BOOL},  { NULL, kpidCommented, VT_BOOL},};UInt64 CHandler::GetPackSize(int refIndex) const{  const CRefItem &refItem = _refItems[refIndex];  UInt64 totalPackSize = 0;  for (int i = 0; i < refItem.NumItems; i++)    totalPackSize += _items[refItem.ItemIndex + i].PackSize;  return totalPackSize;}STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value){  COM_TRY_BEGIN  NWindows::NCOM::CPropVariant propVariant;  switch(propID)  {    case kpidSolid:      propVariant = _archiveInfo.IsSolid();      break;    case kpidCommented:      propVariant = _archiveInfo.IsCommented();      break;  }  propVariant.Detach(value);  return S_OK;  COM_TRY_END}STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties){  *numProperties = sizeof(kProperties) / sizeof(kProperties[0]);  return S_OK;}STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index,           BSTR *name, PROPID *propID, VARTYPE *varType){  if(index >= sizeof(kProperties) / sizeof(kProperties[0]))    return E_INVALIDARG;  const STATPROPSTG &srcItem = kProperties[index];  *propID = srcItem.propid;  *varType = srcItem.vt;  *name = 0;  return S_OK;}STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties){  *numProperties = sizeof(kArchiveProperties) / sizeof(kArchiveProperties[0]);  return S_OK;}STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32 index,           BSTR *name, PROPID *propID, VARTYPE *varType){  if(index >= sizeof(kArchiveProperties) / sizeof(kArchiveProperties[0]))    return E_INVALIDARG;  const STATPROPSTG &srcItem = kArchiveProperties[index];  *propID = srcItem.propid;  *varType = srcItem.vt;  *name = 0;  return S_OK;}STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems){  *numItems = _refItems.Size();  return S_OK;}static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result){  if (!DosTimeToFileTime(rarTime.DosTime, result))    return false;  UInt64 value =  (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime;  value += (UInt64)rarTime.LowSecond * 10000000;  value += ((UInt64)rarTime.SubTime[2] << 16) +     ((UInt64)rarTime.SubTime[1] << 8) +    ((UInt64)rarTime.SubTime[0]);  result.dwLowDateTime = (DWORD)value;  result.dwHighDateTime = DWORD(value >> 32);  return true;}STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID,  PROPVARIANT *value){  COM_TRY_BEGIN  NWindows::NCOM::CPropVariant propVariant;  const CRefItem &refItem = _refItems[index];  const CItemEx &item = _items[refItem.ItemIndex];  switch(propID)  {    case kpidPath:    {      UString u;      if (item.HasUnicodeName() && !item.UnicodeName.IsEmpty())        u = item.UnicodeName;      else        u = MultiByteToUnicodeString(item.Name, CP_OEMCP);      propVariant = (const wchar_t *)NItemName::WinNameToOSName(u);      break;    }    case kpidIsFolder:      propVariant = item.IsDirectory();      break;    case kpidSize:      propVariant = item.UnPackSize;      break;    case kpidPackedSize:    {      propVariant = GetPackSize(index);      break;    }    case kpidLastWriteTime:    {      FILETIME localFileTime, utcFileTime;      if (RarTimeToFileTime(item.LastWriteTime, localFileTime))      {        if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))          utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;      }      else        utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;      propVariant = utcFileTime;      break;    }    case kpidCreationTime:    {      if (item.IsCreationTimeDefined)      {        FILETIME localFileTime, utcFileTime;        if (RarTimeToFileTime(item.CreationTime, localFileTime))        {          if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))            utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;        }        else          utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;        propVariant = utcFileTime;      }      break;    }    case kpidLastAccessTime:    {      if (item.IsLastAccessTimeDefined)      {        FILETIME localFileTime, utcFileTime;        if (RarTimeToFileTime(item.LastAccessTime, localFileTime))        {          if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))            utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;        }        else          utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;        propVariant = utcFileTime;      }      break;    }    case kpidAttributes:      propVariant = item.GetWinAttributes();      break;    case kpidEncrypted:      propVariant = item.IsEncrypted();      break;    case kpidSolid:      propVariant = IsSolid(index);      break;    case kpidCommented:      propVariant = item.IsCommented();      break;    case kpidSplitBefore:      propVariant = item.IsSplitBefore();      break;    case kpidSplitAfter:      propVariant = _items[refItem.ItemIndex + refItem.NumItems - 1].IsSplitAfter();      break;    /*    case kpidDictionarySize:      if (!item.IsDirectory())        propVariant = UInt32(0x10000 << item.GetDictSize());      break;    */    case kpidCRC:    {      const CItemEx &lastItem =           _items[refItem.ItemIndex + refItem.NumItems - 1];      if (lastItem.IsSplitAfter())        propVariant = item.FileCRC;      else        propVariant = lastItem.FileCRC;      break;    }    case kpidUnPackVersion:      propVariant = item.UnPackVersion;      break;    case kpidMethod:    {      UString method;      if (item.Method >= Byte('0') && item.Method <= Byte('5'))      {        method = L"m";        wchar_t temp[32];        ConvertUInt64ToString(item.Method - Byte('0'), temp);        method += temp;        if (!item.IsDirectory())        {          method += L":";          ConvertUInt64ToString(16 + item.GetDictSize(), temp);          method += temp;        }      }      else      {        wchar_t temp[32];        ConvertUInt64ToString(item.Method, temp);        method += temp;      }      propVariant = method;      break;    }    case kpidHostOS:      propVariant = (item.HostOS < kNumHostOSes) ?        (kHostOS[item.HostOS]) : kUnknownOS;      break;  }  propVariant.Detach(value);  return S_OK;  COM_TRY_END}class CVolumeName{  bool _first;  bool _newStyle;  UString _unchangedPart;  UString _changedPart;      UString _afterPart;    public:  CVolumeName(): _newStyle(true) {};  bool InitName(const UString &name, bool newStyle)  {    _first = true;    _newStyle = newStyle;    int dotPos = name.ReverseFind('.');    UString basePart = name;    if (dotPos >= 0)    {      UString ext = name.Mid(dotPos + 1);      if (ext.CompareNoCase(L"RAR")==0 ||         ext.CompareNoCase(L"EXE") == 0)      {        _afterPart = L".rar";        basePart = name.Left(dotPos);      }    }    if (!_newStyle)    {      _afterPart.Empty();      _unchangedPart = basePart + UString(L".");      _changedPart = L"r00";      return true;;    }    int numLetters = 1;    bool splitStyle = false;    if (basePart.Right(numLetters) == L"1")    {      while (numLetters < basePart.Length())      {        if (basePart[basePart.Length() - numLetters - 1] != '0')          break;        numLetters++;      }    }    else       return false;    _unchangedPart = basePart.Left(basePart.Length() - numLetters);    _changedPart = basePart.Right(numLetters);    return true;  }  UString GetNextName()  {    UString newName;     if (_newStyle || !_first)    {      int i;      int numLetters = _changedPart.Length();      for (i = numLetters - 1; i >= 0; i--)      {        wchar_t c = _changedPart[i];        if (c == L'9')        {          c = L'0';          newName = c + newName;          if (i == 0)            newName = UString(L'1') + newName;          continue;        }        c++;        newName = UString(c) + newName;        i--;        for (; i >= 0; i--)          newName = _changedPart[i] + newName;        break;      }      _changedPart = newName;    }    _first = false;    return _unchangedPart + _changedPart + _afterPart;  }};STDMETHODIMP CHandler::Open(IInStream *stream,     const UInt64 *maxCheckStartPosition,    IArchiveOpenCallback *openArchiveCallback){  COM_TRY_BEGIN  Close();  try  {    CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;    CMyComPtr<ICryptoGetTextPassword> getTextPassword;    CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openArchiveCallback;        CVolumeName seqName;    if (openArchiveCallback != NULL)    {      openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);      RINOK(openArchiveCallback->SetTotal(NULL, NULL));      UInt64 numFiles = _items.Size();      RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));      openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);    }    while(true)    {      CMyComPtr<IInStream> inStream;      if (!_archives.IsEmpty())      {        if (!openVolumeCallback)          break;                if(_archives.Size() == 1)        {          if (!_archiveInfo.IsVolume())            break;          UString baseName;          {            NCOM::CPropVariant propVariant;            RINOK(openVolumeCallback->GetProperty(kpidName, &propVariant));            if (propVariant.vt != VT_BSTR)              break;            baseName = propVariant.bstrVal;          }          seqName.InitName(baseName, _archiveInfo.HaveNewVolumeName());        }        UString fullName = seqName.GetNextName();        HRESULT result = openVolumeCallback->GetStream(fullName, &inStream);        if (result == S_FALSE)          break;        if (result != S_OK)          return result;        if (!stream)          break;      }      else        inStream = stream;            NArchive::NRar::CInArchive archive;      if(!archive.Open(inStream, maxCheckStartPosition))        return S_FALSE;

⌨️ 快捷键说明

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