Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/Rar/RarHandler.cpp')
-rwxr-xr-xCPP/7zip/Archive/Rar/RarHandler.cpp941
1 files changed, 941 insertions, 0 deletions
diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp
new file mode 100755
index 00000000..3389f0e2
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/RarHandler.cpp
@@ -0,0 +1,941 @@
+// 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;
+ 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);
+ }
+
+ for (;;)
+ {
+ 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;
+
+ if (_archives.IsEmpty())
+ archive.GetArchiveInfo(_archiveInfo);
+
+ CItemEx item;
+ for (;;)
+ {
+ HRESULT result = archive.GetNextItem(item, getTextPassword);
+ if (result == S_FALSE)
+ break;
+ RINOK(result);
+ if (item.IgnoreItem())
+ continue;
+
+ bool needAdd = true;
+ if (item.IsSplitBefore())
+ {
+ if (!_refItems.IsEmpty())
+ {
+ CRefItem &refItem = _refItems.Back();
+ refItem.NumItems++;
+ needAdd = false;
+ }
+ }
+ 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;
+ int j;
+ for(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;
+
+ CFilterCoder *filterStreamSpec = new CFilterCoder;
+ CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec;
+
+ NCrypto::NRar20::CDecoder *rar20CryptoDecoderSpec = NULL;
+ CMyComPtr<ICompressFilter> rar20CryptoDecoder;
+ NCrypto::NRar29::CDecoder *rar29CryptoDecoderSpec = NULL;
+ CMyComPtr<ICompressFilter> 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->SetStream(realOutStream);
+ outStreamSpec->Init();
+ 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;
+
+ CMyComPtr<ISequentialInStream> inStream;
+ if (item.IsEncrypted())
+ {
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ if (item.UnPackVersion >= 29)
+ {
+ if (!rar29CryptoDecoder)
+ {
+ rar29CryptoDecoderSpec = new NCrypto::NRar29::CDecoder;
+ rar29CryptoDecoder = rar29CryptoDecoderSpec;
+ // RINOK(rar29CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar29Decoder));
+ }
+ rar29CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
+ CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties;
+ RINOK(rar29CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,
+ &cryptoProperties));
+ RINOK(cryptoProperties->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0));
+ filterStreamSpec->Filter = rar29CryptoDecoder;
+ }
+ else if (item.UnPackVersion >= 20)
+ {
+ if (!rar20CryptoDecoder)
+ {
+ rar20CryptoDecoderSpec = new NCrypto::NRar20::CDecoder;
+ rar20CryptoDecoder = rar20CryptoDecoderSpec;
+ // RINOK(rar20CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar20Decoder));
+ }
+ filterStreamSpec->Filter = rar20CryptoDecoder;
+ }
+ else
+ {
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+ RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword,
+ &cryptoSetPassword));
+
+ if (!getTextPassword)
+ extractCallback.QueryInterface(IID_ICryptoGetTextPassword,
+ &getTextPassword);
+ if (getTextPassword)
+ {
+ CMyComBSTR password;
+ RINOK(getTextPassword->CryptoGetTextPassword(&password));
+ if (item.UnPackVersion >= 29)
+ {
+ 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));
+ }
+ 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));
+ }
+ filterStreamSpec->SetInStream(folderInStream);
+ inStream = filterStream;
+ }
+ else
+ {
+ inStream = folderInStream;
+ }
+ CMyComPtr<ICompressCoder> commonCoder;
+ switch(item.Method)
+ {
+ case '0':
+ {
+ if(copyCoderSpec == NULL)
+ {
+ copyCoderSpec = new NCompress::CCopyCoder;
+ copyCoder = copyCoderSpec;
+ }
+ commonCoder = copyCoder;
+ 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<ICompressSetDecoderProperties2> compressSetDecoderProperties;
+ RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties2,
+ &compressSetDecoderProperties));
+
+ Byte isSolid = (Byte)((IsSolid(index) || item.IsSplitBefore()) ? 1: 0);
+
+ RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1));
+
+ commonCoder = decoder;
+ break;
+ }
+ default:
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+ HRESULT result = commonCoder->Code(inStream, outStream,
+ &packSize, &item.UnPackSize, compressProgress);
+ if (item.IsEncrypted())
+ filterStreamSpec->ReleaseInStream();
+ if (result == S_FALSE)
+ {
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ if (result != S_OK)
+ return result;
+
+ /*
+ 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
+}
+*/
+
+}}