diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2014-11-23 03:00:00 +0300 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:51 +0300 |
commit | f08f4dcc3c02464c17753b3feafcfe5243b9e236 (patch) | |
tree | b0e1b15bc5368d92dff422e8ec0818564a2b00b8 /CPP/7zip/Archive/Rar | |
parent | 83f8ddcc5b2161e1e3c49666265257fca8aeb12c (diff) |
9.349.34
Diffstat (limited to 'CPP/7zip/Archive/Rar')
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Rar/RarHandler.cpp | 1287 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Rar/RarHandler.h | 79 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Rar/RarHeader.cpp | 21 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Rar/RarHeader.h | 69 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Rar/RarIn.cpp | 478 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Rar/RarIn.h | 123 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Rar/RarItem.cpp | 55 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Rar/RarItem.h | 40 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Rar/RarRegister.cpp | 13 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Rar/RarVolumeInStream.cpp | 78 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Rar/RarVolumeInStream.h | 49 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Rar/StdAfx.cpp | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Rar/StdAfx.h | 2 |
13 files changed, 1227 insertions, 1067 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) + }} diff --git a/CPP/7zip/Archive/Rar/RarHandler.h b/CPP/7zip/Archive/Rar/RarHandler.h index 79266827..81191be9 100755..100644 --- a/CPP/7zip/Archive/Rar/RarHandler.h +++ b/CPP/7zip/Archive/Rar/RarHandler.h @@ -7,44 +7,85 @@ #include "../../Common/CreateCoder.h" -#include "RarIn.h" -#include "RarVolumeInStream.h" +#include "RarItem.h" namespace NArchive { namespace NRar { +struct CInArcInfo +{ + UInt32 Flags; + Byte EncryptVersion; + + UInt64 StartPos; + UInt64 EndPos; + UInt64 FileSize; + + UInt32 EndFlags; + UInt32 VolNumber; + UInt32 DataCRC; + + CInArcInfo(): EndFlags(0) {} + + UInt64 GetPhySize() const { return EndPos - StartPos; } + + 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 IsFirstVolume() const { return (Flags & NHeader::NArchive::kFirstVolume) != 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); } + + bool Is_VolNumber_Defined() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) != 0; } + bool Is_DataCRC_Defined() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) != 0; } +}; + +struct CArc +{ + CMyComPtr<IInStream> Stream; + UInt64 PhySize; + // CByteBuffer Comment; + + CArc(): PhySize(0) {} + ISequentialInStream *CreateLimitedStream(UInt64 offset, UInt64 size) const; +}; + +struct CRefItem +{ + unsigned VolumeIndex; + unsigned ItemIndex; + unsigned NumItems; +}; + class CHandler: public IInArchive, PUBLIC_ISetCompressCodecsInfo public CMyUnknownImp { CRecordVector<CRefItem> _refItems; - CObjectVector<CItemEx> _items; - CObjectVector<CInArchive> _archives; - NArchive::NRar::CInArchiveInfo _archiveInfo; - AString _errorMessage; + CObjectVector<CItem> _items; + CObjectVector<CArc> _arcs; + NArchive::NRar::CInArcInfo _arcInfo; + // AString _errorMessage; + UInt32 _errorFlags; + UInt32 _warningFlags; + bool _isArc; 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(); - } + UInt64 GetPackSize(unsigned refIndex) const; + bool IsSolid(unsigned refIndex) const; + + /* void AddErrorMessage(const AString &s) { if (!_errorMessage.IsEmpty()) _errorMessage += '\n'; _errorMessage += s; } + */ HRESULT Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, diff --git a/CPP/7zip/Archive/Rar/RarHeader.cpp b/CPP/7zip/Archive/Rar/RarHeader.cpp deleted file mode 100755 index 94481e02..00000000 --- a/CPP/7zip/Archive/Rar/RarHeader.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// 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/CPP/7zip/Archive/Rar/RarHeader.h b/CPP/7zip/Archive/Rar/RarHeader.h index 5c21a2ac..b518338a 100755..100644 --- a/CPP/7zip/Archive/Rar/RarHeader.h +++ b/CPP/7zip/Archive/Rar/RarHeader.h @@ -3,16 +3,15 @@ #ifndef __ARCHIVE_RAR_HEADER_H #define __ARCHIVE_RAR_HEADER_H -#include "Common/Types.h" +#include "../../../Common/MyTypes.h" namespace NArchive { namespace NRar { namespace NHeader { -const int kMarkerSize = 7; -extern Byte kMarker[kMarkerSize]; +const unsigned kMarkerSize = 7; -const int kArchiveSolid = 0x1; +const unsigned kArchiveSolid = 0x1; namespace NBlockType { @@ -44,36 +43,40 @@ namespace NArchive 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 UInt16 kEndOfArc_Flags_NextVol = 1; + const UInt16 kEndOfArc_Flags_DataCRC = 2; + const UInt16 kEndOfArc_Flags_RevSpace = 4; + const UInt16 kEndOfArc_Flags_VolNumber = 8; - const int kBlockHeadersAreEncrypted = 0x80; + const unsigned kHeaderSizeMin = 7; + + const unsigned kArchiveHeaderSize = 13; + const unsigned 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 unsigned kSplitBefore = 1 << 0; + const unsigned kSplitAfter = 1 << 1; + const unsigned kEncrypted = 1 << 2; + const unsigned kComment = 1 << 3; + const unsigned kSolid = 1 << 4; - const int kDictBitStart = 5; - const int kNumDictBits = 3; - const int kDictMask = (1 << kNumDictBits) - 1; - const int kDictDirectoryValue = 0x7; + const unsigned kDictBitStart = 5; + const unsigned kNumDictBits = 3; + const unsigned kDictMask = (1 << kNumDictBits) - 1; + const unsigned 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; + const unsigned kSize64Bits = 1 << 8; + const unsigned kUnicodeName = 1 << 9; + const unsigned kSalt = 1 << 10; + const unsigned kOldVersion = 1 << 11; + const unsigned kExtTime = 1 << 12; + // const unsigned kExtFlags = 1 << 13; + // const unsigned kSkipIfUnknown = 1 << 14; + + const unsigned kLongBlock = 1 << 15; /* struct CBlock @@ -134,17 +137,17 @@ namespace NFile }; */ - const int kLabelFileAttribute = 0x08; - const int kWinFileDirectoryAttributeMask = 0x10; + const unsigned kLabelFileAttribute = 0x08; + const unsigned kWinFileDirectoryAttributeMask = 0x10; enum CHostOS { kHostMSDOS = 0, - kHostOS2 = 1, - kHostWin32 = 2, - kHostUnix = 3, - kHostMacOS = 4, - kHostBeOS = 5 + kHostOS2 = 1, + kHostWin32 = 2, + kHostUnix = 3, + kHostMacOS = 4, + kHostBeOS = 5 }; } diff --git a/CPP/7zip/Archive/Rar/RarIn.cpp b/CPP/7zip/Archive/Rar/RarIn.cpp deleted file mode 100755 index a7d018ff..00000000 --- a/CPP/7zip/Archive/Rar/RarIn.cpp +++ /dev/null @@ -1,478 +0,0 @@ -// 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/CPP/7zip/Archive/Rar/RarIn.h b/CPP/7zip/Archive/Rar/RarIn.h deleted file mode 100755 index a6998db2..00000000 --- a/CPP/7zip/Archive/Rar/RarIn.h +++ /dev/null @@ -1,123 +0,0 @@ -// 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/CPP/7zip/Archive/Rar/RarItem.cpp b/CPP/7zip/Archive/Rar/RarItem.cpp deleted file mode 100755 index 9216ae57..00000000 --- a/CPP/7zip/Archive/Rar/RarItem.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// 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/CPP/7zip/Archive/Rar/RarItem.h b/CPP/7zip/Archive/Rar/RarItem.h index 4aa4d866..56d25f2c 100755..100644 --- a/CPP/7zip/Archive/Rar/RarItem.h +++ b/CPP/7zip/Archive/Rar/RarItem.h @@ -3,13 +3,12 @@ #ifndef __ARCHIVE_RAR_ITEM_H #define __ARCHIVE_RAR_ITEM_H -#include "Common/Types.h" -#include "Common/MyString.h" +#include "../../../Common/StringConvert.h" #include "RarHeader.h" -namespace NArchive{ -namespace NRar{ +namespace NArchive { +namespace NRar { struct CRarTime { @@ -56,18 +55,35 @@ struct CItem 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) {} -}; + UInt32 GetWinAttrib() const; -class CItemEx: public CItem -{ -public: UInt64 Position; - UInt16 MainPartSize; + unsigned MainPartSize; UInt16 CommentSize; UInt16 AlignSize; + + // int BaseFileIndex; + // bool IsAltStream; + + UString GetName() const + { + if (( /* IsAltStream || */ HasUnicodeName()) && !UnicodeName.IsEmpty()) + return UnicodeName; + return MultiByteToUnicodeString(Name, CP_OEMCP); + } + + void Clear() + { + CTimeDefined = false; + ATimeDefined = false; + Name.Empty(); + UnicodeName.Empty(); + // IsAltStream = false; + // BaseFileIndex = -1; + } + + CItem() { Clear(); } + UInt64 GetFullSize() const { return MainPartSize + CommentSize + AlignSize + PackSize; }; // DWORD GetHeaderWithCommentSize() const { return MainPartSize + CommentSize; }; UInt64 GetCommentPosition() const { return Position + MainPartSize; }; diff --git a/CPP/7zip/Archive/Rar/RarRegister.cpp b/CPP/7zip/Archive/Rar/RarRegister.cpp deleted file mode 100755 index 2bcf569e..00000000 --- a/CPP/7zip/Archive/Rar/RarRegister.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// 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/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp b/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp deleted file mode 100755 index 25194f91..00000000 --- a/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// 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/CPP/7zip/Archive/Rar/RarVolumeInStream.h b/CPP/7zip/Archive/Rar/RarVolumeInStream.h deleted file mode 100755 index 78d95b10..00000000 --- a/CPP/7zip/Archive/Rar/RarVolumeInStream.h +++ /dev/null @@ -1,49 +0,0 @@ -// 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/CPP/7zip/Archive/Rar/StdAfx.cpp b/CPP/7zip/Archive/Rar/StdAfx.cpp index d0feea85..d0feea85 100755..100644 --- a/CPP/7zip/Archive/Rar/StdAfx.cpp +++ b/CPP/7zip/Archive/Rar/StdAfx.cpp diff --git a/CPP/7zip/Archive/Rar/StdAfx.h b/CPP/7zip/Archive/Rar/StdAfx.h index e7fb6986..2854ff3e 100755..100644 --- a/CPP/7zip/Archive/Rar/StdAfx.h +++ b/CPP/7zip/Archive/Rar/StdAfx.h @@ -3,6 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" +#include "../../../Common/Common.h" #endif |