diff options
Diffstat (limited to 'CPP/7zip/Archive/Rar/RarHandler.cpp')
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Rar/RarHandler.cpp | 1287 |
1 files changed, 1102 insertions, 185 deletions
diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp index 5d072d34..c4adee41 100755..100644 --- a/CPP/7zip/Archive/Rar/RarHandler.cpp +++ b/CPP/7zip/Archive/Rar/RarHandler.cpp @@ -2,50 +2,104 @@ #include "StdAfx.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/StringConvert.h" +#include "../../../../C/CpuArch.h" -#include "Windows/PropVariant.h" -#include "Windows/PropVariantUtils.h" -#include "Windows/Time.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/UTFConvert.h" + +#include "../../../Windows/PropVariantUtils.h" +#include "../../../Windows/TimeUtils.h" #include "../../IPassword.h" #include "../../Common/CreateCoder.h" #include "../../Common/FilterCoder.h" +#include "../../Common/LimitedStreams.h" #include "../../Common/MethodId.h" #include "../../Common/ProgressUtils.h" +#include "../../Common/RegisterArc.h" +#include "../../Common/StreamUtils.h" #include "../../Compress/CopyCoder.h" #include "../../Crypto/Rar20Crypto.h" #include "../../Crypto/RarAes.h" +#include "../Common/FindSignature.h" #include "../Common/ItemNameUtils.h" #include "../Common/OutStreamWithCRC.h" #include "RarHandler.h" using namespace NWindows; -using namespace NTime; + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) namespace NArchive { namespace NRar { -static const wchar_t *kHostOS[] = +#define SIGNATURE { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 } + +static const Byte kMarker[NHeader::kMarkerSize] = SIGNATURE; + +bool CItem::IgnoreItem() const { - L"MS DOS", - L"OS/2", - L"Win32", - L"Unix", - L"Mac OS", - L"BeOS" -}; + 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; +} -static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]); +UInt32 CItem::GetWinAttrib() const +{ + UInt32 a; + switch (HostOS) + { + case NHeader::NFile::kHostMSDOS: + case NHeader::NFile::kHostOS2: + case NHeader::NFile::kHostWin32: + a = Attrib; + break; + default: + a = 0; // must be converted from unix value; + } + if (IsDir()) + a |= NHeader::NFile::kWinFileDirectoryAttributeMask; + return a; +} + +static const char *kHostOS[] = +{ + "MS DOS" + , "OS/2" + , "Win32" + , "Unix" + , "Mac OS" + , "BeOS" +}; -static const wchar_t *kUnknownOS = L"Unknown"; +static const char *kUnknownOS = "Unknown"; static const CUInt32PCharPair k_Flags[] = { @@ -61,75 +115,771 @@ static const CUInt32PCharPair k_Flags[] = { 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} +enum EErrorType +{ + k_ErrorType_OK, + k_ErrorType_Corrupted, + k_ErrorType_UnexpectedEnd, + k_ErrorType_DecryptionError }; -static const STATPROPSTG kArcProps[] = +class CInArchive { - { 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} + IInStream *m_Stream; + UInt64 m_StreamStartPosition; + CBuffer<wchar_t> _unicodeNameBuffer; + CByteBuffer _comment; + CByteBuffer m_FileHeaderData; + NHeader::NBlock::CBlock m_BlockHeader; + NCrypto::NRar29::CDecoder *m_RarAESSpec; + CMyComPtr<ICompressFilter> m_RarAES; + CBuffer<Byte> m_DecryptedData; + Byte *m_DecryptedDataAligned; + UInt32 m_DecryptedDataSize; + bool m_CryptoMode; + UInt32 m_CryptoPos; + + + HRESULT ReadBytesSpec(void *data, size_t *size); + bool ReadBytesAndTestSize(void *data, UInt32 size); + void ReadName(const Byte *p, unsigned nameSize, CItem &item); + bool ReadHeaderReal(const Byte *p, unsigned size, CItem &item); + + HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit); + + void AddToSeekValue(UInt64 addValue) + { + m_Position += addValue; + } + + void FinishCryptoBlock() + { + if (m_CryptoMode) + while ((m_CryptoPos & 0xF) != 0) + { + m_CryptoPos++; + m_Position++; + } + } + +public: + UInt64 m_Position; + CInArcInfo ArcInfo; + bool HeaderErrorWarning; + + HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit); + HRESULT GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPassword, + bool &filled, EErrorType &error); +}; + +static bool CheckHeaderCrc(const Byte *header, size_t headerSize) +{ + return Get16(header) == (UInt16)(CrcCalc(header + 2, headerSize - 2) & 0xFFFF); +} + +HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) +{ + HeaderErrorWarning = false; + m_CryptoMode = false; + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition)); + RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileSize)); + RINOK(stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL)); + m_Position = m_StreamStartPosition; + + UInt64 arcStartPos = m_StreamStartPosition; + { + Byte marker[NHeader::kMarkerSize]; + RINOK(ReadStream_FALSE(stream, marker, NHeader::kMarkerSize)); + if (memcmp(marker, kMarker, NHeader::kMarkerSize) == 0) + m_Position += NHeader::kMarkerSize; + else + { + if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) + return S_FALSE; + RINOK(stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL)); + RINOK(FindSignatureInStream(stream, 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); + + ArcInfo.EncryptVersion = 0; + ArcInfo.Flags = Get16(buf + 3); + + UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize; + if (ArcInfo.IsThereEncryptVer()) + { + if (blockSize <= headerSize) + return S_FALSE; + RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1)); + AddToSeekValue(1); + ArcInfo.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize]; + headerSize += 1; + } + if (blockSize < headerSize + || buf[2] != NHeader::NBlockType::kArchiveHeader + || !CheckHeaderCrc(buf, headerSize)) + return S_FALSE; + + size_t commentSize = blockSize - headerSize; + _comment.Alloc(commentSize); + RINOK(ReadStream_FALSE(stream, _comment, commentSize)); + AddToSeekValue(commentSize); + m_Stream = stream; + ArcInfo.StartPos = arcStartPos; + return S_OK; +} + +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; +} + +static void DecodeUnicodeFileName(const Byte *name, const Byte *encName, + unsigned encSize, wchar_t *unicodeName, unsigned maxDecSize) +{ + unsigned encPos = 0; + unsigned decPos = 0; + unsigned 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: + { + unsigned len = encName[encPos++]; + if (len & 0x80) + { + Byte correction = encName[encPos++]; + for (len = (len & 0x7f) + 2; + len > 0 && decPos < maxDecSize; len--, decPos++) + unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + (highByte << 8)); + } + else + for (len += 2; len > 0 && decPos < maxDecSize; len--, decPos++) + unicodeName[decPos] = name[decPos]; + } + break; + } + flags <<= 2; + flagBits -= 2; + } + unicodeName[decPos < maxDecSize ? decPos : maxDecSize - 1] = 0; +} + +void CInArchive::ReadName(const Byte *p, unsigned nameSize, CItem &item) +{ + item.UnicodeName.Empty(); + if (nameSize > 0) + { + unsigned i; + for (i = 0; i < nameSize && p[i] != 0; i++); + item.Name.SetFrom((const char *)p, i); + + if (item.HasUnicodeName()) + { + if (i < nameSize) + { + i++; + unsigned uNameSizeMax = MyMin(nameSize, (unsigned)0x400); + _unicodeNameBuffer.AllocAtLeast(uNameSizeMax + 1); + DecodeUnicodeFileName(p, p + i, nameSize - i, _unicodeNameBuffer, uNameSizeMax); + item.UnicodeName = _unicodeNameBuffer; + } + else if (!ConvertUTF8ToUnicode(item.Name, item.UnicodeName)) + item.UnicodeName.Empty(); + } + } + else + item.Name.Empty(); +} + +static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime) +{ + rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0); + unsigned numDigits = (mask & 3); + rarTime.SubTime[0] = + rarTime.SubTime[1] = + rarTime.SubTime[2] = 0; + if (numDigits > size) + return -1; + for (unsigned i = 0; i < numDigits; i++) + rarTime.SubTime[3 - numDigits + i] = p[i]; + return numDigits; +} + +#define READ_TIME(_mask_, _ttt_) \ + { int size2 = ReadTime(p, size, _mask_, _ttt_); if (size2 < 0) return false; p += size2, size -= size2; } + +#define READ_TIME_2(_mask_, _def_, _ttt_) \ + _def_ = ((_mask_ & 8) != 0); if (_def_) \ + { if (size < 4) return false; \ + _ttt_ ## .DosTime = Get32(p); p += 4; size -= 4; \ + READ_TIME(_mask_, _ttt_); } \ + +bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item) +{ + const Byte *pStart = p; + + item.Clear(); + item.Flags = m_BlockHeader.Flags; + + const unsigned kFileHeaderSize = 25; + + if (size < kFileHeaderSize) + return false; + + item.PackSize = Get32(p); + item.Size = Get32(p + 4); + item.HostOS = p[8]; + item.FileCRC = Get32(p + 9); + item.MTime.DosTime = Get32(p + 13); + item.UnPackVersion = p[17]; + item.Method = p[18]; + unsigned nameSize = Get16(p + 19); + item.Attrib = Get32(p + 21); + + item.MTime.LowSecond = 0; + item.MTime.SubTime[0] = + item.MTime.SubTime[1] = + item.MTime.SubTime[2] = 0; + + p += kFileHeaderSize; + size -= kFileHeaderSize; + if ((item.Flags & NHeader::NFile::kSize64Bits) != 0) + { + if (size < 8) + return false; + item.PackSize |= ((UInt64)Get32(p) << 32); + item.Size |= ((UInt64)Get32(p + 4) << 32); + p += 8; + size -= 8; + } + if (nameSize > size) + return false; + ReadName(p, nameSize, item); + p += nameSize; + size -= nameSize; + + /* + // It was commented, since it's difficult to support alt Streams for solid archives. + if (m_BlockHeader.Type == NHeader::NBlockType::kSubBlock) + { + if (item.HasSalt()) + { + if (size < sizeof(item.Salt)) + return false; + size -= sizeof(item.Salt); + p += sizeof(item.Salt); + } + if (item.Name == "ACL" && size == 0) + { + item.IsAltStream = true; + item.Name.Empty(); + item.UnicodeName = L".ACL"; + } + else if (item.Name == "STM" && size != 0 && (size & 1) == 0) + { + item.IsAltStream = true; + item.Name.Empty(); + for (UInt32 i = 0; i < size; i += 2) + { + wchar_t c = Get16(p + i); + if (c == 0) + return false; + item.UnicodeName += c; + } + } + } + */ + + if (item.HasSalt()) + { + if (size < sizeof(item.Salt)) + return false; + for (unsigned i = 0; i < sizeof(item.Salt); i++) + item.Salt[i] = p[i]; + p += sizeof(item.Salt); + size -= sizeof(item.Salt); + } + + // some rar archives have HasExtTime flag without field. + if (size >= 2 && item.HasExtTime()) + { + Byte aMask = (Byte)(p[0] >> 4); + Byte b = p[1]; + p += 2; + size -= 2; + Byte mMask = (Byte)(b >> 4); + Byte cMask = (Byte)(b & 0xF); + if ((mMask & 8) != 0) + { + READ_TIME(mMask, item.MTime); + } + READ_TIME_2(cMask, item.CTimeDefined, item.CTime); + READ_TIME_2(aMask, item.ATimeDefined, item.ATime); + } + + unsigned fileHeaderWithNameSize = 7 + (unsigned)(p - pStart); + + 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); + + // return (m_BlockHeader.Type != NHeader::NBlockType::kSubBlock || item.IsAltStream); + return true; +} + +HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPassword, bool &filled, EErrorType &error) +{ + filled = false; + error = k_ErrorType_OK; + for (;;) + { + m_Stream->Seek(m_Position, STREAM_SEEK_SET, NULL); + ArcInfo.EndPos = m_Position; + if (!m_CryptoMode && (ArcInfo.Flags & + NHeader::NArchive::kBlockHeadersAreEncrypted) != 0) + { + m_CryptoMode = false; + if (getTextPassword == 0) + { + error = k_ErrorType_DecryptionError; + return S_OK; // return S_FALSE; + } + if (!m_RarAES) + { + m_RarAESSpec = new NCrypto::NRar29::CDecoder; + m_RarAES = m_RarAESSpec; + } + m_RarAESSpec->SetRar350Mode(ArcInfo.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)) + unsigned len = 0; + if (password) + len = MyStringLen((BSTR)password); + CByteBuffer buffer(len * 2); + for (unsigned i = 0; i < len; i++) + { + wchar_t c = password[i]; + ((Byte *)buffer)[i * 2] = (Byte)c; + ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); + } + + RINOK(m_RarAESSpec->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size())); + + const UInt32 kDecryptedBufferSize = (1 << 12); + if (m_DecryptedData.Size() == 0) + { + const UInt32 kAlign = 16; + m_DecryptedData.Alloc(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.AllocAtLeast(7); + size_t processed = 7; + RINOK(ReadBytesSpec((Byte *)m_FileHeaderData, &processed)); + if (processed != 7) + { + if (processed != 0) + error = k_ErrorType_UnexpectedEnd; + ArcInfo.EndPos = m_Position + processed; // test it + return S_OK; + } + + const Byte *p = m_FileHeaderData; + m_BlockHeader.CRC = Get16(p + 0); + m_BlockHeader.Type = p[2]; + m_BlockHeader.Flags = Get16(p + 3); + m_BlockHeader.HeadSize = Get16(p + 5); + + if (m_BlockHeader.HeadSize < 7) + { + error = k_ErrorType_Corrupted; + return S_OK; + // ThrowExceptionWithCode(CInArchiveException::kIncorrectArchive); + } + + if (m_BlockHeader.Type < NHeader::NBlockType::kFileHeader || + m_BlockHeader.Type > NHeader::NBlockType::kEndOfArchive) + { + error = m_CryptoMode ? + k_ErrorType_DecryptionError : + k_ErrorType_Corrupted; + return S_OK; + } + + if (m_BlockHeader.Type == NHeader::NBlockType::kEndOfArchive) + { + bool footerError = false; + + unsigned expectHeadLen = 7; + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) + expectHeadLen += 4; + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) + expectHeadLen += 2; + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_RevSpace) + expectHeadLen += 7; + + // rar 5.0 beta 1 writes incorrect RevSpace and headSize + + if (m_BlockHeader.HeadSize < expectHeadLen) + HeaderErrorWarning = true; + + if (m_BlockHeader.HeadSize > 7) + { + /* We suppose that EndOfArchive header is always small. + It's only 20 bytes for multivolume + Fix the limit, if larger footers are possible */ + if (m_BlockHeader.HeadSize > (1 << 8)) + footerError = true; + else + { + if (m_FileHeaderData.Size() < m_BlockHeader.HeadSize) + m_FileHeaderData.ChangeSize_KeepData(m_BlockHeader.HeadSize, 7); + UInt32 afterSize = m_BlockHeader.HeadSize - 7; + if (ReadBytesAndTestSize(m_FileHeaderData + 7, afterSize)) + processed += afterSize; + else + { + if (!m_CryptoMode) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + footerError = true; + } + } + } + + if (footerError || !CheckHeaderCrc(m_FileHeaderData, m_BlockHeader.HeadSize)) + { + error = m_CryptoMode ? + k_ErrorType_DecryptionError : + k_ErrorType_Corrupted; + } + else + { + ArcInfo.EndFlags = m_BlockHeader.Flags; + UInt32 offset = 7; + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) + { + if (processed < offset + 4) + error = k_ErrorType_Corrupted; + else + ArcInfo.DataCRC = Get32(m_FileHeaderData + offset); + offset += 4; + } + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) + { + if (processed < offset + 2) + error = k_ErrorType_Corrupted; + ArcInfo.VolNumber = (UInt32)Get16(m_FileHeaderData + offset); + } + } + m_Position += processed; + FinishCryptoBlock(); + ArcInfo.EndPos = m_Position; + return S_OK; + } + + if (m_BlockHeader.Type == NHeader::NBlockType::kFileHeader + /* || m_BlockHeader.Type == NHeader::NBlockType::kSubBlock */) + { + if (m_FileHeaderData.Size() < m_BlockHeader.HeadSize) + m_FileHeaderData.ChangeSize_KeepData(m_BlockHeader.HeadSize, 7); + // m_CurData = (Byte *)m_FileHeaderData; + // m_PosLimit = m_BlockHeader.HeadSize; + if (!ReadBytesAndTestSize(m_FileHeaderData + 7, m_BlockHeader.HeadSize - 7)) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + + bool okItem = ReadHeaderReal(m_FileHeaderData + 7, m_BlockHeader.HeadSize - 7, item); + if (okItem) + { + if (!CheckHeaderCrc(m_FileHeaderData, m_BlockHeader.HeadSize - item.CommentSize)) + { + error = k_ErrorType_Corrupted; // ThrowExceptionWithCode(CInArchiveException::kFileHeaderCRCError); + return S_OK; + } + filled = true; + } + + FinishCryptoBlock(); + m_CryptoMode = false; + // Move Position to compressed Data; + m_Stream->Seek(m_Position, STREAM_SEEK_SET, NULL); + AddToSeekValue(item.PackSize); // m_Position points to next header; + // if (okItem) + return S_OK; + /* + else + continue; + */ + } + if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 10)) + { + error = k_ErrorType_DecryptionError; + return S_OK; + } + if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0) + { + if (m_FileHeaderData.Size() < 7 + 4) + m_FileHeaderData.ChangeSize_KeepData(7 + 4, 7); + if (!ReadBytesAndTestSize(m_FileHeaderData + 7, 4)) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + UInt32 dataSize = Get32(m_FileHeaderData + 7); + AddToSeekValue(dataSize); + if (m_CryptoMode && dataSize > (1 << 27)) + { + error = k_ErrorType_DecryptionError; + return S_OK; + } + m_CryptoPos = m_BlockHeader.HeadSize; + } + else + m_CryptoPos = 0; + + { + UInt64 newPos = m_Position + m_BlockHeader.HeadSize; + if (newPos > ArcInfo.FileSize) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + } + AddToSeekValue(m_BlockHeader.HeadSize); + FinishCryptoBlock(); + m_CryptoMode = false; + } +} + + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidAttrib, + + kpidEncrypted, + kpidSolid, + kpidCommented, + kpidSplitBefore, + kpidSplitAfter, + kpidCRC, + kpidHostOS, + kpidMethod, + kpidUnpackVer +}; + +static const Byte kArcProps[] = +{ + kpidTotalPhySize, + kpidCharacts, + kpidSolid, + kpidNumBlocks, + // kpidEncrypted, + kpidIsVolume, + kpidVolumeIndex, + kpidNumVolumes + // kpidCommented }; IMP_IInArchive_Props IMP_IInArchive_ArcProps -UInt64 CHandler::GetPackSize(int refIndex) const +UInt64 CHandler::GetPackSize(unsigned refIndex) const { const CRefItem &refItem = _refItems[refIndex]; UInt64 totalPackSize = 0; - for (int i = 0; i < refItem.NumItems; i++) + for (unsigned i = 0; i < refItem.NumItems; i++) totalPackSize += _items[refItem.ItemIndex + i].PackSize; return totalPackSize; } +bool CHandler::IsSolid(unsigned refIndex) const +{ + const CItem &item = _items[_refItems[refIndex].ItemIndex]; + if (item.UnPackVersion < 20) + { + if (_arcInfo.IsSolid()) + return (refIndex > 0); + return false; + } + return item.IsSolid(); +} + STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) + 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 kpidVolumeIndex: if (_arcInfo.Is_VolNumber_Defined()) prop = (UInt32)_arcInfo.VolNumber; break; + case kpidSolid: prop = _arcInfo.IsSolid(); break; + case kpidCharacts: + { + AString s = FlagsToString(k_Flags, ARRAY_SIZE(k_Flags), _arcInfo.Flags); + // FLAGS_TO_PROP(k_Flags, _arcInfo.Flags, prop); + if (_arcInfo.Is_DataCRC_Defined()) + { + if (!s.IsEmpty()) + s += ' '; + s += "VolCRC"; + } + prop = s; + break; + } + // case kpidEncrypted: prop = _arcInfo.IsEncrypted(); break; // it's for encrypted names. + case kpidIsVolume: prop = _arcInfo.IsVolume(); break; + case kpidNumVolumes: prop = (UInt32)_arcs.Size(); break; + case kpidOffset: if (_arcs.Size() == 1 && _arcInfo.StartPos != 0) prop = _arcInfo.StartPos; break; + + case kpidTotalPhySize: + { + if (_arcs.Size() > 1) + { + UInt64 sum = 0; + FOR_VECTOR (v, _arcs) + sum += _arcs[v].PhySize; + prop = sum; + } + break; + } + + case kpidPhySize: + { + if (_arcs.Size() != 0) + prop = _arcInfo.GetPhySize(); + break; + } + + // case kpidCommented: prop = _arcInfo.IsCommented(); break; + case kpidNumBlocks: { UInt32 numBlocks = 0; - for (int i = 0; i < _refItems.Size(); i++) + FOR_VECTOR (i, _refItems) if (!IsSolid(i)) numBlocks++; prop = (UInt32)numBlocks; break; } - case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + + // case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + + case kpidErrorFlags: + { + UInt32 v = _errorFlags; + if (!_isArc) + v |= kpv_ErrorFlags_IsNotArc; + prop = v; + break; + } + + case kpidWarningFlags: + { + if (_warningFlags != 0) + prop = _warningFlags; + break; + } + + case kpidExtension: + if (_arcs.Size() == 1) + { + if (_arcInfo.Is_VolNumber_Defined()) + { + char sz[16]; + ConvertUInt32ToString((UInt32)_arcInfo.VolNumber + 1, sz); + unsigned len = MyStringLen(sz); + AString s = "part"; + for (; len < 2; len++) + s += '0'; + s += sz; + s += ".rar"; + prop = s; + } + } + break; } prop.Detach(value); return S_OK; @@ -144,7 +894,7 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result) { - if (!DosTimeToFileTime(rarTime.DosTime, result)) + if (!NTime::DosTimeToFileTime(rarTime.DosTime, result)) return false; UInt64 value = (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime; value += (UInt64)rarTime.LowSecond * 10000000; @@ -156,7 +906,7 @@ static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result) return true; } -static void RarTimeToProp(const CRarTime &rarTime, NWindows::NCOM::CPropVariant &prop) +static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop) { FILETIME localFileTime, utcFileTime; if (RarTimeToFileTime(rarTime, localFileTime)) @@ -169,22 +919,28 @@ static void RarTimeToProp(const CRarTime &rarTime, NWindows::NCOM::CPropVariant prop = utcFileTime; } -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; const CRefItem &refItem = _refItems[index]; - const CItemEx &item = _items[refItem.ItemIndex]; + const CItem &item = _items[refItem.ItemIndex]; + /* + const CItem *mainItem = &item; + if (item.BaseFileIndex >= 0) + mainItem = &_items[_refItems[item.BaseFileIndex].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); + if (item.BaseFileIndex >= 0) + u = mainItem->GetName(); + u += item.GetName(); + */ + prop = (const wchar_t *)NItemName::WinNameToOSName(item.GetName()); break; } case kpidIsDir: prop = item.IsDir(); break; @@ -193,7 +949,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va 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 kpidAttrib: prop = item.GetWinAttrib(); break; case kpidEncrypted: prop = item.IsEncrypted(); break; case kpidSolid: prop = IsSolid(index); break; case kpidCommented: prop = item.IsCommented(); break; @@ -201,43 +957,44 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va case kpidSplitAfter: prop = _items[refItem.ItemIndex + refItem.NumItems - 1].IsSplitAfter(); break; case kpidCRC: { - const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1]; + const CItem &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')) + char temp[16]; + char *s = temp; + if (item.Method >= (Byte)'0' && item.Method <= (Byte)'5') { - method = L"m"; - wchar_t temp[32]; - ConvertUInt64ToString(item.Method - Byte('0'), temp); - method += temp; + *s++ = 'm'; + *s++ = (char)item.Method; if (!item.IsDir()) { - method += L":"; - ConvertUInt64ToString(16 + item.GetDictSize(), temp); - method += temp; + *s++ = ':'; + ConvertUInt32ToString(16 + item.GetDictSize(), s); } } else - { - wchar_t temp[32]; - ConvertUInt64ToString(item.Method, temp); - method += temp; - } - prop = method; + ConvertUInt32ToString(item.Method, s); + s += MyStringLen(s); + *s = 0; + prop = s; break; } - case kpidHostOS: prop = (item.HostOS < kNumHostOSes) ? (kHostOS[item.HostOS]) : kUnknownOS; break; + case kpidHostOS: prop = (item.HostOS < ARRAY_SIZE(kHostOS)) ? kHostOS[item.HostOS] : kUnknownOS; break; } prop.Detach(value); return S_OK; COM_TRY_END } +static bool IsDigit(wchar_t c) +{ + return c >= L'0' && c <= L'9'; +} + class CVolumeName { bool _first; @@ -256,23 +1013,23 @@ public: UString basePart = name; if (dotPos >= 0) { - UString ext = name.Mid(dotPos + 1); - if (ext.CompareNoCase(L"rar") == 0) + UString ext = name.Ptr(dotPos + 1); + if (ext.IsEqualToNoCase(L"rar")) { - _afterPart = name.Mid(dotPos); + _afterPart = name.Ptr(dotPos); basePart = name.Left(dotPos); } - else if (ext.CompareNoCase(L"exe") == 0) + else if (ext.IsEqualToNoCase(L"exe")) { _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) + if (ext.IsEqualToNoCase(L"000") || + ext.IsEqualToNoCase(L"001") || + ext.IsEqualToNoCase(L"r00") || + ext.IsEqualToNoCase(L"r01")) { _afterPart.Empty(); _first = false; @@ -291,46 +1048,49 @@ public: 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 + if (basePart.IsEmpty()) return false; - _unchangedPart = basePart.Left(basePart.Length() - numLetters); - _changedPart = basePart.Right(numLetters); + unsigned i = basePart.Len(); + do + if (!IsDigit(basePart[i - 1])) + break; + while (--i); + _unchangedPart = basePart.Left(i); + _changedPart = basePart.Ptr(i); return true; } + /* + void MakeBeforeFirstName() + { + unsigned len = _changedPart.Len(); + _changedPart.Empty(); + for (unsigned i = 0; i < len; i++) + _changedPart += L'0'; + } + */ + UString GetNextName() { UString newName; if (_newStyle || !_first) { - int i; - int numLetters = _changedPart.Length(); - for (i = numLetters - 1; i >= 0; i--) + for (int i = (int)_changedPart.Len() - 1; i >= 0; i--) { wchar_t c = _changedPart[i]; if (c == L'9') { c = L'0'; - newName = c + newName; + newName.InsertAtFront(c); if (i == 0) - newName = UString(L'1') + newName; + newName.InsertAtFront(L'1'); continue; } c++; newName = UString(c) + newName; i--; for (; i >= 0; i--) - newName = _changedPart[i] + newName; + newName.InsertAtFront(_changedPart[i]); break; } _changedPart = newName; @@ -360,17 +1120,18 @@ HRESULT CHandler::Open2(IInStream *stream, openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); } + CInArchive archive; for (;;) { CMyComPtr<IInStream> inStream; - if (!_archives.IsEmpty()) + if (!_arcs.IsEmpty()) { if (!openVolumeCallback) break; - if (_archives.Size() == 1) + if (_arcs.Size() == 1) { - if (!_archiveInfo.IsVolume()) + if (!_arcInfo.IsVolume()) break; UString baseName; { @@ -380,7 +1141,14 @@ HRESULT CHandler::Open2(IInStream *stream, break; baseName = prop.bstrVal; } - seqName.InitName(baseName, _archiveInfo.HaveNewVolumeName()); + if (!seqName.InitName(baseName, _arcInfo.HaveNewVolumeName())) + break; + /* + if (_arcInfo.HaveNewVolumeName() && !_arcInfo.IsFirstVolume()) + { + seqName.MakeBeforeFirstName(); + } + */ } UString fullName = seqName.GetNextName(); @@ -389,47 +1157,54 @@ HRESULT CHandler::Open2(IInStream *stream, break; if (result != S_OK) return result; - if (!stream) + if (!inStream) break; } else inStream = stream; UInt64 endPos = 0; - RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); - RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(inStream->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; + _isArc = true; + CItem item; for (;;) { if (archive.m_Position > endPos) { - AddErrorMessage("Unexpected end of archive"); + _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; break; } - bool decryptionError; - AString errorMessageLoc; - HRESULT result = archive.GetNextItem(item, getTextPassword, decryptionError, errorMessageLoc); - if (errorMessageLoc) - AddErrorMessage(errorMessageLoc); - if (result == S_FALSE) + EErrorType error; + // bool decryptionError; + // AString errorMessageLoc; + bool filled; + HRESULT result = archive.GetNextItem(item, getTextPassword, filled, error); + if (error != k_ErrorType_OK) + { + if (error == k_ErrorType_UnexpectedEnd) + _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; + else if (error == k_ErrorType_Corrupted) + _errorFlags |= kpv_ErrorFlags_HeadersError; + else if (error == k_ErrorType_DecryptionError) + _errorFlags |= kpv_ErrorFlags_EncryptedHeadersError; + + // AddErrorMessage(errorMessageLoc); + } + RINOK(result); + if (!filled) { - if (decryptionError && _items.IsEmpty()) + if (error == k_ErrorType_DecryptionError && _items.IsEmpty()) return S_FALSE; break; } - RINOK(result); if (item.IgnoreItem()) continue; @@ -448,7 +1223,7 @@ HRESULT CHandler::Open2(IInStream *stream, CRefItem refItem; refItem.ItemIndex = _items.Size(); refItem.NumItems = 1; - refItem.VolumeIndex = _archives.Size(); + refItem.VolumeIndex = _arcs.Size(); _refItems.Add(refItem); } _items.Add(item); @@ -459,10 +1234,38 @@ HRESULT CHandler::Open2(IInStream *stream, RINOK(openCallback->SetCompleted(&numFiles, &numBytes)); } } + + if (archive.HeaderErrorWarning) + _warningFlags |= kpv_ErrorFlags_HeadersError; + + /* + if (archive.m_Position < endPos) + _warningFlags |= kpv_ErrorFlags_DataAfterEnd; + */ + if (_arcs.IsEmpty()) + _arcInfo = archive.ArcInfo; + // _arcInfo.EndPos = archive.EndPos; + curBytes += endPos; - _archives.Add(archive); + { + CArc &arc = _arcs.AddNew(); + arc.PhySize = archive.ArcInfo.GetPhySize(); + arc.Stream = inStream; + } } } + + /* + int baseFileIndex = -1; + for (int i = 0; i < _refItems.Size(); i++) + { + CItem &item = _items[_refItems[i].ItemIndex]; + if (item.IsAltStream) + item.BaseFileIndex = baseFileIndex; + else + baseFileIndex = i; + } + */ return S_OK; } @@ -472,25 +1275,31 @@ STDMETHODIMP CHandler::Open(IInStream *stream, { COM_TRY_BEGIN Close(); - try + // try { HRESULT res = Open2(stream, maxCheckStartPosition, openCallback); + /* if (res != S_OK) Close(); + */ + return res; } - catch(const CInArchiveException &) { Close(); return S_FALSE; } - catch(...) { Close(); throw; } + // catch(const CInArchiveException &) { Close(); return S_FALSE; } + // catch(...) { Close(); throw; } COM_TRY_END } STDMETHODIMP CHandler::Close() { COM_TRY_BEGIN - _errorMessage.Empty(); + // _errorMessage.Empty(); + _errorFlags = 0; + _warningFlags = 0; + _isArc = false; _refItems.Clear(); _items.Clear(); - _archives.Clear(); + _arcs.Clear(); return S_OK; COM_TRY_END } @@ -502,6 +1311,111 @@ struct CMethodItem }; +class CFolderInStream: + public ISequentialInStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + +private: + const CObjectVector<CArc> *_archives; + const CObjectVector<CItem> *_items; + CRefItem _refItem; + unsigned _curIndex; + UInt32 _crc; + bool _fileIsOpen; + CMyComPtr<ISequentialInStream> _stream; + + HRESULT OpenStream(); + HRESULT CloseStream(); +public: + void Init(const CObjectVector<CArc> *archives, + const CObjectVector<CItem> *items, + const CRefItem &refItem); + + CRecordVector<UInt32> CRCs; +}; + + +ISequentialInStream* CArc::CreateLimitedStream(UInt64 offset, UInt64 size) const +{ + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream(streamSpec); + Stream->Seek(offset, STREAM_SEEK_SET, NULL); + streamSpec->SetStream(Stream); + streamSpec->Init(size); + return inStream.Detach(); +} + +void CFolderInStream::Init( + const CObjectVector<CArc> *archives, + const CObjectVector<CItem> *items, + const CRefItem &refItem) +{ + _archives = archives; + _items = items; + _refItem = refItem; + _curIndex = 0; + CRCs.Clear(); + _fileIsOpen = false; +} + +HRESULT CFolderInStream::OpenStream() +{ + while (_curIndex < _refItem.NumItems) + { + const CItem &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; +} + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { @@ -511,23 +1425,23 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, // censoredTotalPacked = 0, importantTotalUnPacked = 0; // importantTotalPacked = 0; - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _refItems.Size(); if (numItems == 0) return S_OK; - int lastIndex = 0; + unsigned lastIndex = 0; CRecordVector<int> importantIndexes; CRecordVector<bool> extractStatuses; for (UInt32 t = 0; t < numItems; t++) { - int index = allFilesMode ? t : indices[t]; + unsigned index = allFilesMode ? t : indices[t]; const CRefItem &refItem = _refItems[index]; - const CItemEx &item = _items[refItem.ItemIndex]; + const CItem &item = _items[refItem.ItemIndex]; censoredTotalUnPacked += item.Size; // censoredTotalPacked += item.PackSize; - int j; + unsigned j; for (j = lastIndex; j <= index; j++) // if (!_items[_refItems[j].ItemIndex].IsSolid()) if (!IsSolid(j)) @@ -535,9 +1449,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, for (j = lastIndex; j <= index; j++) { const CRefItem &refItem = _refItems[j]; - const CItemEx &item = _items[refItem.ItemIndex]; + const CItem &item = _items[refItem.ItemIndex]; - // const CItemEx &item = _items[j]; + // const CItem &item = _items[j]; importantTotalUnPacked += item.Size; // importantTotalPacked += item.PackSize; @@ -573,7 +1487,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, lps->Init(extractCallback, false); bool solidStart = true; - for (int i = 0; i < importantIndexes.Size(); i++, + for (unsigned i = 0; i < importantIndexes.Size(); i++, currentImportantTotalUnPacked += currentUnPackSize, currentImportantTotalPacked += currentPackSize) { @@ -593,7 +1507,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt32 index = importantIndexes[i]; const CRefItem &refItem = _refItems[index]; - const CItemEx &item = _items[refItem.ItemIndex]; + const CItem &item = _items[refItem.ItemIndex]; currentUnPackSize = item.Size; @@ -617,7 +1531,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (i < importantIndexes.Size() - 1) { // const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]]; - // const CItemEx &nextItemInfo = _items[nextRefItem.ItemIndex]; + // const CItem &nextItemInfo = _items[nextRefItem.ItemIndex]; // mustBeProcessedAnywhere = nextItemInfo.IsSolid(); mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]); } @@ -637,14 +1551,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, realOutStream.Release(); /* - for (int partIndex = 0; partIndex < 1; partIndex++) + for (unsigned partIndex = 0; partIndex < 1; partIndex++) { CMyComPtr<ISequentialInStream> inStream; // item redefinition - const CItemEx &item = _items[refItem.ItemIndex + partIndex]; + const CItem &item = _items[refItem.ItemIndex + partIndex]; - NArchive::NRar::CInArchive &archive = _archives[refItem.VolumeIndex + partIndex]; + CInArchive &archive = _arcs[refItem.VolumeIndex + partIndex]; inStream.Attach(archive.CreateLimitedStream(item.GetDataPosition(), item.PackSize)); @@ -655,7 +1569,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, folderInStream = folderInStreamSpec; } - folderInStreamSpec->Init(&_archives, &_items, refItem); + folderInStreamSpec->Init(&_arcs, &_items, refItem); UInt64 packSize = currentPackSize; @@ -694,7 +1608,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, else { outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); continue; } RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, @@ -708,25 +1622,25 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, 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++) + UString unicodePassword; + unsigned len = 0; + if (password) + len = MyStringLen((BSTR)password); + CByteBuffer buffer(len * 2); + for (unsigned i = 0; i < len; i++) { - wchar_t c = unicodePassword[i]; + wchar_t c = password[i]; ((Byte *)buffer)[i * 2] = (Byte)c; ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); } - RINOK(cryptoSetPassword->CryptoSetPassword( - (const Byte *)buffer, sizeInBytes)); + RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size())); } else { - AString oemPassword = UnicodeStringToMultiByte( - (const wchar_t *)password, CP_OEMCP); - RINOK(cryptoSetPassword->CryptoSetPassword( - (const Byte *)(const char *)oemPassword, oemPassword.Length())); + AString oemPassword; + if (password) + oemPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP); + RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len())); } } else @@ -754,15 +1668,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, case '4': case '5': { - /* - if (item.UnPackVersion >= 29) - { - outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); - continue; - } - */ - int m; + unsigned m; for (m = 0; m < methodItems.Size(); m++) if (methodItems[m].RarUnPackVersion == item.UnPackVersion) break; @@ -772,7 +1678,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, mi.RarUnPackVersion = item.UnPackVersion; mi.Coder.Release(); - if (item.UnPackVersion <= 30) + if (item.UnPackVersion <= 40) { UInt32 methodID = 0x040300; if (item.UnPackVersion < 20) @@ -787,7 +1693,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (mi.Coder == 0) { outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); continue; } @@ -814,7 +1720,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } default: outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); continue; } HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &item.Size, progress); @@ -834,7 +1740,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, !item.IsSplitBefore() && !item.IsSplitAfter()) */ { - const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1]; + const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1]; bool crcOK = outStreamSpec->GetCRC() == lastItem.FileCRC; outStream.Release(); RINOK(extractCallback->SetOperationResult(crcOK ? @@ -845,9 +1751,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, else { bool crcOK = true; - for (int partIndex = 0; partIndex < refItem.NumItems; partIndex++) + for (unsigned partIndex = 0; partIndex < refItem.NumItems; partIndex++) { - const CItemEx &item = _items[refItem.ItemIndex + partIndex]; + const CItem &item = _items[refItem.ItemIndex + partIndex]; if (item.FileCRC != folderInStreamSpec->CRCs[partIndex]) { crcOK = false; @@ -866,4 +1772,15 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, IMPL_ISetCompressCodecsInfo +IMP_CreateArcIn + +static CArcInfo g_ArcInfo = + { "Rar", "rar r00", 0, 3, + NHeader::kMarkerSize, SIGNATURE, + 0, + NArcInfoFlags::kFindSignature, + CreateArc }; + +REGISTER_ARC(Rar) + }} |