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 + -
显示快捷键?