diff options
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Archive/Rar')
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.cpp | 869 | ||||
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.h | 66 | ||||
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.cpp | 21 | ||||
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.h | 205 | ||||
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.cpp | 478 | ||||
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.h | 123 | ||||
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.cpp | 55 | ||||
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.h | 79 | ||||
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Rar/RarRegister.cpp | 13 | ||||
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp | 78 | ||||
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.h | 49 | ||||
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.cpp | 3 | ||||
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.h | 8 |
13 files changed, 2047 insertions, 0 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.cpp new file mode 100644 index 000000000..5d072d34d --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.cpp @@ -0,0 +1,869 @@ +// RarHandler.cpp + +#include "StdAfx.h" + +#include "Common/ComTry.h" +#include "Common/IntToString.h" +#include "Common/StringConvert.h" + +#include "Windows/PropVariant.h" +#include "Windows/PropVariantUtils.h" +#include "Windows/Time.h" + +#include "../../IPassword.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/FilterCoder.h" +#include "../../Common/MethodId.h" +#include "../../Common/ProgressUtils.h" + +#include "../../Compress/CopyCoder.h" + +#include "../../Crypto/Rar20Crypto.h" +#include "../../Crypto/RarAes.h" + +#include "../Common/ItemNameUtils.h" +#include "../Common/OutStreamWithCRC.h" + +#include "RarHandler.h" + +using namespace NWindows; +using namespace NTime; + +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"; + +static const CUInt32PCharPair k_Flags[] = +{ + { 0, "Volume" }, + { 1, "Comment" }, + { 2, "Lock" }, + { 3, "Solid" }, + { 4, "NewVolName" }, // pack_comment in old versuons + { 5, "Authenticity" }, + { 6, "Recovery" }, + { 7, "BlockEncryption" }, + { 8, "FirstVolume" }, + { 9, "EncryptVer" } +}; + +static const STATPROPSTG kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidIsDir, VT_BOOL}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidPackSize, VT_UI8}, + { NULL, kpidMTime, VT_FILETIME}, + { NULL, kpidCTime, VT_FILETIME}, + { NULL, kpidATime, VT_FILETIME}, + { NULL, kpidAttrib, 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, kpidUnpackVer, VT_UI1} +}; + +static const STATPROPSTG kArcProps[] = +{ + { NULL, kpidCharacts, VT_BSTR}, + { NULL, kpidSolid, VT_BOOL}, + { NULL, kpidNumBlocks, VT_UI4}, + // { NULL, kpidEncrypted, VT_BOOL}, + { NULL, kpidIsVolume, VT_BOOL}, + { NULL, kpidNumVolumes, VT_UI4}, + { NULL, kpidPhySize, VT_UI8} + // { NULL, kpidCommented, VT_BOOL} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +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 prop; + switch(propID) + { + case kpidSolid: prop = _archiveInfo.IsSolid(); break; + case kpidCharacts: FLAGS_TO_PROP(k_Flags, _archiveInfo.Flags, prop); break; + // case kpidEncrypted: prop = _archiveInfo.IsEncrypted(); break; // it's for encrypted names. + case kpidIsVolume: prop = _archiveInfo.IsVolume(); break; + case kpidNumVolumes: prop = (UInt32)_archives.Size(); break; + case kpidOffset: if (_archiveInfo.StartPosition != 0) prop = _archiveInfo.StartPosition; break; + // case kpidCommented: prop = _archiveInfo.IsCommented(); break; + case kpidNumBlocks: + { + UInt32 numBlocks = 0; + for (int i = 0; i < _refItems.Size(); i++) + if (!IsSolid(i)) + numBlocks++; + prop = (UInt32)numBlocks; + break; + } + case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +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; +} + +static void RarTimeToProp(const CRarTime &rarTime, NWindows::NCOM::CPropVariant &prop) +{ + FILETIME localFileTime, utcFileTime; + if (RarTimeToFileTime(rarTime, localFileTime)) + { + if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime)) + utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; + } + else + utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; + prop = utcFileTime; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + 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); + prop = (const wchar_t *)NItemName::WinNameToOSName(u); + break; + } + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: prop = item.Size; break; + case kpidPackSize: prop = GetPackSize(index); break; + case kpidMTime: RarTimeToProp(item.MTime, prop); break; + case kpidCTime: if (item.CTimeDefined) RarTimeToProp(item.CTime, prop); break; + case kpidATime: if (item.ATimeDefined) RarTimeToProp(item.ATime, prop); break; + case kpidAttrib: prop = item.GetWinAttributes(); break; + case kpidEncrypted: prop = item.IsEncrypted(); break; + case kpidSolid: prop = IsSolid(index); break; + case kpidCommented: prop = item.IsCommented(); break; + case kpidSplitBefore: prop = item.IsSplitBefore(); break; + case kpidSplitAfter: prop = _items[refItem.ItemIndex + refItem.NumItems - 1].IsSplitAfter(); break; + case kpidCRC: + { + const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1]; + prop = ((lastItem.IsSplitAfter()) ? item.FileCRC : lastItem.FileCRC); + break; + } + case kpidUnpackVer: prop = 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.IsDir()) + { + method += L":"; + ConvertUInt64ToString(16 + item.GetDictSize(), temp); + method += temp; + } + } + else + { + wchar_t temp[32]; + ConvertUInt64ToString(item.Method, temp); + method += temp; + } + prop = method; + break; + } + case kpidHostOS: prop = (item.HostOS < kNumHostOSes) ? (kHostOS[item.HostOS]) : kUnknownOS; break; + } + prop.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) + { + _afterPart = name.Mid(dotPos); + basePart = name.Left(dotPos); + } + else if (ext.CompareNoCase(L"exe") == 0) + { + _afterPart = L".rar"; + basePart = name.Left(dotPos); + } + else if (!_newStyle) + { + if (ext.CompareNoCase(L"000") == 0 || + ext.CompareNoCase(L"001") == 0 || + ext.CompareNoCase(L"r00") == 0 || + ext.CompareNoCase(L"r01") == 0) + { + _afterPart.Empty(); + _first = false; + _changedPart = ext; + _unchangedPart = name.Left(dotPos + 1); + return true; + } + } + } + + if (!_newStyle) + { + _afterPart.Empty(); + _unchangedPart = basePart + UString(L"."); + _changedPart = L"r00"; + return true; + } + + int numLetters = 1; + if (basePart.Right(numLetters) == L"1" || basePart.Right(numLetters) == L"0") + { + 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; + } +}; + +HRESULT CHandler::Open2(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback) +{ + { + CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; + CMyComPtr<ICryptoGetTextPassword> getTextPassword; + CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openCallback; + + CVolumeName seqName; + + UInt64 totalBytes = 0; + UInt64 curBytes = 0; + + if (openCallback) + { + openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback); + 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 prop; + RINOK(openVolumeCallback->GetProperty(kpidName, &prop)); + if (prop.vt != VT_BSTR) + break; + baseName = prop.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; + + UInt64 endPos = 0; + RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + if (openCallback) + { + totalBytes += endPos; + RINOK(openCallback->SetTotal(NULL, &totalBytes)); + } + + NArchive::NRar::CInArchive archive; + RINOK(archive.Open(inStream, maxCheckStartPosition)); + + if (_archives.IsEmpty()) + archive.GetArchiveInfo(_archiveInfo); + + CItemEx item; + for (;;) + { + if (archive.m_Position > endPos) + { + AddErrorMessage("Unexpected end of archive"); + break; + } + bool decryptionError; + AString errorMessageLoc; + HRESULT result = archive.GetNextItem(item, getTextPassword, decryptionError, errorMessageLoc); + if (errorMessageLoc) + AddErrorMessage(errorMessageLoc); + if (result == S_FALSE) + { + if (decryptionError && _items.IsEmpty()) + return 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 (openCallback && _items.Size() % 100 == 0) + { + UInt64 numFiles = _items.Size(); + UInt64 numBytes = curBytes + item.Position; + RINOK(openCallback->SetCompleted(&numFiles, &numBytes)); + } + } + curBytes += endPos; + _archives.Add(archive); + } + } + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback) +{ + COM_TRY_BEGIN + Close(); + try + { + HRESULT res = Open2(stream, maxCheckStartPosition, openCallback); + if (res != S_OK) + Close(); + return res; + } + catch(const CInArchiveException &) { Close(); return S_FALSE; } + catch(...) { Close(); throw; } + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + COM_TRY_BEGIN + _errorMessage.Empty(); + _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 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + CMyComPtr<ICryptoGetTextPassword> getTextPassword; + 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.Size; + // 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.Size; + // importantTotalPacked += item.PackSize; + importantIndexes.Add(j); + extractStatuses.Add(j == index); + } + lastIndex = index + 1; + } + + RINOK(extractCallback->SetTotal(importantTotalUnPacked)); + UInt64 currentImportantTotalUnPacked = 0; + UInt64 currentImportantTotalPacked = 0; + UInt64 currentUnPackSize, currentPackSize; + + CObjectVector<CMethodItem> methodItems; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + 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; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + bool solidStart = true; + for (int i = 0; i < importantIndexes.Size(); i++, + currentImportantTotalUnPacked += currentUnPackSize, + currentImportantTotalPacked += currentPackSize) + { + lps->InSize = currentImportantTotalPacked; + lps->OutSize = currentImportantTotalUnPacked; + RINOK(lps->SetCur()); + CMyComPtr<ISequentialOutStream> realOutStream; + + Int32 askMode; + if (extractStatuses[i]) + askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + else + askMode = NExtract::NAskMode::kSkip; + + UInt32 index = importantIndexes[i]; + + const CRefItem &refItem = _refItems[index]; + const CItemEx &item = _items[refItem.ItemIndex]; + + currentUnPackSize = item.Size; + + currentPackSize = GetPackSize(index); + + if (item.IgnoreItem()) + continue; + + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + if (!IsSolid(index)) + solidStart = true; + if (item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(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 = NExtract::NAskMode::kSkip; + + RINOK(extractCallback->PrepareOperation(askMode)); + + COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; + CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + realOutStream.Release(); + + /* + 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); + + 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(NExtract::NOperationResult::kUnSupportedMethod)); + continue; + } + RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, + &cryptoSetPassword)); + + if (!getTextPassword) + extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&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': + { + commonCoder = copyCoder; + break; + } + case '1': + case '2': + case '3': + case '4': + case '5': + { + /* + if (item.UnPackVersion >= 29) + { + outStream.Release(); + RINOK(extractCallback->SetOperationResult(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; + + mi.Coder.Release(); + if (item.UnPackVersion <= 30) + { + UInt32 methodID = 0x040300; + if (item.UnPackVersion < 20) + methodID += 1; + else if (item.UnPackVersion < 29) + methodID += 2; + else + methodID += 3; + RINOK(CreateCoder(EXTERNAL_CODECS_VARS methodID, mi.Coder, false)); + } + + if (mi.Coder == 0) + { + outStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + continue; + } + + 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); + if (solidStart) + { + isSolid = false; + solidStart = false; + } + + + RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1)); + + commonCoder = decoder; + break; + } + default: + outStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + continue; + } + HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &item.Size, progress); + if (item.IsEncrypted()) + filterStreamSpec->ReleaseInStream(); + if (result == S_FALSE) + { + outStream.Release(); + RINOK(extractCallback->SetOperationResult(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 ? + NExtract::NOperationResult::kOK: + 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 ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kCRCError)); + } + */ + } + return S_OK; + COM_TRY_END +} + +IMPL_ISetCompressCodecsInfo + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.h new file mode 100644 index 000000000..792668273 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.h @@ -0,0 +1,66 @@ +// Rar/Handler.h + +#ifndef __RAR_HANDLER_H +#define __RAR_HANDLER_H + +#include "../IArchive.h" + +#include "../../Common/CreateCoder.h" + +#include "RarIn.h" +#include "RarVolumeInStream.h" + +namespace NArchive { +namespace NRar { + +class CHandler: + public IInArchive, + PUBLIC_ISetCompressCodecsInfo + public CMyUnknownImp +{ + CRecordVector<CRefItem> _refItems; + CObjectVector<CItemEx> _items; + CObjectVector<CInArchive> _archives; + NArchive::NRar::CInArchiveInfo _archiveInfo; + AString _errorMessage; + + DECL_EXTERNAL_CODECS_VARS + + UInt64 GetPackSize(int refIndex) const; + + bool IsSolid(int refIndex) + { + const CItemEx &item = _items[_refItems[refIndex].ItemIndex]; + if (item.UnPackVersion < 20) + { + if (_archiveInfo.IsSolid()) + return (refIndex > 0); + return false; + } + return item.IsSolid(); + } + void AddErrorMessage(const AString &s) + { + if (!_errorMessage.IsEmpty()) + _errorMessage += '\n'; + _errorMessage += s; + } + + HRESULT Open2(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback); + +public: + MY_QUERYINTERFACE_BEGIN2(IInArchive) + QUERY_ENTRY_ISetCompressCodecsInfo + MY_QUERYINTERFACE_END + MY_ADDREF_RELEASE + + INTERFACE_IInArchive(;) + + DECL_ISetCompressCodecsInfo +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.cpp new file mode 100644 index 000000000..94481e025 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.cpp @@ -0,0 +1,21 @@ +// Archive/Rar/Headers.cpp + +#include "StdAfx.h" + +#include "RarHeader.h" + +namespace NArchive{ +namespace NRar{ +namespace NHeader{ + +Byte kMarker[kMarkerSize] = {0x52 + 1, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00}; + +class CMarkerInitializer +{ +public: + CMarkerInitializer() { kMarker[0]--; }; +}; + +static CMarkerInitializer markerInitializer; + +}}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.h b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.h new file mode 100644 index 000000000..5c21a2ac0 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.h @@ -0,0 +1,205 @@ +// Archive/RarHeader.h + +#ifndef __ARCHIVE_RAR_HEADER_H +#define __ARCHIVE_RAR_HEADER_H + +#include "Common/Types.h" + +namespace NArchive { +namespace NRar { +namespace NHeader { + +const int kMarkerSize = 7; +extern Byte kMarker[kMarkerSize]; + +const int kArchiveSolid = 0x1; + +namespace NBlockType +{ + enum EBlockType + { + kMarker = 0x72, + kArchiveHeader, + kFileHeader, + kCommentHeader, + kOldAuthenticity, + kOldSubBlock, + kRecoveryRecord, + kAuthenticity, + kSubBlock, + kEndOfArchive + }; +} + +namespace NArchive +{ + const UInt16 kVolume = 1; + const UInt16 kComment = 2; + const UInt16 kLock = 4; + const UInt16 kSolid = 8; + const UInt16 kNewVolName = 0x10; // ('volname.partN.rar') + const UInt16 kAuthenticity = 0x20; + const UInt16 kRecovery = 0x40; + const UInt16 kBlockEncryption = 0x80; + const UInt16 kFirstVolume = 0x100; // (set only by RAR 3.0 and later) + const UInt16 kEncryptVer = 0x200; // RAR 3.6 there is EncryptVer Byte in End of MainHeader + + const int kHeaderSizeMin = 7; + + const int kArchiveHeaderSize = 13; + + const int kBlockHeadersAreEncrypted = 0x80; + +} + +namespace NFile +{ + const int kSplitBefore = 1 << 0; + const int kSplitAfter = 1 << 1; + const int kEncrypted = 1 << 2; + const int kComment = 1 << 3; + const int kSolid = 1 << 4; + + const int kDictBitStart = 5; + const int kNumDictBits = 3; + const int kDictMask = (1 << kNumDictBits) - 1; + const int kDictDirectoryValue = 0x7; + + const int kSize64Bits = 1 << 8; + const int kUnicodeName = 1 << 9; + const int kSalt = 1 << 10; + const int kOldVersion = 1 << 11; + const int kExtTime = 1 << 12; + // const int kExtFlags = 1 << 13; + // const int kSkipIfUnknown = 1 << 14; + + const int kLongBlock = 1 << 15; + + /* + struct CBlock + { + // UInt16 HeadCRC; + // Byte Type; + // UInt16 Flags; + // UInt16 HeadSize; + UInt32 PackSize; + UInt32 UnPackSize; + Byte HostOS; + UInt32 FileCRC; + UInt32 Time; + Byte UnPackVersion; + Byte Method; + UInt16 NameSize; + UInt32 Attributes; + }; + */ + + /* + struct CBlock32 + { + UInt16 HeadCRC; + Byte Type; + UInt16 Flags; + UInt16 HeadSize; + UInt32 PackSize; + UInt32 UnPackSize; + Byte HostOS; + UInt32 FileCRC; + UInt32 Time; + Byte UnPackVersion; + Byte Method; + UInt16 NameSize; + UInt32 Attributes; + UInt16 GetRealCRC(const void *aName, UInt32 aNameSize, + bool anExtraDataDefined = false, Byte *anExtraData = 0) const; + }; + struct CBlock64 + { + UInt16 HeadCRC; + Byte Type; + UInt16 Flags; + UInt16 HeadSize; + UInt32 PackSizeLow; + UInt32 UnPackSizeLow; + Byte HostOS; + UInt32 FileCRC; + UInt32 Time; + Byte UnPackVersion; + Byte Method; + UInt16 NameSize; + UInt32 Attributes; + UInt32 PackSizeHigh; + UInt32 UnPackSizeHigh; + UInt16 GetRealCRC(const void *aName, UInt32 aNameSize) const; + }; + */ + + const int kLabelFileAttribute = 0x08; + const int kWinFileDirectoryAttributeMask = 0x10; + + enum CHostOS + { + kHostMSDOS = 0, + kHostOS2 = 1, + kHostWin32 = 2, + kHostUnix = 3, + kHostMacOS = 4, + kHostBeOS = 5 + }; +} + +namespace NBlock +{ + const UInt16 kLongBlock = 1 << 15; + struct CBlock + { + UInt16 CRC; + Byte Type; + UInt16 Flags; + UInt16 HeadSize; + // UInt32 DataSize; + }; +} + +/* +struct CSubBlock +{ + UInt16 HeadCRC; + Byte HeadType; + UInt16 Flags; + UInt16 HeadSize; + UInt32 DataSize; + UInt16 SubType; + Byte Level; // Reserved : Must be 0 +}; + +struct CCommentBlock +{ + UInt16 HeadCRC; + Byte HeadType; + UInt16 Flags; + UInt16 HeadSize; + UInt16 UnpSize; + Byte UnpVer; + Byte Method; + UInt16 CommCRC; +}; + + +struct CProtectHeader +{ + UInt16 HeadCRC; + Byte HeadType; + UInt16 Flags; + UInt16 HeadSize; + UInt32 DataSize; + Byte Version; + UInt16 RecSectors; + UInt32 TotalBlocks; + Byte Mark[8]; +}; +*/ + +}}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.cpp new file mode 100644 index 000000000..e4c23752c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.cpp @@ -0,0 +1,478 @@ +// Archive/RarIn.cpp + +#include "StdAfx.h" + +#include "../../../../C/7zCrc.h" +#include "../../../../C/CpuArch.h" + +#include "Common/StringConvert.h" +#include "Common/UTFConvert.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/StreamUtils.h" + +#include "../Common/FindSignature.h" + +#include "RarIn.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +namespace NArchive { +namespace NRar { + +static const char *k_UnexpectedEnd = "Unexpected end of archive"; +static const char *k_DecryptionError = "Decryption Error"; + +void CInArchive::ThrowExceptionWithCode( + CInArchiveException::CCauseType cause) +{ + throw CInArchiveException(cause); +} + +HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit) +{ + try + { + Close(); + HRESULT res = Open2(inStream, searchHeaderSizeLimit); + if (res == S_OK) + return res; + Close(); + return res; + } + catch(...) { Close(); throw; } +} + +void CInArchive::Close() +{ + m_Stream.Release(); +} + +HRESULT CInArchive::ReadBytesSpec(void *data, size_t *resSize) +{ + if (m_CryptoMode) + { + size_t size = *resSize; + *resSize = 0; + const Byte *bufData = m_DecryptedDataAligned; + UInt32 bufSize = m_DecryptedDataSize; + size_t i; + for (i = 0; i < size && m_CryptoPos < bufSize; i++) + ((Byte *)data)[i] = bufData[m_CryptoPos++]; + *resSize = i; + return S_OK; + } + return ReadStream(m_Stream, data, resSize); +} + +bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size) +{ + size_t processed = size; + if (ReadBytesSpec(data, &processed) != S_OK) + return false; + return processed == size; +} + +HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit) +{ + m_CryptoMode = false; + RINOK(stream->Seek(0, STREAM_SEEK_SET, &m_StreamStartPosition)); + m_Position = m_StreamStartPosition; + + UInt64 arcStartPos; + RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize, + searchHeaderSizeLimit, arcStartPos)); + m_Position = arcStartPos + NHeader::kMarkerSize; + RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); + Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1]; + + RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize)); + AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize); + + + UInt32 blockSize = Get16(buf + 5); + + _header.EncryptVersion = 0; + _header.Flags = Get16(buf + 3); + + UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize; + if (_header.IsThereEncryptVer()) + { + if (blockSize <= headerSize) + return S_FALSE; + RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1)); + AddToSeekValue(1); + _header.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize]; + headerSize += 1; + } + if (blockSize < headerSize || + buf[2] != NHeader::NBlockType::kArchiveHeader || + (UInt32)Get16(buf) != (CrcCalc(buf + 2, headerSize - 2) & 0xFFFF)) + return S_FALSE; + + size_t commentSize = blockSize - headerSize; + _comment.SetCapacity(commentSize); + RINOK(ReadStream_FALSE(stream, _comment, commentSize)); + AddToSeekValue(commentSize); + m_Stream = stream; + _header.StartPosition = arcStartPos; + return S_OK; +} + +void CInArchive::GetArchiveInfo(CInArchiveInfo &archiveInfo) const +{ + archiveInfo = _header; +} + +static void DecodeUnicodeFileName(const char *name, const Byte *encName, + int encSize, wchar_t *unicodeName, int maxDecSize) +{ + int encPos = 0; + int decPos = 0; + int flagBits = 0; + Byte flags = 0; + Byte highByte = encName[encPos++]; + while (encPos < encSize && decPos < maxDecSize) + { + if (flagBits == 0) + { + flags = encName[encPos++]; + flagBits = 8; + } + switch(flags >> 6) + { + case 0: + unicodeName[decPos++] = encName[encPos++]; + break; + case 1: + unicodeName[decPos++] = (wchar_t)(encName[encPos++] + (highByte << 8)); + break; + case 2: + unicodeName[decPos++] = (wchar_t)(encName[encPos] + (encName[encPos + 1] << 8)); + encPos += 2; + break; + case 3: + { + int length = encName[encPos++]; + if (length & 0x80) + { + Byte correction = encName[encPos++]; + for (length = (length & 0x7f) + 2; + length > 0 && decPos < maxDecSize; length--, decPos++) + unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + (highByte << 8)); + } + else + for (length += 2; length > 0 && decPos < maxDecSize; length--, decPos++) + unicodeName[decPos] = name[decPos]; + } + break; + } + flags <<= 2; + flagBits -= 2; + } + unicodeName[decPos < maxDecSize ? decPos : maxDecSize - 1] = 0; +} + +void CInArchive::ReadName(CItemEx &item, int nameSize) +{ + item.UnicodeName.Empty(); + if (nameSize > 0) + { + m_NameBuffer.EnsureCapacity(nameSize + 1); + char *buffer = (char *)m_NameBuffer; + + for (int i = 0; i < nameSize; i++) + buffer[i] = ReadByte(); + + int mainLen; + for (mainLen = 0; mainLen < nameSize; mainLen++) + if (buffer[mainLen] == '\0') + break; + buffer[mainLen] = '\0'; + item.Name = buffer; + + if(item.HasUnicodeName()) + { + if(mainLen < nameSize) + { + int unicodeNameSizeMax = MyMin(nameSize, (0x400)); + _unicodeNameBuffer.EnsureCapacity(unicodeNameSizeMax + 1); + DecodeUnicodeFileName(buffer, (const Byte *)buffer + mainLen + 1, + nameSize - (mainLen + 1), _unicodeNameBuffer, unicodeNameSizeMax); + item.UnicodeName = _unicodeNameBuffer; + } + else if (!ConvertUTF8ToUnicode(item.Name, item.UnicodeName)) + item.UnicodeName.Empty(); + } + } + else + item.Name.Empty(); +} + +Byte CInArchive::ReadByte() +{ + if (m_CurPos >= m_PosLimit) + throw CInArchiveException(CInArchiveException::kIncorrectArchive); + return m_CurData[m_CurPos++]; +} + +UInt16 CInArchive::ReadUInt16() +{ + UInt16 value = 0; + for (int i = 0; i < 2; i++) + { + Byte b = ReadByte(); + value |= (UInt16(b) << (8 * i)); + } + return value; +} + +UInt32 CInArchive::ReadUInt32() +{ + UInt32 value = 0; + for (int i = 0; i < 4; i++) + { + Byte b = ReadByte(); + value |= (UInt32(b) << (8 * i)); + } + return value; +} + +void CInArchive::ReadTime(Byte mask, CRarTime &rarTime) +{ + rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0); + int numDigits = (mask & 3); + rarTime.SubTime[0] = rarTime.SubTime[1] = rarTime.SubTime[2] = 0; + for (int i = 0; i < numDigits; i++) + rarTime.SubTime[3 - numDigits + i] = ReadByte(); +} + +void CInArchive::ReadHeaderReal(CItemEx &item) +{ + item.Flags = m_BlockHeader.Flags; + item.PackSize = ReadUInt32(); + item.Size = ReadUInt32(); + item.HostOS = ReadByte(); + item.FileCRC = ReadUInt32(); + item.MTime.DosTime = ReadUInt32(); + item.UnPackVersion = ReadByte(); + item.Method = ReadByte(); + int nameSize = ReadUInt16(); + item.Attrib = ReadUInt32(); + + item.MTime.LowSecond = 0; + item.MTime.SubTime[0] = + item.MTime.SubTime[1] = + item.MTime.SubTime[2] = 0; + + if((item.Flags & NHeader::NFile::kSize64Bits) != 0) + { + item.PackSize |= ((UInt64)ReadUInt32() << 32); + item.Size |= ((UInt64)ReadUInt32() << 32); + } + + ReadName(item, nameSize); + + if (item.HasSalt()) + for (int i = 0; i < sizeof(item.Salt); i++) + item.Salt[i] = ReadByte(); + + // some rar archives have HasExtTime flag without field. + if (m_CurPos < m_PosLimit && item.HasExtTime()) + { + Byte accessMask = (Byte)(ReadByte() >> 4); + Byte b = ReadByte(); + Byte modifMask = (Byte)(b >> 4); + Byte createMask = (Byte)(b & 0xF); + if ((modifMask & 8) != 0) + ReadTime(modifMask, item.MTime); + item.CTimeDefined = ((createMask & 8) != 0); + if (item.CTimeDefined) + { + item.CTime.DosTime = ReadUInt32(); + ReadTime(createMask, item.CTime); + } + item.ATimeDefined = ((accessMask & 8) != 0); + if (item.ATimeDefined) + { + item.ATime.DosTime = ReadUInt32(); + ReadTime(accessMask, item.ATime); + } + } + + UInt16 fileHeaderWithNameSize = (UInt16)m_CurPos; + + item.Position = m_Position; + item.MainPartSize = fileHeaderWithNameSize; + item.CommentSize = (UInt16)(m_BlockHeader.HeadSize - fileHeaderWithNameSize); + + if (m_CryptoMode) + item.AlignSize = (UInt16)((16 - ((m_BlockHeader.HeadSize) & 0xF)) & 0xF); + else + item.AlignSize = 0; + AddToSeekValue(m_BlockHeader.HeadSize); +} + +void CInArchive::AddToSeekValue(UInt64 addValue) +{ + m_Position += addValue; +} + +HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage) +{ + decryptionError = false; + for (;;) + { + SeekInArchive(m_Position); + if (!m_CryptoMode && (_header.Flags & + NHeader::NArchive::kBlockHeadersAreEncrypted) != 0) + { + m_CryptoMode = false; + if (getTextPassword == 0) + return S_FALSE; + if (!m_RarAES) + { + m_RarAESSpec = new NCrypto::NRar29::CDecoder; + m_RarAES = m_RarAESSpec; + } + m_RarAESSpec->SetRar350Mode(_header.IsEncryptOld()); + + // Salt + const UInt32 kSaltSize = 8; + Byte salt[kSaltSize]; + if(!ReadBytesAndTestSize(salt, kSaltSize)) + return S_FALSE; + m_Position += kSaltSize; + RINOK(m_RarAESSpec->SetDecoderProperties2(salt, kSaltSize)) + // Password + CMyComBSTR password; + RINOK(getTextPassword->CryptoGetTextPassword(&password)) + UString unicodePassword(password); + + CByteBuffer buffer; + 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(m_RarAESSpec->CryptoSetPassword((const Byte *)buffer, sizeInBytes)); + + const UInt32 kDecryptedBufferSize = (1 << 12); + if (m_DecryptedData.GetCapacity() == 0) + { + const UInt32 kAlign = 16; + m_DecryptedData.SetCapacity(kDecryptedBufferSize + kAlign); + m_DecryptedDataAligned = (Byte *)((ptrdiff_t)((Byte *)m_DecryptedData + kAlign - 1) & ~(ptrdiff_t)(kAlign - 1)); + } + RINOK(m_RarAES->Init()); + size_t decryptedDataSizeT = kDecryptedBufferSize; + RINOK(ReadStream(m_Stream, m_DecryptedDataAligned, &decryptedDataSizeT)); + m_DecryptedDataSize = (UInt32)decryptedDataSizeT; + m_DecryptedDataSize = m_RarAES->Filter(m_DecryptedDataAligned, m_DecryptedDataSize); + + m_CryptoMode = true; + m_CryptoPos = 0; + } + + m_FileHeaderData.EnsureCapacity(7); + size_t processed = 7; + RINOK(ReadBytesSpec((Byte *)m_FileHeaderData, &processed)); + if (processed != 7) + { + if (processed != 0) + errorMessage = k_UnexpectedEnd; + return S_FALSE; + } + + m_CurData = (Byte *)m_FileHeaderData; + m_CurPos = 0; + m_PosLimit = 7; + m_BlockHeader.CRC = ReadUInt16(); + m_BlockHeader.Type = ReadByte(); + m_BlockHeader.Flags = ReadUInt16(); + m_BlockHeader.HeadSize = ReadUInt16(); + + if (m_BlockHeader.HeadSize < 7) + ThrowExceptionWithCode(CInArchiveException::kIncorrectArchive); + + if (m_BlockHeader.Type == NHeader::NBlockType::kEndOfArchive) + return S_FALSE; + + if (m_BlockHeader.Type == NHeader::NBlockType::kFileHeader) + { + m_FileHeaderData.EnsureCapacity(m_BlockHeader.HeadSize); + m_CurData = (Byte *)m_FileHeaderData; + m_PosLimit = m_BlockHeader.HeadSize; + if (!ReadBytesAndTestSize(m_CurData + m_CurPos, m_BlockHeader.HeadSize - 7)) + { + errorMessage = k_UnexpectedEnd; + return S_FALSE; + } + + ReadHeaderReal(item); + if ((CrcCalc(m_CurData + 2, + m_BlockHeader.HeadSize - item.CommentSize - 2) & 0xFFFF) != m_BlockHeader.CRC) + ThrowExceptionWithCode(CInArchiveException::kFileHeaderCRCError); + + FinishCryptoBlock(); + m_CryptoMode = false; + SeekInArchive(m_Position); // Move Position to compressed Data; + AddToSeekValue(item.PackSize); // m_Position points to next header; + return S_OK; + } + if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 10)) + { + decryptionError = true; + errorMessage = k_DecryptionError; + return S_FALSE; + } + if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0) + { + m_FileHeaderData.EnsureCapacity(7 + 4); + m_CurData = (Byte *)m_FileHeaderData; + if (!ReadBytesAndTestSize(m_CurData + m_CurPos, 4)) + { + errorMessage = k_UnexpectedEnd; + return S_FALSE; + } + m_PosLimit = 7 + 4; + UInt32 dataSize = ReadUInt32(); + AddToSeekValue(dataSize); + if (m_CryptoMode && dataSize > (1 << 27)) + { + decryptionError = true; + errorMessage = k_DecryptionError; + return S_FALSE; + } + m_CryptoPos = m_BlockHeader.HeadSize; + } + else + m_CryptoPos = 0; + AddToSeekValue(m_BlockHeader.HeadSize); + FinishCryptoBlock(); + m_CryptoMode = false; + } +} + +void CInArchive::SeekInArchive(UInt64 position) +{ + m_Stream->Seek(position, STREAM_SEEK_SET, NULL); +} + +ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size) +{ + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream(streamSpec); + SeekInArchive(position); + streamSpec->SetStream(m_Stream); + streamSpec->Init(size); + return inStream.Detach(); +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.h new file mode 100644 index 000000000..a6998db26 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.h @@ -0,0 +1,123 @@ +// RarIn.h + +#ifndef __ARCHIVE_RAR_IN_H +#define __ARCHIVE_RAR_IN_H + +#include "Common/DynamicBuffer.h" +#include "Common/MyCom.h" + +#include "../../ICoder.h" +#include "../../IStream.h" + +#include "../../Common/StreamObjects.h" + +#include "../../Crypto/RarAes.h" + +#include "RarHeader.h" +#include "RarItem.h" + +namespace NArchive { +namespace NRar { + +class CInArchiveException +{ +public: + enum CCauseType + { + kUnexpectedEndOfArchive = 0, + kArchiveHeaderCRCError, + kFileHeaderCRCError, + kIncorrectArchive + } + Cause; + CInArchiveException(CCauseType cause) : Cause(cause) {} +}; + + +struct CInArchiveInfo +{ + UInt32 Flags; + Byte EncryptVersion; + UInt64 StartPosition; + + bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; } + bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; } + bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; } + bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 0; } + bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; } + bool IsThereEncryptVer() const { return (Flags & NHeader::NArchive::kEncryptVer) != 0; } + bool IsEncryptOld() const { return (!IsThereEncryptVer() || EncryptVersion < 36); } +}; + +class CInArchive +{ + CMyComPtr<IInStream> m_Stream; + + UInt64 m_StreamStartPosition; + + CInArchiveInfo _header; + CDynamicBuffer<char> m_NameBuffer; + CDynamicBuffer<wchar_t> _unicodeNameBuffer; + + CByteBuffer _comment; + + void ReadName(CItemEx &item, int nameSize); + void ReadHeaderReal(CItemEx &item); + + HRESULT ReadBytesSpec(void *data, size_t *size); + bool ReadBytesAndTestSize(void *data, UInt32 size); + + HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit); + + void ThrowExceptionWithCode(CInArchiveException::CCauseType cause); + void ThrowUnexpectedEndOfArchiveException(); + + void AddToSeekValue(UInt64 addValue); + + CDynamicBuffer<Byte> m_FileHeaderData; + + NHeader::NBlock::CBlock m_BlockHeader; + + NCrypto::NRar29::CDecoder *m_RarAESSpec; + CMyComPtr<ICompressFilter> m_RarAES; + + Byte *m_CurData; // it must point to start of Rar::Block + UInt32 m_CurPos; + UInt32 m_PosLimit; + Byte ReadByte(); + UInt16 ReadUInt16(); + UInt32 ReadUInt32(); + void ReadTime(Byte mask, CRarTime &rarTime); + + CBuffer<Byte> m_DecryptedData; + Byte *m_DecryptedDataAligned; + UInt32 m_DecryptedDataSize; + + bool m_CryptoMode; + UInt32 m_CryptoPos; + void FinishCryptoBlock() + { + if (m_CryptoMode) + while ((m_CryptoPos & 0xF) != 0) + { + m_CryptoPos++; + m_Position++; + } + } + +public: + UInt64 m_Position; + + HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit); + void Close(); + HRESULT GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage); + + void GetArchiveInfo(CInArchiveInfo &archiveInfo) const; + + void SeekInArchive(UInt64 position); + ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size); +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.cpp new file mode 100644 index 000000000..9216ae57b --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.cpp @@ -0,0 +1,55 @@ +// RarItem.cpp + +#include "StdAfx.h" + +#include "RarItem.h" + +namespace NArchive{ +namespace NRar{ + +bool CItem::IgnoreItem() const +{ + switch(HostOS) + { + case NHeader::NFile::kHostMSDOS: + case NHeader::NFile::kHostOS2: + case NHeader::NFile::kHostWin32: + return ((Attrib & NHeader::NFile::kLabelFileAttribute) != 0); + } + return false; +} + +bool CItem::IsDir() const +{ + if (GetDictSize() == NHeader::NFile::kDictDirectoryValue) + return true; + switch(HostOS) + { + case NHeader::NFile::kHostMSDOS: + case NHeader::NFile::kHostOS2: + case NHeader::NFile::kHostWin32: + if ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) + return true; + } + return false; +} + +UInt32 CItem::GetWinAttributes() const +{ + UInt32 winAttributes; + switch(HostOS) + { + case NHeader::NFile::kHostMSDOS: + case NHeader::NFile::kHostOS2: + case NHeader::NFile::kHostWin32: + winAttributes = Attrib; + break; + default: + winAttributes = 0; // must be converted from unix value; + } + if (IsDir()) + winAttributes |= NHeader::NFile::kWinFileDirectoryAttributeMask; + return winAttributes; +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.h b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.h new file mode 100644 index 000000000..4aa4d8667 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.h @@ -0,0 +1,79 @@ +// RarItem.h + +#ifndef __ARCHIVE_RAR_ITEM_H +#define __ARCHIVE_RAR_ITEM_H + +#include "Common/Types.h" +#include "Common/MyString.h" + +#include "RarHeader.h" + +namespace NArchive{ +namespace NRar{ + +struct CRarTime +{ + UInt32 DosTime; + Byte LowSecond; + Byte SubTime[3]; +}; + +struct CItem +{ + UInt64 Size; + UInt64 PackSize; + + CRarTime CTime; + CRarTime ATime; + CRarTime MTime; + + UInt32 FileCRC; + UInt32 Attrib; + + UInt16 Flags; + Byte HostOS; + Byte UnPackVersion; + Byte Method; + + bool CTimeDefined; + bool ATimeDefined; + + AString Name; + UString UnicodeName; + + Byte Salt[8]; + + bool IsEncrypted() const { return (Flags & NHeader::NFile::kEncrypted) != 0; } + bool IsSolid() const { return (Flags & NHeader::NFile::kSolid) != 0; } + bool IsCommented() const { return (Flags & NHeader::NFile::kComment) != 0; } + bool IsSplitBefore() const { return (Flags & NHeader::NFile::kSplitBefore) != 0; } + bool IsSplitAfter() const { return (Flags & NHeader::NFile::kSplitAfter) != 0; } + bool HasSalt() const { return (Flags & NHeader::NFile::kSalt) != 0; } + bool HasExtTime() const { return (Flags & NHeader::NFile::kExtTime) != 0; } + bool HasUnicodeName()const { return (Flags & NHeader::NFile::kUnicodeName) != 0; } + bool IsOldVersion() const { return (Flags & NHeader::NFile::kOldVersion) != 0; } + + UInt32 GetDictSize() const { return (Flags >> NHeader::NFile::kDictBitStart) & NHeader::NFile::kDictMask; } + bool IsDir() const; + bool IgnoreItem() const; + UInt32 GetWinAttributes() const; + + CItem(): CTimeDefined(false), ATimeDefined(false) {} +}; + +class CItemEx: public CItem +{ +public: + UInt64 Position; + UInt16 MainPartSize; + UInt16 CommentSize; + UInt16 AlignSize; + UInt64 GetFullSize() const { return MainPartSize + CommentSize + AlignSize + PackSize; }; + // DWORD GetHeaderWithCommentSize() const { return MainPartSize + CommentSize; }; + UInt64 GetCommentPosition() const { return Position + MainPartSize; }; + UInt64 GetDataPosition() const { return GetCommentPosition() + CommentSize + AlignSize; }; +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarRegister.cpp new file mode 100644 index 000000000..2bcf569ef --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarRegister.cpp @@ -0,0 +1,13 @@ +// RarRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "RarHandler.h" +static IInArchive *CreateArc() { return new NArchive::NRar::CHandler; } + +static CArcInfo g_ArcInfo = + { L"Rar", L"rar r00", 0, 3, {0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00}, 7, false, CreateArc, 0, }; + +REGISTER_ARC(Rar) diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp new file mode 100644 index 000000000..25194f915 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp @@ -0,0 +1,78 @@ +// RarVolumeInStream.cpp + +#include "StdAfx.h" + +#include "../../../../C/7zCrc.h" + +#include "RarVolumeInStream.h" + +namespace NArchive { +namespace NRar { + +void CFolderInStream::Init( + CObjectVector<CInArchive> *archives, + const CObjectVector<CItemEx> *items, + const CRefItem &refItem) +{ + _archives = archives; + _items = items; + _refItem = refItem; + _curIndex = 0; + CRCs.Clear(); + _fileIsOpen = false; +} + +HRESULT CFolderInStream::OpenStream() +{ + while (_curIndex < _refItem.NumItems) + { + const CItemEx &item = (*_items)[_refItem.ItemIndex + _curIndex]; + _stream.Attach((*_archives)[_refItem.VolumeIndex + _curIndex]. + CreateLimitedStream(item.GetDataPosition(), item.PackSize)); + _curIndex++; + _fileIsOpen = true; + _crc = CRC_INIT_VAL; + return S_OK; + } + return S_OK; +} + +HRESULT CFolderInStream::CloseStream() +{ + CRCs.Add(CRC_GET_DIGEST(_crc)); + _stream.Release(); + _fileIsOpen = false; + return S_OK; +} + +STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 realProcessedSize = 0; + while ((_curIndex < _refItem.NumItems || _fileIsOpen) && size > 0) + { + if (_fileIsOpen) + { + UInt32 localProcessedSize; + RINOK(_stream->Read( + ((Byte *)data) + realProcessedSize, size, &localProcessedSize)); + _crc = CrcUpdate(_crc, ((Byte *)data) + realProcessedSize, localProcessedSize); + if (localProcessedSize == 0) + { + RINOK(CloseStream()); + continue; + } + realProcessedSize += localProcessedSize; + size -= localProcessedSize; + break; + } + else + { + RINOK(OpenStream()); + } + } + if (processedSize != 0) + *processedSize = realProcessedSize; + return S_OK; +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.h b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.h new file mode 100644 index 000000000..78d95b10f --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.h @@ -0,0 +1,49 @@ +// RarVolumeInStream.h + +#ifndef __RAR_VOLUME_IN_STREAM_H +#define __RAR_VOLUME_IN_STREAM_H + +#include "../../IStream.h" +#include "RarIn.h" + +namespace NArchive { +namespace NRar { + +struct CRefItem +{ + int VolumeIndex; + int ItemIndex; + int NumItems; +}; + +class CFolderInStream: + public ISequentialInStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + +private: + CObjectVector<CInArchive> *_archives; + const CObjectVector<CItemEx> *_items; + CRefItem _refItem; + int _curIndex; + UInt32 _crc; + bool _fileIsOpen; + CMyComPtr<ISequentialInStream> _stream; + + HRESULT OpenStream(); + HRESULT CloseStream(); +public: + void Init(CObjectVector<CInArchive> *archives, + const CObjectVector<CItemEx> *items, + const CRefItem &refItem); + + CRecordVector<UInt32> CRCs; +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.cpp new file mode 100644 index 000000000..d0feea85c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.cpp @@ -0,0 +1,3 @@ +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.h new file mode 100644 index 000000000..e7fb6986d --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.h @@ -0,0 +1,8 @@ +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/MyWindows.h" + +#endif |