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

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/Rar/RarHandler.cpp')
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Rar/RarHandler.cpp1287
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)
+
}}