This commit is contained in:
Igor Pavlov
2015-08-16 00:00:00 +00:00
committed by Kornel Lesiński
parent 54490d51d5
commit cba375916f
152 changed files with 6544 additions and 2001 deletions

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,410 @@
// Rar5Handler.h
#ifndef __RAR5_HANDLER_H
#define __RAR5_HANDLER_H
#include "../../../../C/Blake2.h"
#include "../../../Common/MyBuffer.h"
#include "../../../Windows/PropVariant.h"
#include "../../Common/CreateCoder.h"
#include "../IArchive.h"
namespace NArchive {
namespace NRar5 {
namespace NHeaderFlags
{
const unsigned kExtra = 1 << 0;
const unsigned kData = 1 << 1;
// const unsigned kUnknown = 1 << 2;
const unsigned kPrevVol = 1 << 3;
const unsigned kNextVol = 1 << 4;
// const unsigned kIsChild = 1 << 5;
// const unsigned kPreserveChild = 1 << 6;
}
namespace NHeaderType
{
enum
{
kArc = 1,
kFile,
kService,
kArcEncrypt,
kEndOfArc
};
}
namespace NArcFlags
{
const unsigned kVol = 1 << 0;
const unsigned kVolNumber = 1 << 1;
const unsigned kSolid = 1 << 2;
// const unsigned kRecovery = 1 << 3;
// const unsigned kLocked = 1 << 4;
}
const unsigned kArcExtraRecordType_Locator = 1;
namespace NLocatorFlags
{
const unsigned kQuickOpen = 1 << 0;
const unsigned kRecovery = 1 << 1;
}
namespace NFileFlags
{
const unsigned kIsDir = 1 << 0;
const unsigned kUnixTime = 1 << 1;
const unsigned kCrc32 = 1 << 2;
const unsigned kUnknownSize = 1 << 3;
}
namespace NMethodFlags
{
// const unsigned kVersionMask = 0x3F;
const unsigned kSolid = 1 << 6;
}
namespace NArcEndFlags
{
const unsigned kMoreVols = 1 << 0;
}
enum EHostOS
{
kHost_Windows = 0,
kHost_Unix
};
// ---------- Extra ----------
namespace NExtraRecordType
{
enum
{
kCrypto = 1,
kHash,
kTime,
kVersion,
kLink,
kUnixOwner,
kSubdata
};
}
// const unsigned kCryptoAlgo_AES = 0;
namespace NCryptoFlags
{
const unsigned kPswCheck = 1 << 0;
const unsigned kUseMAC = 1 << 1;
}
struct CCryptoInfo
{
UInt64 Algo;
UInt64 Flags;
Byte Cnt;
bool UseMAC() const { return (Flags & NCryptoFlags::kUseMAC) != 0; }
bool IsThereCheck() const { return (Flags & NCryptoFlags::kPswCheck) != 0; }
bool Parse(const Byte *p, size_t size);
};
const unsigned kHashID_Blake2sp = 0;
namespace NTimeRecord
{
enum
{
k_Index_MTime = 0,
k_Index_CTime,
k_Index_ATime
};
namespace NFlags
{
const unsigned kUnixTime = 1 << 0;
const unsigned kMTime = 1 << 1;
// const unsigned kCTime = 1 << 2;
// const unsigned kATime = 1 << 3;
}
}
namespace NLinkType
{
enum
{
kUnixSymLink = 1,
kWinSymLink,
kWinJunction,
kHardLink,
kFileCopy
};
}
namespace NLinkFlags
{
const unsigned kTargetIsDir = 1 << 0;
}
struct CItem
{
UInt32 CommonFlags;
UInt32 Flags;
Byte RecordType;
bool Version_Defined;
int ACL;
AString Name;
int VolIndex;
int NextItem;
UInt32 UnixMTime;
UInt32 CRC;
UInt32 Attrib;
UInt32 Method;
CByteBuffer Extra;
UInt64 Size;
UInt64 PackSize;
UInt64 HostOS;
UInt64 DataPos;
UInt64 Version;
CItem() { Clear(); }
void Clear()
{
CommonFlags = 0;
Flags = 0;
VolIndex = 0;
NextItem = -1;
Version_Defined = false;
Version = 0;
Name.Empty();
Extra.Free();
ACL = -1;
}
bool IsSplitBefore() const { return (CommonFlags & NHeaderFlags::kPrevVol) != 0; }
bool IsSplitAfter() const { return (CommonFlags & NHeaderFlags::kNextVol) != 0; }
bool IsSplit() const { return (CommonFlags & (NHeaderFlags::kPrevVol | NHeaderFlags::kNextVol)) != 0; }
bool IsDir() const { return (Flags & NFileFlags::kIsDir) != 0; }
bool Has_UnixMTime() const { return (Flags & NFileFlags::kUnixTime) != 0; }
bool Has_CRC() const { return (Flags & NFileFlags::kCrc32) != 0; }
bool Is_UnknownSize() const { return (Flags & NFileFlags::kUnknownSize) != 0; }
bool IsNextForItem(const CItem &prev) const
{
return !IsDir() && !prev.IsDir() && IsSplitBefore() && prev.IsSplitAfter() && (Name == prev.Name);
// && false;
}
bool IsSolid() const { return ((UInt32)Method & NMethodFlags::kSolid) != 0; }
unsigned GetAlgoVersion() const { return (unsigned)Method & 0x3F; }
unsigned GetMethod() const { return ((unsigned)Method >> 7) & 0x7; }
UInt32 GetDictSize() const { return (((UInt32)Method >> 10) & 0xF); }
bool IsService() const { return RecordType == NHeaderType::kService; }
bool Is_STM() const { return IsService() && Name == "STM"; }
bool Is_CMT() const { return IsService() && Name == "CMT"; }
bool Is_ACL() const { return IsService() && Name == "ACL"; }
// bool Is_QO() const { return IsService() && Name == "QO"; }
int FindExtra(unsigned type, unsigned &recordDataSize) const;
bool IsEncrypted() const
{
unsigned size;
return FindExtra(NExtraRecordType::kCrypto, size) >= 0;
}
int FindExtra_Blake() const
{
unsigned size = 0;
int offset = FindExtra(NExtraRecordType::kHash, size);
if (offset >= 0
&& size == BLAKE2S_DIGEST_SIZE + 1
&& Extra[(unsigned)offset] == kHashID_Blake2sp)
return offset + 1;
return -1;
}
bool FindExtra_Version(UInt64 &version) const;
struct CLinkInfo
{
UInt64 Type;
UInt64 Flags;
unsigned NameOffset;
unsigned NameLen;
};
bool FindExtra_Link(CLinkInfo &link) const;
void Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const;
bool Is_CopyLink() const;
bool NeedUse_as_CopyLink() const { return PackSize == 0 && Is_CopyLink(); }
bool GetAltStreamName(AString &name) const;
UInt32 GetWinAttrib() const
{
UInt32 a;
switch (HostOS)
{
case kHost_Windows: a = Attrib; break;
case kHost_Unix: a = (Attrib << 16); break;
default: a = 0;
}
// if (IsDir()) a |= FILE_ATTRIBUTE_DIRECTORY;
return a;
}
UInt64 GetDataPosition() const { return DataPos; }
};
struct CInArcInfo
{
UInt64 Flags;
UInt64 VolNumber;
UInt64 StartPos;
UInt64 EndPos;
UInt64 EndFlags;
bool EndOfArchive_was_Read;
bool IsEncrypted;
// CByteBuffer Extra;
/*
struct CLocator
{
UInt64 Flags;
UInt64 QuickOpen;
UInt64 Recovery;
bool Is_QuickOpen() const { return (Flags & NLocatorFlags::kQuickOpen) != 0; }
bool Is_Recovery() const { return (Flags & NLocatorFlags::kRecovery) != 0; }
};
int FindExtra(unsigned type, unsigned &recordDataSize) const;
bool FindExtra_Locator(CLocator &locator) const;
*/
CInArcInfo():
Flags(0),
VolNumber(0),
StartPos(0),
EndPos(0),
EndFlags(0),
EndOfArchive_was_Read(false),
IsEncrypted(false)
{}
/*
void Clear()
{
Flags = 0;
VolNumber = 0;
StartPos = 0;
EndPos = 0;
EndFlags = 0;
EndOfArchive_was_Read = false;
Extra.Free();
}
*/
UInt64 GetPhySize() const { return EndPos - StartPos; }
bool AreMoreVolumes() const { return (EndFlags & NArcEndFlags::kMoreVols) != 0; }
bool IsVolume() const { return (Flags & NArcFlags::kVol) != 0; }
bool IsSolid() const { return (Flags & NArcFlags::kSolid) != 0; }
bool Is_VolNumber_Defined() const { return (Flags & NArcFlags::kVolNumber) != 0; }
UInt64 GetVolIndex() const { return Is_VolNumber_Defined() ? VolNumber : 0; }
};
struct CRefItem
{
unsigned Item;
unsigned Last;
int Parent;
int Link;
};
struct CArc
{
CMyComPtr<IInStream> Stream;
CInArcInfo Info;
};
class CHandler:
public IInArchive,
public IArchiveGetRawProps,
PUBLIC_ISetCompressCodecsInfo
public CMyUnknownImp
{
public:
CRecordVector<CRefItem> _refs;
CObjectVector<CItem> _items;
private:
CObjectVector<CArc> _arcs;
CObjectVector<CByteBuffer> _acls;
UInt32 _errorFlags;
// UInt32 _warningFlags;
bool _isArc;
CByteBuffer _comment;
DECL_EXTERNAL_CODECS_VARS
UInt64 GetPackSize(unsigned refIndex) const;
void FillLinks();
HRESULT Open2(IInStream *stream,
const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback *openCallback);
public:
MY_QUERYINTERFACE_BEGIN2(IInArchive)
MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps)
QUERY_ENTRY_ISetCompressCodecsInfo
MY_QUERYINTERFACE_END
MY_ADDREF_RELEASE
INTERFACE_IInArchive(;)
INTERFACE_IArchiveGetRawProps(;)
DECL_ISetCompressCodecsInfo
};
}}
#endif

View File

@@ -30,6 +30,7 @@
#include "../Common/ItemNameUtils.h"
#include "../Common/OutStreamWithCRC.h"
#include "RarVol.h"
#include "RarHandler.h"
using namespace NWindows;
@@ -44,6 +45,8 @@ namespace NRar {
static const Byte kMarker[NHeader::kMarkerSize] = SIGNATURE;
const unsigned kPasswordLen_MAX = 127;
bool CItem::IgnoreItem() const
{
switch (HostOS)
@@ -131,7 +134,7 @@ class CInArchive
CByteBuffer _comment;
CByteBuffer m_FileHeaderData;
NHeader::NBlock::CBlock m_BlockHeader;
NCrypto::NRar29::CDecoder *m_RarAESSpec;
NCrypto::NRar3::CDecoder *m_RarAESSpec;
CMyComPtr<ICompressFilter> m_RarAES;
CBuffer<Byte> m_DecryptedData;
Byte *m_DecryptedDataAligned;
@@ -362,6 +365,7 @@ static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime)
_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;
@@ -500,7 +504,7 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass
}
if (!m_RarAES)
{
m_RarAESSpec = new NCrypto::NRar29::CDecoder;
m_RarAESSpec = new NCrypto::NRar3::CDecoder;
m_RarAES = m_RarAESSpec;
}
m_RarAESSpec->SetRar350Mode(ArcInfo.IsEncryptOld());
@@ -518,7 +522,10 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass
unsigned len = 0;
if (password)
len = MyStringLen(password);
CByteBuffer buffer(len * 2);
if (len > kPasswordLen_MAX)
len = kPasswordLen_MAX;
CByteArr buffer(len * 2);
for (unsigned i = 0; i < len; i++)
{
wchar_t c = password[i];
@@ -526,7 +533,7 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass
((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
}
RINOK(m_RarAESSpec->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size()));
m_RarAESSpec->SetPassword((const Byte *)buffer, len * 2);
const UInt32 kDecryptedBufferSize = (1 << 12);
if (m_DecryptedData.Size() == 0)
@@ -990,121 +997,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
COM_TRY_END
}
static bool IsDigit(wchar_t c)
{
return c >= L'0' && c <= L'9';
}
class CVolumeName
{
bool _first;
bool _newStyle;
UString _unchangedPart;
UString _changedPart;
UString _afterPart;
public:
CVolumeName(): _newStyle(true) {};
bool InitName(const UString &name, bool newStyle)
{
_first = true;
_newStyle = newStyle;
int dotPos = name.ReverseFind_Dot();
UString basePart = name;
if (dotPos >= 0)
{
UString ext = name.Ptr(dotPos + 1);
if (ext.IsEqualTo_Ascii_NoCase("rar"))
{
_afterPart = name.Ptr(dotPos);
basePart = name.Left(dotPos);
}
else if (ext.IsEqualTo_Ascii_NoCase("exe"))
{
_afterPart.SetFromAscii(".rar");
basePart = name.Left(dotPos);
}
else if (!_newStyle)
{
if (ext.IsEqualTo_Ascii_NoCase("000") ||
ext.IsEqualTo_Ascii_NoCase("001") ||
ext.IsEqualTo_Ascii_NoCase("r00") ||
ext.IsEqualTo_Ascii_NoCase("r01"))
{
_afterPart.Empty();
_first = false;
_changedPart = ext;
_unchangedPart = name.Left(dotPos + 1);
return true;
}
}
}
if (!_newStyle)
{
_afterPart.Empty();
_unchangedPart = basePart;
_unchangedPart += L'.';
_changedPart.SetFromAscii("r00");
return true;
}
if (basePart.IsEmpty())
return false;
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()
{
if (_newStyle || !_first)
{
unsigned i = _changedPart.Len();
for (;;)
{
wchar_t c = _changedPart[--i];
if (c == L'9')
{
c = L'0';
_changedPart.ReplaceOneCharAtPos(i, c);
if (i == 0)
{
_changedPart.InsertAtFront(L'1');
break;
}
continue;
}
c++;
_changedPart.ReplaceOneCharAtPos(i, c);
break;
}
}
_first = false;
return _unchangedPart + _changedPart + _afterPart;
}
};
static HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize)
HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize)
{
areThereNonZeros = false;
numZeros = 0;
@@ -1136,7 +1030,6 @@ HRESULT CHandler::Open2(IInStream *stream,
{
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openCallback;
CVolumeName seqName;
@@ -1145,8 +1038,8 @@ HRESULT CHandler::Open2(IInStream *stream,
if (openCallback)
{
openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
openCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
}
CInArchive archive;
@@ -1363,108 +1256,91 @@ struct CMethodItem
};
class CFolderInStream:
class CVolsInStream:
public ISequentialInStream,
public CMyUnknownImp
{
public:
MY_UNKNOWN_IMP
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
private:
const CObjectVector<CArc> *_archives;
UInt64 _rem;
ISequentialInStream *_stream;
const CObjectVector<CArc> *_arcs;
const CObjectVector<CItem> *_items;
CRefItem _refItem;
unsigned _curIndex;
UInt32 _crc;
bool _fileIsOpen;
CMyComPtr<ISequentialInStream> _stream;
bool _calcCrc;
HRESULT OpenStream();
HRESULT CloseStream();
public:
void Init(const CObjectVector<CArc> *archives,
const CObjectVector<CItem> *items,
const CRefItem &refItem);
MY_UNKNOWN_IMP
CRecordVector<UInt32> CRCs;
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
void Init(const CObjectVector<CArc> *arcs,
const CObjectVector<CItem> *items,
const CRefItem &refItem)
{
_arcs = arcs;
_items = items;
_refItem = refItem;
_curIndex = 0;
_stream = NULL;
CrcIsOK = true;
}
bool CrcIsOK;
};
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)
STDMETHODIMP CVolsInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize)
*processedSize = 0;
UInt32 realProcessedSize = 0;
while ((_curIndex < _refItem.NumItems || _fileIsOpen) && size > 0)
while (size != 0)
{
if (_fileIsOpen)
if (!_stream)
{
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;
if (_curIndex >= _refItem.NumItems)
break;
const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex];
IInStream *s = (*_arcs)[_refItem.VolumeIndex + _curIndex].Stream;
RINOK(s->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL));
_stream = s;
_calcCrc = (CrcIsOK && item.IsSplitAfter());
_crc = CRC_INIT_VAL;
_rem = item.PackSize;
}
else
{
RINOK(OpenStream());
UInt32 cur = size;
if (cur > _rem)
cur = (UInt32)_rem;
UInt32 num = cur;
HRESULT res = _stream->Read(data, cur, &cur);
if (_calcCrc)
_crc = CrcUpdate(_crc, data, cur);
realProcessedSize += cur;
if (processedSize)
*processedSize = realProcessedSize;
data = (Byte *)data + cur;
size -= cur;
_rem -= cur;
if (_rem == 0)
{
const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex];
_curIndex++;
if (_calcCrc && CRC_GET_DIGEST(_crc) != item.FileCRC)
CrcIsOK = false;
_stream = NULL;
}
if (res != S_OK)
return res;
if (realProcessedSize != 0)
return S_OK;
if (cur == 0 && num != 0)
return S_OK;
}
}
if (processedSize != 0)
*processedSize = realProcessedSize;
return S_OK;
}
@@ -1526,13 +1402,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CFilterCoder *filterStreamSpec = new CFilterCoder(false);
CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec;
NCrypto::NRar20::CDecoder *rar20CryptoDecoderSpec = NULL;
NCrypto::NRar2::CDecoder *rar20CryptoDecoderSpec = NULL;
CMyComPtr<ICompressFilter> rar20CryptoDecoder;
NCrypto::NRar29::CDecoder *rar29CryptoDecoderSpec = NULL;
CMyComPtr<ICompressFilter> rar29CryptoDecoder;
NCrypto::NRar3::CDecoder *rar3CryptoDecoderSpec = NULL;
CMyComPtr<ICompressFilter> rar3CryptoDecoder;
CFolderInStream *folderInStreamSpec = NULL;
CMyComPtr<ISequentialInStream> folderInStream;
CVolsInStream *volsInStreamSpec = NULL;
CMyComPtr<ISequentialInStream> volsInStream;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
@@ -1602,26 +1478,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
outStreamSpec->Init();
realOutStream.Release();
/*
for (unsigned partIndex = 0; partIndex < 1; partIndex++)
if (!volsInStream)
{
CMyComPtr<ISequentialInStream> inStream;
// item redefinition
const CItem &item = _items[refItem.ItemIndex + partIndex];
CInArchive &archive = _arcs[refItem.VolumeIndex + partIndex];
inStream.Attach(archive.CreateLimitedStream(item.GetDataPosition(),
item.PackSize));
*/
if (!folderInStream)
{
folderInStreamSpec = new CFolderInStream;
folderInStream = folderInStreamSpec;
volsInStreamSpec = new CVolsInStream;
volsInStream = volsInStreamSpec;
}
folderInStreamSpec->Init(&_arcs, &_items, refItem);
volsInStreamSpec->Init(&_arcs, &_items, refItem);
UInt64 packSize = currentPackSize;
@@ -1632,29 +1495,29 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (item.IsEncrypted())
{
CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
// CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
if (item.UnPackVersion >= 29)
{
if (!rar29CryptoDecoder)
if (!rar3CryptoDecoder)
{
rar29CryptoDecoderSpec = new NCrypto::NRar29::CDecoder;
rar29CryptoDecoder = rar29CryptoDecoderSpec;
rar3CryptoDecoderSpec = new NCrypto::NRar3::CDecoder;
rar3CryptoDecoder = rar3CryptoDecoderSpec;
}
rar29CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
rar3CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
/*
CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties;
RINOK(rar29CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,
RINOK(rar3CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,
&cryptoProperties));
*/
RINOK(rar29CryptoDecoderSpec->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0));
filterStreamSpec->Filter = rar29CryptoDecoder;
RINOK(rar3CryptoDecoderSpec->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0));
filterStreamSpec->Filter = rar3CryptoDecoder;
}
else if (item.UnPackVersion >= 20)
{
if (!rar20CryptoDecoder)
{
rar20CryptoDecoderSpec = new NCrypto::NRar20::CDecoder;
rar20CryptoDecoderSpec = new NCrypto::NRar2::CDecoder;
rar20CryptoDecoder = rar20CryptoDecoderSpec;
}
filterStreamSpec->Filter = rar20CryptoDecoder;
@@ -1666,49 +1529,66 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
continue;
}
RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword));
// RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword));
if (!getTextPassword)
extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
if (getTextPassword)
if (!getTextPassword)
{
outStream.Release();
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
continue;
}
// if (getTextPassword)
{
CMyComBSTR password;
RINOK(getTextPassword->CryptoGetTextPassword(&password));
if (item.UnPackVersion >= 29)
{
UString unicodePassword;
unsigned len = 0;
if (password)
len = MyStringLen(password);
CByteBuffer buffer(len * 2);
if (len > kPasswordLen_MAX)
len = kPasswordLen_MAX;
CByteArr 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(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size()));
rar3CryptoDecoderSpec->SetPassword((const Byte *)buffer, len * 2);
}
else
{
AString oemPassword;
if (password)
oemPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len()));
{
UString unicode = (LPCOLESTR)password;
if (unicode.Len() > kPasswordLen_MAX)
unicode.DeleteFrom(kPasswordLen_MAX);
oemPassword = UnicodeStringToMultiByte(unicode, CP_OEMCP);
}
rar20CryptoDecoderSpec->SetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len());
}
}
/*
else
{
RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
RINOK(cryptoSetPassword->CryptoSetPassword(NULL, 0));
}
*/
filterStreamSpec->SetInStream(folderInStream);
filterStreamSpec->SetInStream(volsInStream);
filterStreamSpec->SetOutStreamSize(NULL);
inStream = filterStream;
}
else
{
inStream = folderInStream;
inStream = volsInStream;
}
CMyComPtr<ICompressCoder> commonCoder;
@@ -1766,7 +1646,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Byte isSolid = (Byte)((IsSolid(index) || item.IsSplitBefore()) ? 1: 0);
if (solidStart)
{
isSolid = false;
isSolid = 0;
solidStart = false;
}
@@ -1786,46 +1666,25 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (item.IsEncrypted())
filterStreamSpec->ReleaseInStream();
if (result == S_FALSE)
{
outStream.Release();
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError));
continue;
}
if (result != S_OK)
return result;
const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
int opRes = (volsInStreamSpec->CrcIsOK && outStreamSpec->GetCRC() == lastItem.FileCRC) ?
NExtract::NOperationResult::kOK:
NExtract::NOperationResult::kCRCError;
outStream.Release();
/*
if (refItem.NumItems == 1 &&
!item.IsSplitBefore() && !item.IsSplitAfter())
*/
if (result != S_OK)
{
const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
bool crcOK = outStreamSpec->GetCRC() == lastItem.FileCRC;
outStream.Release();
RINOK(extractCallback->SetOperationResult(crcOK ?
NExtract::NOperationResult::kOK:
NExtract::NOperationResult::kCRCError));
if (result == S_FALSE)
opRes = NExtract::NOperationResult::kDataError;
else if (result == E_NOTIMPL)
opRes = NExtract::NOperationResult::kUnsupportedMethod;
else
return result;
}
/*
else
{
bool crcOK = true;
for (unsigned partIndex = 0; partIndex < refItem.NumItems; partIndex++)
{
const CItem &item = _items[refItem.ItemIndex + partIndex];
if (item.FileCRC != folderInStreamSpec->CRCs[partIndex])
{
crcOK = false;
break;
}
}
RINOK(extractCallback->SetOperationResult(crcOK ?
NExtract::NOperationResult::kOK:
NExtract::NOperationResult::kCRCError));
}
*/
RINOK(extractCallback->SetOperationResult(opRes));
}
return S_OK;
COM_TRY_END
}

View File

@@ -0,0 +1,129 @@
// RarVol.h
#ifndef __ARCHIVE_RAR_VOL_H
#define __ARCHIVE_RAR_VOL_H
#include "../../../Common/StringConvert.h"
#include "RarHeader.h"
namespace NArchive {
namespace NRar {
inline bool IsDigit(wchar_t c)
{
return c >= L'0' && c <= L'9';
}
class CVolumeName
{
bool _first;
bool _newStyle;
UString _unchangedPart;
UString _changedPart;
UString _afterPart;
public:
CVolumeName(): _newStyle(true) {};
bool InitName(const UString &name, bool newStyle = true)
{
_first = true;
_newStyle = newStyle;
int dotPos = name.ReverseFind_Dot();
UString basePart = name;
if (dotPos >= 0)
{
UString ext = name.Ptr(dotPos + 1);
if (ext.IsEqualTo_Ascii_NoCase("rar"))
{
_afterPart = name.Ptr(dotPos);
basePart = name.Left(dotPos);
}
else if (ext.IsEqualTo_Ascii_NoCase("exe"))
{
_afterPart.SetFromAscii(".rar");
basePart = name.Left(dotPos);
}
else if (!_newStyle)
{
if (ext.IsEqualTo_Ascii_NoCase("000") ||
ext.IsEqualTo_Ascii_NoCase("001") ||
ext.IsEqualTo_Ascii_NoCase("r00") ||
ext.IsEqualTo_Ascii_NoCase("r01"))
{
_afterPart.Empty();
_first = false;
_changedPart = ext;
_unchangedPart = name.Left(dotPos + 1);
return true;
}
}
}
if (!_newStyle)
{
_afterPart.Empty();
_unchangedPart = basePart;
_unchangedPart += L'.';
_changedPart.SetFromAscii("r00");
return true;
}
if (basePart.IsEmpty())
return false;
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()
{
if (_newStyle || !_first)
{
unsigned i = _changedPart.Len();
for (;;)
{
wchar_t c = _changedPart[--i];
if (c == L'9')
{
c = L'0';
_changedPart.ReplaceOneCharAtPos(i, c);
if (i == 0)
{
_changedPart.InsertAtFront(L'1');
break;
}
continue;
}
c++;
_changedPart.ReplaceOneCharAtPos(i, c);
break;
}
}
_first = false;
return _unchangedPart + _changedPart + _afterPart;
}
};
}}
#endif