diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2015-08-16 03:00:00 +0300 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:55 +0300 |
commit | cba375916fb18db8b9101aedf4fa079e019311b3 (patch) | |
tree | 6275ae5fc2a8dd337ab0327180c871807e6ba5d4 /CPP/7zip/Archive | |
parent | 54490d51d5c6b0d794dcbad2d634d4c95fc25b6c (diff) |
15.0615.06
Diffstat (limited to 'CPP/7zip/Archive')
29 files changed, 3514 insertions, 1553 deletions
diff --git a/CPP/7zip/Archive/7z/7zDecode.cpp b/CPP/7zip/Archive/7z/7zDecode.cpp index d1a810cb..bfe1b24e 100644 --- a/CPP/7zip/Archive/7z/7zDecode.cpp +++ b/CPP/7zip/Archive/7z/7zDecode.cpp @@ -301,6 +301,12 @@ HRESULT CDecoder::Decode( { const CCoderInfo &coderInfo = folderInfo.Coders[i]; + #ifndef _SFX + // we don't support RAR codecs here + if ((coderInfo.MethodID >> 8) == 0x403) + return E_NOTIMPL; + #endif + CCreatedCoder cod; RINOK(CreateCoder( EXTERNAL_CODECS_LOC_VARS diff --git a/CPP/7zip/Archive/7z/7zHandler.h b/CPP/7zip/Archive/7z/7zHandler.h index 8a078e19..eb7791bc 100644 --- a/CPP/7zip/Archive/7z/7zHandler.h +++ b/CPP/7zip/Archive/7z/7zHandler.h @@ -44,6 +44,7 @@ public: UInt64 _numSolidBytes; bool _numSolidBytesDefined; bool _solidExtension; + bool _useTypeSorting; bool _compressHeaders; bool _encryptHeadersSpecified; diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp index 5cab6a82..7ece4c68 100644 --- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp +++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp @@ -508,14 +508,19 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (ui.NewData) { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(i, kpidSize, &prop)); - if (prop.vt != VT_UI8) - return E_INVALIDARG; - ui.Size = (UInt64)prop.uhVal.QuadPart; - if (ui.Size != 0 && ui.IsAnti) - return E_INVALIDARG; + ui.Size = 0; + if (!ui.IsDir) + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidSize, &prop)); + if (prop.vt != VT_UI8) + return E_INVALIDARG; + ui.Size = (UInt64)prop.uhVal.QuadPart; + if (ui.Size != 0 && ui.IsAnti) + return E_INVALIDARG; + } } + updateItems.Add(ui); } @@ -613,6 +618,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt options.NumSolidFiles = _numSolidFiles; options.NumSolidBytes = _numSolidBytes; options.SolidExtension = _solidExtension; + options.UseTypeSorting = _useTypeSorting; + options.RemoveSfxBlock = _removeSfxBlock; // options.VolumeMode = _volumeMode; @@ -701,6 +708,7 @@ void COutHandler::InitProps() // _volumeMode = false; InitSolid(); + _useTypeSorting = false; } HRESULT COutHandler::SetSolidFromString(const UString &s) @@ -821,6 +829,8 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer); + if (name.IsEqualTo("qs")) return PROPVARIANT_to_bool(value, _useTypeSorting); + // if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode); } return CMultiMethodProps::SetProperty(name, value); diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp index e7c9ecc6..345cd627 100644 --- a/CPP/7zip/Archive/7z/7zUpdate.cpp +++ b/CPP/7zip/Archive/7z/7zUpdate.cpp @@ -554,11 +554,11 @@ static int CompareEmptyItems(const unsigned *p1, const unsigned *p2, void *param } static const char *g_Exts = - " lzma 7z ace arc arj bz bz2 deb lzo lzx gz pak rpm sit tgz tbz tbz2 tgz cab ha lha lzh rar zoo" + " 7z xz lzma ace arc arj bz tbz bz2 tbz2 cab deb gz tgz ha lha lzh lzo lzx pak rar rpm sit zoo" " zip jar ear war msi" " 3gp avi mov mpeg mpg mpe wmv" " aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav" - " swf " + " swf" " chm hxi hxs" " gif jpeg jpg jp2 png tiff bmp ico psd psp" " awg ps eps cgm dxf svg vrml wmf emf ai md" @@ -569,9 +569,9 @@ static const char *g_Exts = " vmdk dsk nvram vmem vmsd vmsn vmss vmtm" " inl inc idl acf asa h hpp hxx c cpp cxx rc java cs pas bas vb cls ctl frm dlg def" " f77 f f90 f95" - " asm sql manifest dep " - " mak clw csproj vcproj sln dsp dsw " - " class " + " asm sql manifest dep" + " mak clw csproj vcproj sln dsp dsw" + " class" " bat cmd" " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml" " awk sed hta js php php3 php4 php5 phptml pl pm py pyo rb sh tcl vbs" @@ -580,7 +580,7 @@ static const char *g_Exts = " abw afp cwk lwp wpd wps wpt wrf wri" " abf afm bdf fon mgf otf pcf pfa snf ttf" " dbf mdb nsf ntf wdb db fdb gdb" - " exe dll ocx vbx sfx sys tlb awx com obj lib out o so " + " exe dll ocx vbx sfx sys tlb awx com obj lib out o so" " pdb pch idb ncb opt"; static unsigned GetExtIndex(const char *ext) @@ -2251,7 +2251,7 @@ HRESULT Update( continue; CRecordVector<CRefItem> refItems; refItems.ClearAndSetSize(numFiles); - bool sortByType = (numSolidFiles > 1); + bool sortByType = (options.UseTypeSorting && numSolidFiles > 1); for (i = 0; i < numFiles; i++) refItems[i] = CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType); CSortParam sortParam; diff --git a/CPP/7zip/Archive/7z/7zUpdate.h b/CPP/7zip/Archive/7z/7zUpdate.h index 3986af43..a7abf779 100644 --- a/CPP/7zip/Archive/7z/7zUpdate.h +++ b/CPP/7zip/Archive/7z/7zUpdate.h @@ -97,6 +97,9 @@ struct CUpdateOptions UInt64 NumSolidFiles; UInt64 NumSolidBytes; bool SolidExtension; + + bool UseTypeSorting; + bool RemoveSfxBlock; bool MultiThreadMixer; @@ -109,6 +112,7 @@ struct CUpdateOptions NumSolidFiles((UInt64)(Int64)(-1)), NumSolidBytes((UInt64)(Int64)(-1)), SolidExtension(false), + UseTypeSorting(true), RemoveSfxBlock(false), MultiThreadMixer(true) {} diff --git a/CPP/7zip/Archive/7z/makefile b/CPP/7zip/Archive/7z/makefile index 19982112..49818371 100644 --- a/CPP/7zip/Archive/7z/makefile +++ b/CPP/7zip/Archive/7z/makefile @@ -1,5 +1,5 @@ PROG = 7z.dll -DEF_FILE = ../../Archive/Archive2.def +DEF_FILE = ../Archive.def CFLAGS = $(CFLAGS) \ -DEXTERNAL_CODECS \ @@ -60,9 +60,11 @@ WIN_OBJS = \ $O\StreamUtils.obj \ $O\VirtThread.obj \ +COMPRESS_OBJS = \ + $O\CopyCoder.obj \ + AR_COMMON_OBJS = \ $O\CoderMixer2.obj \ - $O\CoderMixer2MT.obj \ $O\CrossThreadProgress.obj \ $O\HandlerOut.obj \ $O\InStreamWithCRC.obj \ @@ -76,4 +78,6 @@ C_OBJS = \ $O\CpuArch.obj \ $O\Threads.obj \ +!include "../../Crc.mak" + !include "../../7zip.mak" diff --git a/CPP/7zip/Archive/Common/CoderMixer.cpp b/CPP/7zip/Archive/Common/CoderMixer.cpp deleted file mode 100644 index a19f0457..00000000 --- a/CPP/7zip/Archive/Common/CoderMixer.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// CoderMixer.cpp - -#include "StdAfx.h" - -#include "CoderMixer.h" - -namespace NCoderMixer { - -void CCoderInfo::SetCoderInfo(const UInt64 *inSize, const UInt64 *outSize) -{ - InSizeAssigned = (inSize != 0); - if (InSizeAssigned) - InSizeValue = *inSize; - OutSizeAssigned = (outSize != 0); - if (OutSizeAssigned) - OutSizeValue = *outSize; -} - -} diff --git a/CPP/7zip/Archive/Common/CoderMixer.h b/CPP/7zip/Archive/Common/CoderMixer.h deleted file mode 100644 index 6379dd80..00000000 --- a/CPP/7zip/Archive/Common/CoderMixer.h +++ /dev/null @@ -1,32 +0,0 @@ -// CoderMixer.h - -#ifndef __CODER_MIXER_H -#define __CODER_MIXER_H - -#include "../../../Common/MyCom.h" -#include "../../ICoder.h" - -namespace NCoderMixer { - -struct CCoderInfo -{ - CMyComPtr<ICompressCoder> Coder; - CMyComPtr<ISequentialInStream> InStream; - CMyComPtr<ISequentialOutStream> OutStream; - CMyComPtr<ICompressProgressInfo> Progress; - - UInt64 InSizeValue; - UInt64 OutSizeValue; - bool InSizeAssigned; - bool OutSizeAssigned; - - void ReInit() - { - InSizeAssigned = OutSizeAssigned = false; - } - - void SetCoderInfo(const UInt64 *inSize, const UInt64 *outSize); -}; - -} -#endif diff --git a/CPP/7zip/Archive/Common/CoderMixer2MT.cpp b/CPP/7zip/Archive/Common/CoderMixer2MT.cpp deleted file mode 100644 index c0139862..00000000 --- a/CPP/7zip/Archive/Common/CoderMixer2MT.cpp +++ /dev/null @@ -1,254 +0,0 @@ -// CoderMixer2MT.cpp - -#include "StdAfx.h" - -#include "CoderMixer2MT.h" - -namespace NCoderMixer2 { - -void CCoderMT::Execute() { Code(NULL); } - -void CCoderMT::Code(ICompressProgressInfo *progress) -{ - unsigned numInStreams = EncodeMode ? 1 : NumStreams; - unsigned numOutStreams = EncodeMode ? NumStreams : 1; - - InStreamPointers.ClearAndReserve(numInStreams); - OutStreamPointers.ClearAndReserve(numOutStreams); - - unsigned i; - - for (i = 0; i < numInStreams; i++) - InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]); - - for (i = 0; i < numOutStreams; i++) - OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]); - - // we suppose that UnpackSizePointer and PackSizePointers contain correct pointers. - /* - if (UnpackSizePointer) - UnpackSizePointer = &UnpackSize; - for (i = 0; i < NumStreams; i++) - if (PackSizePointers[i]) - PackSizePointers[i] = &PackSizes[i]; - */ - - if (Coder) - Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0], - EncodeMode ? UnpackSizePointer : PackSizePointers[0], - EncodeMode ? PackSizePointers[0] : UnpackSizePointer, - progress); - else - Result = Coder2->Code( - &InStreamPointers.Front(), EncodeMode ? &UnpackSizePointer : &PackSizePointers.Front(), numInStreams, - &OutStreamPointers.Front(), EncodeMode ? &PackSizePointers.Front(): &UnpackSizePointer, numOutStreams, - progress); - - InStreamPointers.Clear(); - OutStreamPointers.Clear(); - - for (i = 0; i < InStreams.Size(); i++) - InStreams[i].Release(); - for (i = 0; i < OutStreams.Size(); i++) - OutStreams[i].Release(); -} - -HRESULT CMixerMT::SetBindInfo(const CBindInfo &bindInfo) -{ - CMixer::SetBindInfo(bindInfo); - - _streamBinders.Clear(); - FOR_VECTOR (i, _bi.Bonds) - { - RINOK(_streamBinders.AddNew().CreateEvents()); - } - return S_OK; -} - -void CMixerMT::AddCoder(ICompressCoder *coder, ICompressCoder2 *coder2, bool isFilter) -{ - const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()]; - CCoderMT &c2 = _coders.AddNew(); - c2.NumStreams = c.NumStreams; - c2.EncodeMode = EncodeMode; - c2.Coder = coder; - c2.Coder2 = coder2; - IsFilter_Vector.Add(isFilter); -} - -CCoder &CMixerMT::GetCoder(unsigned index) -{ - return _coders[index]; -} - -void CMixerMT::ReInit() -{ - FOR_VECTOR (i, _streamBinders) - _streamBinders[i].ReInit(); -} - -void CMixerMT::SelectMainCoder(bool useFirst) -{ - unsigned ci = _bi.UnpackCoder; - - if (!useFirst) - for (;;) - { - if (_coders[ci].NumStreams != 1) - break; - if (!IsFilter_Vector[ci]) - break; - - UInt32 st = _bi.Coder_to_Stream[ci]; - if (_bi.IsStream_in_PackStreams(st)) - break; - int bond = _bi.FindBond_for_PackStream(st); - if (bond < 0) - throw 20150213; - ci = _bi.Bonds[bond].UnpackIndex; - } - - MainCoderIndex = ci; -} - -HRESULT CMixerMT::Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams) -{ - unsigned i; - - for (i = 0; i < _coders.Size(); i++) - { - CCoderMT &coderInfo = _coders[i]; - const CCoderStreamsInfo &csi = _bi.Coders[i]; - - UInt32 j; - - unsigned numInStreams = EncodeMode ? 1 : csi.NumStreams; - unsigned numOutStreams = EncodeMode ? csi.NumStreams : 1; - - coderInfo.InStreams.Clear(); - for (j = 0; j < numInStreams; j++) - coderInfo.InStreams.AddNew(); - - coderInfo.OutStreams.Clear(); - for (j = 0; j < numOutStreams; j++) - coderInfo.OutStreams.AddNew(); - } - - for (i = 0; i < _bi.Bonds.Size(); i++) - { - const CBond &bond = _bi.Bonds[i]; - - UInt32 inCoderIndex, inCoderStreamIndex; - UInt32 outCoderIndex, outCoderStreamIndex; - - { - UInt32 coderIndex, coderStreamIndex; - _bi.GetCoder_for_Stream(bond.PackIndex, coderIndex, coderStreamIndex); - - inCoderIndex = EncodeMode ? bond.UnpackIndex : coderIndex; - outCoderIndex = EncodeMode ? coderIndex : bond.UnpackIndex; - - inCoderStreamIndex = EncodeMode ? 0 : coderStreamIndex; - outCoderStreamIndex = EncodeMode ? coderStreamIndex : 0; - } - - _streamBinders[i].CreateStreams( - &_coders[inCoderIndex].InStreams[inCoderStreamIndex], - &_coders[outCoderIndex].OutStreams[outCoderStreamIndex]); - - CMyComPtr<ICompressSetBufSize> inSetSize, outSetSize; - _coders[inCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&inSetSize); - _coders[outCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&outSetSize); - if (inSetSize && outSetSize) - { - const UInt32 kBufSize = 1 << 19; - inSetSize->SetInBufSize(inCoderStreamIndex, kBufSize); - outSetSize->SetOutBufSize(outCoderStreamIndex, kBufSize); - } - } - - { - CCoderMT &cod = _coders[_bi.UnpackCoder]; - if (EncodeMode) - cod.InStreams[0] = inStreams[0]; - else - cod.OutStreams[0] = outStreams[0]; - } - - for (i = 0; i < _bi.PackStreams.Size(); i++) - { - UInt32 coderIndex, coderStreamIndex; - _bi.GetCoder_for_Stream(_bi.PackStreams[i], coderIndex, coderStreamIndex); - CCoderMT &cod = _coders[coderIndex]; - if (EncodeMode) - cod.OutStreams[coderStreamIndex] = outStreams[i]; - else - cod.InStreams[coderStreamIndex] = inStreams[i]; - } - - return S_OK; -} - -HRESULT CMixerMT::ReturnIfError(HRESULT code) -{ - FOR_VECTOR (i, _coders) - if (_coders[i].Result == code) - return code; - return S_OK; -} - -HRESULT CMixerMT::Code( - ISequentialInStream * const *inStreams, - ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress) -{ - Init(inStreams, outStreams); - - unsigned i; - for (i = 0; i < _coders.Size(); i++) - if (i != MainCoderIndex) - { - RINOK(_coders[i].Create()); - } - - for (i = 0; i < _coders.Size(); i++) - if (i != MainCoderIndex) - _coders[i].Start(); - - _coders[MainCoderIndex].Code(progress); - - for (i = 0; i < _coders.Size(); i++) - if (i != MainCoderIndex) - _coders[i].WaitExecuteFinish(); - - RINOK(ReturnIfError(E_ABORT)); - RINOK(ReturnIfError(E_OUTOFMEMORY)); - - for (i = 0; i < _coders.Size(); i++) - { - HRESULT result = _coders[i].Result; - if (result != S_OK - && result != k_My_HRESULT_WritingWasCut - && result != S_FALSE - && result != E_FAIL) - return result; - } - - RINOK(ReturnIfError(S_FALSE)); - - for (i = 0; i < _coders.Size(); i++) - { - HRESULT result = _coders[i].Result; - if (result != S_OK && result != k_My_HRESULT_WritingWasCut) - return result; - } - - return S_OK; -} - -UInt64 CMixerMT::GetBondStreamSize(unsigned bondIndex) const -{ - return _streamBinders[bondIndex].ProcessedSize; -} - -} diff --git a/CPP/7zip/Archive/Common/CoderMixer2MT.h b/CPP/7zip/Archive/Common/CoderMixer2MT.h deleted file mode 100644 index 41bb3e1c..00000000 --- a/CPP/7zip/Archive/Common/CoderMixer2MT.h +++ /dev/null @@ -1,77 +0,0 @@ -// CoderMixer2MT.h - -#ifndef __CODER_MIXER2_MT_H -#define __CODER_MIXER2_MT_H - -#include "../../../Common/MyCom.h" - -#include "../../Common/StreamBinder.h" -#include "../../Common/VirtThread.h" - -#include "CoderMixer2.h" - -namespace NCoderMixer2 { - -class CCoderMT: public CCoder, public CVirtThread -{ - CLASS_NO_COPY(CCoderMT) - CRecordVector<ISequentialInStream*> InStreamPointers; - CRecordVector<ISequentialOutStream*> OutStreamPointers; - -private: - void Execute(); -public: - bool EncodeMode; - HRESULT Result; - CObjectVector< CMyComPtr<ISequentialInStream> > InStreams; - CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams; - - CCoderMT(): EncodeMode(false) {} - ~CCoderMT() { CVirtThread::WaitThreadFinish(); } - - void Code(ICompressProgressInfo *progress); -}; - - - -class CMixerMT: - public IUnknown, - public CMixer, - public CMyUnknownImp -{ - CObjectVector<CStreamBinder> _streamBinders; - - HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams); - HRESULT ReturnIfError(HRESULT code); - -public: - CObjectVector<CCoderMT> _coders; - - MY_UNKNOWN_IMP - - virtual HRESULT SetBindInfo(const CBindInfo &bindInfo); - - virtual void AddCoder(ICompressCoder *coder, ICompressCoder2 *coder2, bool isFilter); - - virtual CCoder &GetCoder(unsigned index); - - virtual void SelectMainCoder(bool useFirst); - - virtual void ReInit(); - - virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes) - { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes); } - - virtual HRESULT Code( - ISequentialInStream * const *inStreams, - ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress); - - virtual UInt64 GetBondStreamSize(unsigned bondIndex) const; - - CMixerMT(bool encodeMode): CMixer(encodeMode) {} -}; - -} - -#endif diff --git a/CPP/7zip/Archive/Common/CoderMixer2ST.cpp b/CPP/7zip/Archive/Common/CoderMixer2ST.cpp deleted file mode 100644 index 127c1ed4..00000000 --- a/CPP/7zip/Archive/Common/CoderMixer2ST.cpp +++ /dev/null @@ -1,562 +0,0 @@ -// CoderMixer2ST.cpp - -#include "StdAfx.h" - -#include "CoderMixer2ST.h" - -STDMETHODIMP CSequentialInStreamCalcSize::Read(void *data, UInt32 size, UInt32 *processedSize) -{ - UInt32 realProcessed = 0; - HRESULT result = S_OK; - if (_stream) - result = _stream->Read(data, size, &realProcessed); - _size += realProcessed; - if (size != 0 && realProcessed == 0) - _wasFinished = true; - if (processedSize) - *processedSize = realProcessed; - return result; -} - - - -STDMETHODIMP COutStreamCalcSize::Write(const void *data, UInt32 size, UInt32 *processedSize) -{ - HRESULT result = S_OK; - if (_stream) - result = _stream->Write(data, size, &size); - _size += size; - if (processedSize) - *processedSize = size; - return result; -} - -STDMETHODIMP COutStreamCalcSize::Flush() -{ - HRESULT result = S_OK; - if (_stream) - { - CMyComPtr<IOutStreamFlush> outStreamFlush; - _stream.QueryInterface(IID_IOutStreamFlush, &outStreamFlush); - if (outStreamFlush) - result = outStreamFlush->Flush();; - } - return result; -} - - - -namespace NCoderMixer2 { - -CMixerST::CMixerST(bool encodeMode): - CMixer(encodeMode) - {} - -CMixerST::~CMixerST() {} - -void CMixerST::AddCoder(ICompressCoder *coder, ICompressCoder2 *coder2, bool isFilter) -{ - IsFilter_Vector.Add(isFilter); - const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()]; - CCoderST &c2 = _coders.AddNew(); - c2.NumStreams = c.NumStreams; - c2.Coder = coder; - c2.Coder2 = coder2; - - /* - if (isFilter) - { - c2.CanRead = true; - c2.CanWrite = true; - } - else - */ - { - IUnknown *unk = (coder ? (IUnknown *)coder : (IUnknown *)coder2); - { - CMyComPtr<ISequentialInStream> s; - unk->QueryInterface(IID_ISequentialInStream, (void**)&s); - c2.CanRead = (s != NULL); - } - { - CMyComPtr<ISequentialOutStream> s; - unk->QueryInterface(IID_ISequentialOutStream, (void**)&s); - c2.CanWrite = (s != NULL); - } - } -} - -CCoder &CMixerST::GetCoder(unsigned index) -{ - return _coders[index]; -} - -void CMixerST::ReInit() {} - -HRESULT CMixerST::GetInStream2( - ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ - UInt32 outStreamIndex, ISequentialInStream **inStreamRes) -{ - UInt32 coderIndex = outStreamIndex, coderStreamIndex = 0; - - if (EncodeMode) - { - _bi.GetCoder_for_Stream(outStreamIndex, coderIndex, coderStreamIndex); - if (coderStreamIndex != 0) - return E_NOTIMPL; - } - - const CCoder &coder = _coders[coderIndex]; - - CMyComPtr<ISequentialInStream> seqInStream; - coder.QueryInterface(IID_ISequentialInStream, (void **)&seqInStream); - if (!seqInStream) - return E_NOTIMPL; - - UInt32 numInStreams = EncodeMode ? 1 : coder.NumStreams; - UInt32 startIndex = EncodeMode ? coderIndex : _bi.Coder_to_Stream[coderIndex]; - - bool isSet = false; - - if (numInStreams == 1) - { - CMyComPtr<ICompressSetInStream> setStream; - coder.QueryInterface(IID_ICompressSetInStream, (void **)&setStream); - if (setStream) - { - CMyComPtr<ISequentialInStream> seqInStream2; - RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + 0, &seqInStream2)); - RINOK(setStream->SetInStream(seqInStream2)); - isSet = true; - } - } - - if (!isSet && numInStreams != 0) - { - CMyComPtr<ICompressSetInStream2> setStream2; - coder.QueryInterface(IID_ICompressSetInStream2, (void **)&setStream2); - if (!setStream2) - return E_NOTIMPL; - - for (UInt32 i = 0; i < numInStreams; i++) - { - CMyComPtr<ISequentialInStream> seqInStream2; - RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + i, &seqInStream2)); - RINOK(setStream2->SetInStream2(i, seqInStream2)); - } - } - - *inStreamRes = seqInStream.Detach(); - return S_OK; -} - - -HRESULT CMixerST::GetInStream( - ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ - UInt32 inStreamIndex, ISequentialInStream **inStreamRes) -{ - CMyComPtr<ISequentialInStream> seqInStream; - - { - int index = -1; - if (EncodeMode) - { - if (_bi.UnpackCoder == inStreamIndex) - index = 0; - } - else - index = _bi.FindStream_in_PackStreams(inStreamIndex); - - if (index >= 0) - { - seqInStream = inStreams[index]; - *inStreamRes = seqInStream.Detach(); - return S_OK; - } - } - - int bond = FindBond_for_Stream( - true, // forInputStream - inStreamIndex); - if (bond < 0) - return E_INVALIDARG; - - RINOK(GetInStream2(inStreams, /* inSizes, */ - _bi.Bonds[bond].Get_OutIndex(EncodeMode), &seqInStream)); - - while (_binderStreams.Size() <= (unsigned)bond) - _binderStreams.AddNew(); - CStBinderStream &bs = _binderStreams[bond]; - - if (bs.StreamRef || bs.InStreamSpec) - return E_NOTIMPL; - - CSequentialInStreamCalcSize *spec = new CSequentialInStreamCalcSize; - bs.StreamRef = spec; - bs.InStreamSpec = spec; - - spec->SetStream(seqInStream); - spec->Init(); - - seqInStream = bs.InStreamSpec; - - *inStreamRes = seqInStream.Detach(); - return S_OK; -} - - -HRESULT CMixerST::GetOutStream( - ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */ - UInt32 outStreamIndex, ISequentialOutStream **outStreamRes) -{ - CMyComPtr<ISequentialOutStream> seqOutStream; - - { - int index = -1; - if (!EncodeMode) - { - if (_bi.UnpackCoder == outStreamIndex) - index = 0; - } - else - index = _bi.FindStream_in_PackStreams(outStreamIndex); - - if (index >= 0) - { - seqOutStream = outStreams[index]; - *outStreamRes = seqOutStream.Detach(); - return S_OK; - } - } - - int bond = FindBond_for_Stream( - false, // forInputStream - outStreamIndex); - if (bond < 0) - return E_INVALIDARG; - - UInt32 inStreamIndex = _bi.Bonds[bond].Get_InIndex(EncodeMode); - - UInt32 coderIndex = inStreamIndex; - UInt32 coderStreamIndex = 0; - - if (!EncodeMode) - _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex); - - CCoder &coder = _coders[coderIndex]; - - /* - if (!coder.Coder) - return E_NOTIMPL; - */ - - coder.QueryInterface(IID_ISequentialOutStream, (void **)&seqOutStream); - if (!seqOutStream) - return E_NOTIMPL; - - UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1; - UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex; - - bool isSet = false; - - if (numOutStreams == 1) - { - CMyComPtr<ICompressSetOutStream> setOutStream; - coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream); - if (setOutStream) - { - CMyComPtr<ISequentialOutStream> seqOutStream2; - RINOK(GetOutStream(outStreams, /* outSizes, */ startIndex + 0, &seqOutStream2)); - RINOK(setOutStream->SetOutStream(seqOutStream2)); - isSet = true; - } - } - - if (!isSet && numOutStreams != 0) - { - // return E_NOTIMPL; - // /* - CMyComPtr<ICompressSetOutStream2> setStream2; - coder.QueryInterface(IID_ICompressSetOutStream2, (void **)&setStream2); - if (!setStream2) - return E_NOTIMPL; - for (UInt32 i = 0; i < numOutStreams; i++) - { - CMyComPtr<ISequentialOutStream> seqOutStream2; - RINOK(GetOutStream(outStreams, startIndex + i, &seqOutStream2)); - RINOK(setStream2->SetOutStream2(i, seqOutStream2)); - } - // */ - } - - while (_binderStreams.Size() <= (unsigned)bond) - _binderStreams.AddNew(); - CStBinderStream &bs = _binderStreams[bond]; - - if (bs.StreamRef || bs.OutStreamSpec) - return E_NOTIMPL; - - COutStreamCalcSize *spec = new COutStreamCalcSize; - bs.StreamRef = (ISequentialOutStream *)spec; - bs.OutStreamSpec = spec; - - spec->SetStream(seqOutStream); - spec->Init(); - - seqOutStream = bs.OutStreamSpec; - - *outStreamRes = seqOutStream.Detach(); - return S_OK; -} - - -static HRESULT GetError(HRESULT res, HRESULT res2) -{ - if (res == res2) - return res; - if (res == S_OK) - return res2; - if (res == k_My_HRESULT_WritingWasCut) - { - if (res2 != S_OK) - return res2; - } - return res; -} - - -HRESULT CMixerST::FlushStream(UInt32 streamIndex) -{ - { - int index = -1; - if (!EncodeMode) - { - if (_bi.UnpackCoder == streamIndex) - index = 0; - } - else - index = _bi.FindStream_in_PackStreams(streamIndex); - - if (index >= 0) - return S_OK; - } - - int bond = FindBond_for_Stream( - false, // forInputStream - streamIndex); - if (bond < 0) - return E_INVALIDARG; - - UInt32 inStreamIndex = _bi.Bonds[bond].Get_InIndex(EncodeMode); - - UInt32 coderIndex = inStreamIndex; - UInt32 coderStreamIndex = 0; - if (!EncodeMode) - _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex); - - CCoder &coder = _coders[coderIndex]; - CMyComPtr<IOutStreamFlush> flush; - coder.QueryInterface(IID_IOutStreamFlush, (void **)&flush); - HRESULT res = S_OK; - if (flush) - { - res = flush->Flush(); - } - return GetError(res, FlushCoder(coderIndex)); -} - - -HRESULT CMixerST::FlushCoder(UInt32 coderIndex) -{ - CCoder &coder = _coders[coderIndex]; - - UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1; - UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex; - - HRESULT res = S_OK; - for (unsigned i = 0; i < numOutStreams; i++) - res = GetError(res, FlushStream(startIndex + i)); - return res; -} - - -void CMixerST::SelectMainCoder(bool useFirst) -{ - unsigned ci = _bi.UnpackCoder; - - int firstNonFilter = -1; - int firstAllowed = ci; - - for (;;) - { - const CCoderST &coder = _coders[ci]; - // break; - - if (ci != _bi.UnpackCoder) - if (EncodeMode ? !coder.CanWrite : !coder.CanRead) - { - firstAllowed = ci; - firstNonFilter = -2; - } - - if (coder.NumStreams != 1) - break; - - UInt32 st = _bi.Coder_to_Stream[ci]; - if (_bi.IsStream_in_PackStreams(st)) - break; - int bond = _bi.FindBond_for_PackStream(st); - if (bond < 0) - throw 20150213; - - if (EncodeMode ? !coder.CanRead : !coder.CanWrite) - break; - - if (firstNonFilter == -1 && !IsFilter_Vector[ci]) - firstNonFilter = ci; - - ci = _bi.Bonds[bond].UnpackIndex; - } - - ci = firstNonFilter; - if (firstNonFilter < 0 || useFirst) - ci = firstAllowed; - MainCoderIndex = ci; -} - - -HRESULT CMixerST::Code( - ISequentialInStream * const *inStreams, - ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress) -{ - _binderStreams.Clear(); - unsigned ci = MainCoderIndex; - - const CCoder &mainCoder = _coders[MainCoderIndex]; - - CObjectVector< CMyComPtr<ISequentialInStream> > seqInStreams; - CObjectVector< CMyComPtr<ISequentialOutStream> > seqOutStreams; - - UInt32 numInStreams = EncodeMode ? 1 : mainCoder.NumStreams; - UInt32 numOutStreams = !EncodeMode ? 1 : mainCoder.NumStreams; - - UInt32 startInIndex = EncodeMode ? ci : _bi.Coder_to_Stream[ci]; - UInt32 startOutIndex = !EncodeMode ? ci : _bi.Coder_to_Stream[ci]; - - UInt32 i; - - for (i = 0; i < numInStreams; i++) - { - CMyComPtr<ISequentialInStream> seqInStream; - RINOK(GetInStream(inStreams, /* inSizes, */ startInIndex + i, &seqInStream)); - seqInStreams.Add(seqInStream); - } - - for (i = 0; i < numOutStreams; i++) - { - CMyComPtr<ISequentialOutStream> seqOutStream; - RINOK(GetOutStream(outStreams, /* outSizes, */ startOutIndex + i, &seqOutStream)); - seqOutStreams.Add(seqOutStream); - } - - CRecordVector< ISequentialInStream * > seqInStreamsSpec; - CRecordVector< ISequentialOutStream * > seqOutStreamsSpec; - - for (i = 0; i < numInStreams; i++) - seqInStreamsSpec.Add(seqInStreams[i]); - for (i = 0; i < numOutStreams; i++) - seqOutStreamsSpec.Add(seqOutStreams[i]); - - for (i = 0; i < _coders.Size(); i++) - { - if (i == ci) - continue; - - CCoder &coder = _coders[i]; - - CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize; - coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize); - if (setOutStreamSize) - { - RINOK(setOutStreamSize->SetOutStreamSize( - EncodeMode ? coder.PackSizePointers[0] : coder.UnpackSizePointer)); - } - } - - const UInt64 * const *isSizes2 = EncodeMode ? &mainCoder.UnpackSizePointer : &mainCoder.PackSizePointers.Front(); - const UInt64 * const *outSizes2 = EncodeMode ? &mainCoder.PackSizePointers.Front() : &mainCoder.UnpackSizePointer; - - HRESULT res; - if (mainCoder.Coder) - { - res = mainCoder.Coder->Code( - seqInStreamsSpec[0], seqOutStreamsSpec[0], - isSizes2[0], outSizes2[0], - progress); - } - else - { - res = mainCoder.Coder2->Code( - &seqInStreamsSpec.Front(), isSizes2, numInStreams, - &seqOutStreamsSpec.Front(), outSizes2, numOutStreams, - progress); - } - - if (res == k_My_HRESULT_WritingWasCut) - res = S_OK; - - if (res == S_OK || res == S_FALSE) - { - res = GetError(res, FlushCoder(ci)); - } - - for (i = 0; i < _binderStreams.Size(); i++) - { - const CStBinderStream &bs = _binderStreams[i]; - if (bs.InStreamSpec) - bs.InStreamSpec->ReleaseStream(); - else - bs.OutStreamSpec->ReleaseStream(); - } - - if (res == k_My_HRESULT_WritingWasCut) - res = S_OK; - return res; -} - - -HRESULT CMixerST::GetMainUnpackStream( - ISequentialInStream * const *inStreams, - ISequentialInStream **inStreamRes) -{ - CMyComPtr<ISequentialInStream> seqInStream; - - RINOK(GetInStream2(inStreams, /* inSizes, */ - _bi.UnpackCoder, &seqInStream)) - - FOR_VECTOR (i, _coders) - { - CCoder &coder = _coders[i]; - CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize; - coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize); - if (setOutStreamSize) - { - RINOK(setOutStreamSize->SetOutStreamSize(coder.UnpackSizePointer)); - } - } - - *inStreamRes = seqInStream.Detach(); - return S_OK; -} - - -UInt64 CMixerST::GetBondStreamSize(unsigned bondIndex) const -{ - const CStBinderStream &bs = _binderStreams[bondIndex]; - if (bs.InStreamSpec) - return bs.InStreamSpec->GetSize(); - return bs.OutStreamSpec->GetSize(); -} - -} diff --git a/CPP/7zip/Archive/Common/CoderMixer2ST.h b/CPP/7zip/Archive/Common/CoderMixer2ST.h deleted file mode 100644 index f2f7c4cb..00000000 --- a/CPP/7zip/Archive/Common/CoderMixer2ST.h +++ /dev/null @@ -1,129 +0,0 @@ -// CoderMixer2ST.h - -#ifndef __CODER_MIXER2_ST_H -#define __CODER_MIXER2_ST_H - -#include "../../../Common/MyCom.h" - -#include "../../ICoder.h" - -#include "CoderMixer2.h" - -class CSequentialInStreamCalcSize: - public ISequentialInStream, - public CMyUnknownImp -{ -public: - MY_UNKNOWN_IMP1(ISequentialInStream) - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); -private: - CMyComPtr<ISequentialInStream> _stream; - UInt64 _size; - bool _wasFinished; -public: - void SetStream(ISequentialInStream *stream) { _stream = stream; } - void Init() - { - _size = 0; - _wasFinished = false; - } - void ReleaseStream() { _stream.Release(); } - UInt64 GetSize() const { return _size; } - bool WasFinished() const { return _wasFinished; } -}; - - -class COutStreamCalcSize: - public ISequentialOutStream, - public IOutStreamFlush, - public CMyUnknownImp -{ - CMyComPtr<ISequentialOutStream> _stream; - UInt64 _size; -public: - MY_UNKNOWN_IMP2(ISequentialOutStream, IOutStreamFlush) - - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(Flush)(); - - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init() { _size = 0; } - UInt64 GetSize() const { return _size; } -}; - - - -namespace NCoderMixer2 { - -struct CCoderST: public CCoder -{ - bool CanRead; - bool CanWrite; - - CCoderST(): CanRead(false), CanWrite(false) {} -}; - - -struct CStBinderStream -{ - CSequentialInStreamCalcSize *InStreamSpec; - COutStreamCalcSize *OutStreamSpec; - CMyComPtr<IUnknown> StreamRef; - - CStBinderStream(): InStreamSpec(NULL), OutStreamSpec(NULL) {} -}; - - -class CMixerST: - public IUnknown, - public CMixer, - public CMyUnknownImp -{ - HRESULT GetInStream2(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ - UInt32 outStreamIndex, ISequentialInStream **inStreamRes); - HRESULT GetInStream(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ - UInt32 inStreamIndex, ISequentialInStream **inStreamRes); - HRESULT GetOutStream(ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */ - UInt32 outStreamIndex, ISequentialOutStream **outStreamRes); - - HRESULT FlushStream(UInt32 streamIndex); - HRESULT FlushCoder(UInt32 coderIndex); - -public: - CObjectVector<CCoderST> _coders; - - CObjectVector<CStBinderStream> _binderStreams; - - MY_UNKNOWN_IMP - - CMixerST(bool encodeMode); - ~CMixerST(); - - virtual void AddCoder(ICompressCoder *coder, ICompressCoder2 *coder2, bool isFilter); - - virtual CCoder &GetCoder(unsigned index); - - virtual void SelectMainCoder(bool useFirst); - - virtual void ReInit(); - - virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes) - { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes); } - - virtual HRESULT Code( - ISequentialInStream * const *inStreams, - ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress); - - virtual UInt64 GetBondStreamSize(unsigned bondIndex) const; - - HRESULT GetMainUnpackStream( - ISequentialInStream * const *inStreams, - ISequentialInStream **inStreamRes); -}; - -} - -#endif diff --git a/CPP/7zip/Archive/Common/CoderMixerMT.cpp b/CPP/7zip/Archive/Common/CoderMixerMT.cpp deleted file mode 100644 index 96ea76a3..00000000 --- a/CPP/7zip/Archive/Common/CoderMixerMT.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// CoderMixerMT.cpp - -#include "StdAfx.h" - -#include "CoderMixerMT.h" - -namespace NCoderMixer { - -void CCoder::Execute() { Code(NULL); } - -void CCoder::Code(ICompressProgressInfo *progress) -{ - Result = Coder->Code(InStream, OutStream, - InSizeAssigned ? &InSizeValue : NULL, - OutSizeAssigned ? &OutSizeValue : NULL, - progress); - InStream.Release(); - OutStream.Release(); -} - -void CCoderMixerMT::AddCoder(ICompressCoder *coder) -{ - _coders.Add(CCoder()); - _coders.Back().Coder = coder; -} - -void CCoderMixerMT::ReInit() -{ - for(int i = 0; i < _coders.Size(); i++) - _coders[i].ReInit(); -} - -HRESULT CCoderMixerMT::ReturnIfError(HRESULT code) -{ - for (int i = 0; i < _coders.Size(); i++) - if (_coders[i].Result == code) - return code; - return S_OK; -} - -STDMETHODIMP CCoderMixerMT::Code(ISequentialInStream *inStream, - ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 * /* outSize */, - ICompressProgressInfo *progress) -{ - _coders.Front().InStream = inStream; - int i; - _coders.Back().OutStream = outStream; - - for (i = 0; i < _coders.Size(); i++) - if (i != _progressCoderIndex) - { - RINOK(_coders[i].Create()); - } - - _streamBinders.Clear(); - for (i = 0; i + 1 < _coders.Size(); i++) - { - _streamBinders.Add(CStreamBinder()); - CStreamBinder &sb = _streamBinders[i]; - RINOK(sb.CreateEvents()); - sb.CreateStreams(&_coders[i + 1].InStream, &_coders[i].OutStream); - } - - for(i = 0; i < _streamBinders.Size(); i++) - _streamBinders[i].ReInit(); - - for (i = 0; i < _coders.Size(); i++) - if (i != _progressCoderIndex) - _coders[i].Start(); - - _coders[_progressCoderIndex].Code(progress); - - for (i = 0; i < _coders.Size(); i++) - if (i != _progressCoderIndex) - _coders[i].WaitExecuteFinish(); - - RINOK(ReturnIfError(E_ABORT)); - RINOK(ReturnIfError(E_OUTOFMEMORY)); - - for (i = 0; i < _coders.Size(); i++) - { - HRESULT result = _coders[i].Result; - if (result != S_OK && result != E_FAIL && result != S_FALSE) - return result; - } - - RINOK(ReturnIfError(S_FALSE)); - - for (i = 0; i < _coders.Size(); i++) - { - HRESULT result = _coders[i].Result; - if (result != S_OK) - return result; - } - return S_OK; -} - -} diff --git a/CPP/7zip/Archive/Common/CoderMixerMT.h b/CPP/7zip/Archive/Common/CoderMixerMT.h deleted file mode 100644 index d2891b26..00000000 --- a/CPP/7zip/Archive/Common/CoderMixerMT.h +++ /dev/null @@ -1,70 +0,0 @@ -// CoderMixerMT.h - -#ifndef __CODER_MIXER_MT_H -#define __CODER_MIXER_MT_H - -#include "../../../Common/MyVector.h" -#include "../../../Common/MyCom.h" -#include "../../ICoder.h" -#include "../../Common/StreamBinder.h" -#include "../../Common/VirtThread.h" -#include "CoderMixer.h" - -namespace NCoderMixer { - -struct CCoder: public CCoderInfo, public CVirtThread -{ - HRESULT Result; - - virtual void Execute(); - void Code(ICompressProgressInfo *progress); - virtual ~CCoder() { CVirtThread::WaitThreadFinish(); } -}; - -/* - for each coder - AddCoder() - SetProgressIndex(UInt32 coderIndex); - - for each file - { - ReInit() - for each coder - SetCoderInfo - Code - } -*/ - - -class CCoderMixerMT: - public ICompressCoder, - public CMyUnknownImp -{ - CObjectVector<CStreamBinder> _streamBinders; - int _progressCoderIndex; - - HRESULT ReturnIfError(HRESULT code); -public: - CObjectVector<CCoder> _coders; - MY_UNKNOWN_IMP - - STDMETHOD(Code)(ISequentialInStream *inStream, - ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, - ICompressProgressInfo *progress); - - void AddCoder(ICompressCoder *coder); - void SetProgressCoderIndex(int coderIndex) { _progressCoderIndex = coderIndex; } - - void ReInit(); - void SetCoderInfo(UInt32 coderIndex, const UInt64 *inSize, const UInt64 *outSize) - { _coders[coderIndex].SetCoderInfo(inSize, outSize); } - - /* - UInt64 GetWriteProcessedSize(UInt32 binderIndex) const - { return _streamBinders[binderIndex].ProcessedSize; } - */ -}; - -} -#endif diff --git a/CPP/7zip/Archive/Common/FindSignature.cpp b/CPP/7zip/Archive/Common/FindSignature.cpp index e9a0f032..fc952fa8 100644 --- a/CPP/7zip/Archive/Common/FindSignature.cpp +++ b/CPP/7zip/Archive/Common/FindSignature.cpp @@ -2,6 +2,8 @@ #include "StdAfx.h" +#include <string.h> + #include "../../../Common/MyBuffer.h" #include "../../Common/StreamUtils.h" diff --git a/CPP/7zip/Archive/Common/FindSignature.h b/CPP/7zip/Archive/Common/FindSignature.h index e15af573..c359b9ed 100644 --- a/CPP/7zip/Archive/Common/FindSignature.h +++ b/CPP/7zip/Archive/Common/FindSignature.h @@ -1,7 +1,7 @@ // FindSignature.h -#ifndef __FINDSIGNATURE_H -#define __FINDSIGNATURE_H +#ifndef __FIND_SIGNATURE_H +#define __FIND_SIGNATURE_H #include "../../IStream.h" diff --git a/CPP/7zip/Archive/DllExports2.cpp b/CPP/7zip/Archive/DllExports2.cpp index 2b196abe..979b4bf9 100644 --- a/CPP/7zip/Archive/DllExports2.cpp +++ b/CPP/7zip/Archive/DllExports2.cpp @@ -2,6 +2,8 @@ #include "StdAfx.h" +#include "../../Common/MyWindows.h" + #include "../../Common/MyInitGuid.h" #if defined(_7ZIP_LARGE_PAGES) diff --git a/CPP/7zip/Archive/Nsis/NsisIn.h b/CPP/7zip/Archive/Nsis/NsisIn.h index 2bab5299..498784b8 100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.h +++ b/CPP/7zip/Archive/Nsis/NsisIn.h @@ -16,7 +16,7 @@ /* If NSIS_SCRIPT is defined, it will decompile NSIS script to [NSIS].nsi file. The code is much larger in that case. */ -#define NSIS_SCRIPT +// #define NSIS_SCRIPT namespace NArchive { namespace NNsis { diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/CPP/7zip/Archive/Rar/Rar5Handler.cpp new file mode 100644 index 00000000..72fe4f68 --- /dev/null +++ b/CPP/7zip/Archive/Rar/Rar5Handler.cpp @@ -0,0 +1,2683 @@ +// Rar5Handler.cpp + +#include "StdAfx.h" + +#include "../../../../C/7zCrc.h" +#include "../../../../C/CpuArch.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/FilterCoder.h" +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/RegisterArc.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "../../Common/RegisterCodec.h" + +#include "../../Compress/CopyCoder.h" + +#include "../../Crypto/Rar5Aes.h" + +#include "../Common/FindSignature.h" +#include "../Common/ItemNameUtils.h" + +#include "RarVol.h" +#include "Rar5Handler.h" + +using namespace NWindows; + +#define Get32(p) GetUi32(p) + +namespace NArchive { + +namespace NRar { + +HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize); + +} + +namespace NRar5 { + +static const unsigned kMarkerSize = 8; + +#define SIGNATURE { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0 } + +static const Byte kMarker[kMarkerSize] = SIGNATURE; + +static const size_t kCommentSize_Max = (size_t)1 << 16; + +static const char * const kHostOS[] = +{ + "Windows" + , "Unix" +}; + +static const CUInt32PCharPair k_ArcFlags[] = +{ + { 0, "Volume" }, + { 1, "VolumeField" }, + { 2, "Solid" }, + { 3, "Recovery" }, + { 4, "Lock" } +}; + + + +template <unsigned alignMask> +struct CAlignedBuffer +{ + Byte *_buf; + Byte *_bufBase; + size_t _size; + + CAlignedBuffer(): _buf(NULL), _bufBase(NULL), _size(0) {} + ~CAlignedBuffer() { ::MyFree(_bufBase); } +public: + operator Byte *() { return _buf; } + operator const Byte *() const { return _buf; } + + void AllocAtLeast(size_t size) + { + if (_buf && _size >= size) + return; + ::MyFree(_bufBase); + _buf = NULL; + _size = 0; + _bufBase = (Byte *)::MyAlloc(size + alignMask); + + if (_bufBase) + { + _size = size; + // _buf = (Byte *)(((uintptr_t)_bufBase + alignMask) & ~(uintptr_t)alignMask); + _buf = (Byte *)(((ptrdiff_t)_bufBase + alignMask) & ~(ptrdiff_t)alignMask); + } + } +}; + +static unsigned ReadVarInt(const Byte *p, size_t maxSize, UInt64 *val) +{ + *val = 0; + + for (unsigned i = 0; i < maxSize;) + { + Byte b = p[i]; + if (i < 10) + *val |= (UInt64)(b & 0x7F) << (7 * i++); + if ((b & 0x80) == 0) + return i; + } + return 0; +} + + +int CItem::FindExtra(unsigned type, unsigned &recordDataSize) const +{ + recordDataSize = 0; + size_t offset = 0; + + for (;;) + { + size_t rem = Extra.Size() - offset; + if (rem == 0) + return -1; + + { + UInt64 size; + unsigned num = ReadVarInt(Extra + offset, rem, &size); + if (num == 0) + return -1; + offset += num; + rem -= num; + if (size > rem) + return -1; + rem = (size_t)size; + } + { + UInt64 type2; + unsigned num = ReadVarInt(Extra + offset, rem, &type2); + if (num == 0) + return -1; + offset += num; + rem -= num; + + // There was BUG in RAR 5.21- : it stored (size-1) instead of (size) + // for Subdata record in Service header. + // That record always was last in bad archives, so we can fix that case. + if (type2 == NExtraRecordType::kSubdata + && RecordType == NHeaderType::kService + && rem + 1 == Extra.Size() - offset) + rem++; + + if (type2 == type) + { + recordDataSize = (unsigned)rem; + return (int)offset; + } + + offset += rem; + } + } +} + + +bool CCryptoInfo::Parse(const Byte *p, size_t size) +{ + unsigned num = ReadVarInt(p, size, &Algo); + if (num == 0) return false; p += num; size -= num; + + num = ReadVarInt(p, size, &Flags); + if (num == 0) return false; p += num; size -= num; + + if (size != 1 + 16 + 16 + (unsigned)(IsThereCheck() ? 12 : 0)) + return false; + + Cnt = p[0]; + + return true; +} + + +bool CItem::FindExtra_Version(UInt64 &version) const +{ + unsigned size; + int offset = FindExtra(NExtraRecordType::kVersion, size); + if (offset < 0) + return false; + const Byte *p = Extra + (unsigned)offset; + + UInt64 Flags; + unsigned num = ReadVarInt(p, size, &Flags); + if (num == 0) return false; p += num; size -= num; + + num = ReadVarInt(p, size, &version); + if (num == 0) return false; p += num; size -= num; + + return size == 0; +} + +bool CItem::FindExtra_Link(CLinkInfo &link) const +{ + unsigned size; + int offset = FindExtra(NExtraRecordType::kLink, size); + if (offset < 0) + return false; + const Byte *p = Extra + (unsigned)offset; + + unsigned num = ReadVarInt(p, size, &link.Type); + if (num == 0) return false; p += num; size -= num; + + num = ReadVarInt(p, size, &link.Flags); + if (num == 0) return false; p += num; size -= num; + + UInt64 len; + num = ReadVarInt(p, size, &len); + if (num == 0) return false; p += num; size -= num; + + if (size != len) + return false; + + link.NameLen = (unsigned)len; + link.NameOffset = (unsigned)(p - Extra); + return true; +} + +bool CItem::Is_CopyLink() const +{ + CLinkInfo link; + return FindExtra_Link(link) && link.Type == NLinkType::kFileCopy; +} + +void CItem::Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const +{ + CLinkInfo link; + if (!FindExtra_Link(link)) + return; + + if (link.Type != linkType) + { + if (linkType != NLinkType::kUnixSymLink) + return; + switch ((unsigned)link.Type) + { + case NLinkType::kUnixSymLink: + case NLinkType::kWinSymLink: + case NLinkType::kWinJunction: + break; + default: return; + } + } + + AString s; + s.SetFrom_CalcLen((const char *)(Extra + link.NameOffset), link.NameLen); + + UString unicode; + if (ConvertUTF8ToUnicode(s, unicode)) + prop = NItemName::GetOSName(unicode); +} + +bool CItem::GetAltStreamName(AString &name) const +{ + name.Empty(); + unsigned size; + int offset = FindExtra(NExtraRecordType::kSubdata, size); + if (offset < 0) + return false; + name.SetFrom_CalcLen((const char *)(Extra + (unsigned)offset), size); + return true; +} + + +class CHash +{ + bool _calcCRC; + UInt32 _crc; + int _blakeOffset; + CBlake2sp _blake; +public: + + void Init_NoCalc() + { + _calcCRC = false; + _crc = CRC_INIT_VAL; + _blakeOffset = -1; + } + + void Init(const CItem &item); + void Update(const void *data, size_t size); + UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } + + bool Check(const CItem &item, NCrypto::NRar5::CDecoder *cryptoDecoderSpec); +}; + +void CHash::Init(const CItem &item) +{ + _crc = CRC_INIT_VAL; + _calcCRC = item.Has_CRC(); + + _blakeOffset = item.FindExtra_Blake(); + if (_blakeOffset >= 0) + Blake2sp_Init(&_blake); +} + +void CHash::Update(const void *data, size_t size) +{ + if (_calcCRC) + _crc = CrcUpdate(_crc, data, size); + if (_blakeOffset >= 0) + Blake2sp_Update(&_blake, (const Byte *)data, size); +} + +bool CHash::Check(const CItem &item, NCrypto::NRar5::CDecoder *cryptoDecoderSpec) +{ + if (_calcCRC) + { + UInt32 crc = GetCRC(); + if (cryptoDecoderSpec) + crc = cryptoDecoderSpec->Hmac_Convert_Crc32(crc); + if (crc != item.CRC) + return false; + } + + if (_blakeOffset >= 0) + { + Byte digest[BLAKE2S_DIGEST_SIZE]; + Blake2sp_Final(&_blake, digest); + if (cryptoDecoderSpec) + cryptoDecoderSpec->Hmac_Convert_32Bytes(digest); + if (memcmp(digest, &item.Extra[(unsigned)_blakeOffset], BLAKE2S_DIGEST_SIZE) != 0) + return false; + } + + return true; +} + + +class COutStreamWithHash: + public ISequentialOutStream, + public CMyUnknownImp +{ + ISequentialOutStream *_stream; + UInt64 _pos; + UInt64 _size; + bool _size_Defined; + Byte *_destBuf; +public: + CHash _hash; + + COutStreamWithHash(): _destBuf(NULL) {} + + MY_UNKNOWN_IMP + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void Init(const CItem &item, Byte *destBuf) + { + _size_Defined = false; + _size = 0; + _destBuf = NULL; + if (!item.Is_UnknownSize()) + { + _size_Defined = true; + _size = item.Size; + _destBuf = destBuf; + } + _pos = 0; + _hash.Init(item); + } + UInt64 GetPos() const { return _pos; } +}; + + +STDMETHODIMP COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + HRESULT result = S_OK; + if (_size_Defined) + { + UInt64 rem = _size - _pos; + if (size > rem) + size = (UInt32)rem; + } + if (_stream) + result = _stream->Write(data, size, &size); + if (_destBuf) + memcpy(_destBuf + (size_t)_pos, data, size); + _hash.Update(data, size); + _pos += size; + if (processedSize) + *processedSize = size; + return result; +} + + + + + +class CInArchive +{ + CAlignedBuffer<AES_BLOCK_SIZE - 1> _buf; + size_t _bufSize; + size_t _bufPos; + ISequentialInStream *_stream; + + NCrypto::NRar5::CDecoder *m_CryptoDecoderSpec; + CMyComPtr<ICompressFilter> m_CryptoDecoder; + + + + HRESULT ReadStream_Check(void *data, size_t size); + +public: + bool m_CryptoMode; + + bool WrongPassword; + bool IsArc; + bool UnexpectedEnd; + + UInt64 StreamStartPosition; + UInt64 Position; + + bool ReadVar(UInt64 &val); + + struct CHeader + { + UInt64 Type; + UInt64 Flags; + size_t ExtraSize; + UInt64 DataSize; + }; + + HRESULT ReadBlockHeader(CHeader &h); + bool ReadFileHeader(const CHeader &header, CItem &item); + void AddToSeekValue(UInt64 addValue) + { + Position += addValue; + } + + HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, ICryptoGetTextPassword *getTextPassword, + CInArcInfo &info); +}; + + +static HRESULT MySetPassword(ICryptoGetTextPassword *getTextPassword, NCrypto::NRar5::CDecoder *cryptoDecoderSpec) +{ + CMyComBSTR password; + RINOK(getTextPassword->CryptoGetTextPassword(&password)); + AString utf8; + const unsigned kPasswordLen_MAX = 127; + UString unicode = (LPCOLESTR)password; + if (unicode.Len() > kPasswordLen_MAX) + unicode.DeleteFrom(kPasswordLen_MAX); + ConvertUnicodeToUTF8(unicode, utf8); + cryptoDecoderSpec->SetPassword((const Byte *)(const char *)utf8, utf8.Len()); + return S_OK; +} + + +bool CInArchive::ReadVar(UInt64 &val) +{ + unsigned offset = ReadVarInt(_buf + _bufPos, _bufSize - _bufPos, &val); + _bufPos += offset; + return (offset != 0); +} + + +HRESULT CInArchive::ReadStream_Check(void *data, size_t size) +{ + size_t size2 = size; + RINOK(ReadStream(_stream, data, &size2)); + if (size2 == size) + return S_OK; + UnexpectedEnd = true; + return S_FALSE; +} + + +HRESULT CInArchive::ReadBlockHeader(CHeader &h) +{ + h.Type = 0; + h.Flags = 0; + h.ExtraSize = 0; + h.DataSize = 0; + + const unsigned kStartSize = 4 + 3; + const unsigned kBufSize = AES_BLOCK_SIZE + AES_BLOCK_SIZE; // must be >= kStartSize; + Byte buf[kBufSize]; + unsigned filled; + + if (m_CryptoMode) + { + RINOK(ReadStream_Check(buf, kBufSize)); + memcpy(m_CryptoDecoderSpec->_iv, buf, AES_BLOCK_SIZE); + RINOK(m_CryptoDecoderSpec->Init()); + + _buf.AllocAtLeast(1 << 12); + if (!(Byte *)_buf) + return E_OUTOFMEMORY; + + memcpy(_buf, buf + AES_BLOCK_SIZE, AES_BLOCK_SIZE); + if (m_CryptoDecoderSpec->Filter(_buf, AES_BLOCK_SIZE) != AES_BLOCK_SIZE) + return E_FAIL; + memcpy(buf, _buf, AES_BLOCK_SIZE); + filled = AES_BLOCK_SIZE; + } + else + { + RINOK(ReadStream_Check(buf, kStartSize)); + filled = kStartSize; + } + + UInt64 val; + unsigned offset = ReadVarInt(buf + 4, 3, &val); + if (offset == 0) + return S_FALSE; + { + size_t size = (size_t)val; + _bufPos = (4 + offset); + _bufSize = _bufPos + size; + if (size < 2) + return S_FALSE; + } + + size_t allocSize = _bufSize; + if (m_CryptoMode) + allocSize = (allocSize + AES_BLOCK_SIZE - 1) & ~(size_t)(AES_BLOCK_SIZE - 1); + _buf.AllocAtLeast(allocSize); + if (!(Byte *)_buf) + return E_OUTOFMEMORY; + + memcpy(_buf, buf, filled); + + size_t rem = allocSize - filled; + AddToSeekValue(allocSize + (m_CryptoMode ? AES_BLOCK_SIZE : 0)); + RINOK(ReadStream_Check(_buf + filled, rem)); + if (m_CryptoMode) + { + if (m_CryptoDecoderSpec->Filter(_buf + filled, (UInt32)rem) != rem) + return E_FAIL; + } + + if (CrcCalc(_buf + 4, _bufSize - 4) != Get32(buf)) + return S_FALSE; + + if (!ReadVar(h.Type)) return S_FALSE; + if (!ReadVar(h.Flags)) return S_FALSE; + + if (h.Flags & NHeaderFlags::kExtra) + { + UInt64 extraSize; + if (!ReadVar(extraSize)) + return S_FALSE; + if (extraSize > _bufSize) + return S_FALSE; + h.ExtraSize = (size_t)extraSize; + } + + if (h.Flags & NHeaderFlags::kData) + { + if (!ReadVar(h.DataSize)) + return S_FALSE; + } + + return S_OK; +} + + +/* +int CInArcInfo::FindExtra(unsigned type, unsigned &recordDataSize) const +{ + recordDataSize = 0; + size_t offset = 0; + + for (;;) + { + size_t rem = Extra.Size() - offset; + if (rem == 0) + return -1; + + { + UInt64 size; + unsigned num = ReadVarInt(Extra + offset, rem, &size); + if (num == 0) + return -1; + offset += num; + rem -= num; + if (size > rem) + return -1; + rem = (size_t)size; + } + { + UInt64 type2; + unsigned num = ReadVarInt(Extra + offset, rem, &type2); + if (num == 0) + return -1; + offset += num; + rem -= num; + + if (type2 == type) + { + recordDataSize = (unsigned)rem; + return (int)offset; + } + + offset += rem; + } + } +} + + +bool CInArcInfo::FindExtra_Locator(CLocator &locator) const +{ + locator.Flags = 0; + locator.QuickOpen = 0; + locator.Recovery = 0; + + unsigned size; + int offset = FindExtra(kArcExtraRecordType_Locator, size); + if (offset < 0) + return false; + const Byte *p = Extra + (unsigned)offset; + + unsigned num; + + num = ReadVarInt(p, size, &locator.Flags); + if (num == 0) return false; p += num; size -= num; + + if (locator.Is_QuickOpen()) + { + num = ReadVarInt(p, size, &locator.QuickOpen); + if (num == 0) return false; p += num; size -= num; + } + + if (locator.Is_Recovery()) + { + num = ReadVarInt(p, size, &locator.Recovery); + if (num == 0) return false; p += num; size -= num; + } + + return true; +} +*/ + + +HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit, ICryptoGetTextPassword *getTextPassword, + CInArcInfo &info) +{ + m_CryptoMode = false; + + WrongPassword = false; + IsArc = false; + UnexpectedEnd = false; + + Position = StreamStartPosition; + + UInt64 arcStartPos = StreamStartPosition; + { + Byte marker[kMarkerSize]; + RINOK(ReadStream_FALSE(stream, marker, kMarkerSize)); + if (memcmp(marker, kMarker, kMarkerSize) == 0) + Position += kMarkerSize; + else + { + if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) + return S_FALSE; + RINOK(stream->Seek(StreamStartPosition, STREAM_SEEK_SET, NULL)); + RINOK(FindSignatureInStream(stream, kMarker, kMarkerSize, + searchHeaderSizeLimit, arcStartPos)); + arcStartPos += StreamStartPosition; + Position = arcStartPos + kMarkerSize; + RINOK(stream->Seek(Position, STREAM_SEEK_SET, NULL)); + } + } + + info.StartPos = arcStartPos; + _stream = stream; + + CHeader h; + RINOK(ReadBlockHeader(h)); + info.IsEncrypted = false; + + if (h.Type == NHeaderType::kArcEncrypt) + { + info.IsEncrypted = true; + IsArc = true; + if (!getTextPassword) + return E_NOTIMPL; + + m_CryptoMode = true; + + if (!m_CryptoDecoder) + { + m_CryptoDecoderSpec = new NCrypto::NRar5::CDecoder; + m_CryptoDecoder = m_CryptoDecoderSpec; + } + + RINOK(m_CryptoDecoderSpec->SetDecoderProps( + _buf + _bufPos, (unsigned)(_bufSize - _bufPos), false, false)); + + RINOK(MySetPassword(getTextPassword, m_CryptoDecoderSpec)); + + if (!m_CryptoDecoderSpec->CalcKey_and_CheckPassword()) + { + WrongPassword = True; + return S_FALSE; + } + + RINOK(ReadBlockHeader(h)); + } + + if (h.Type != NHeaderType::kArc) + return S_FALSE; + + IsArc = true; + info.VolNumber = 0; + + if (!ReadVar(info.Flags)) + return S_FALSE; + + if (info.Flags & NArcFlags::kVolNumber) + if (!ReadVar(info.VolNumber)) + return S_FALSE; + + if (h.ExtraSize != 0) + { + if (_bufSize - _bufPos < h.ExtraSize) + return S_FALSE; + /* + info.Extra.Alloc(h.ExtraSize); + memcpy(info.Extra, _buf + _bufPos, h.ExtraSize); + */ + _bufPos += h.ExtraSize; + + /* + CInArcInfo::CLocator locator; + if (info.FindExtra_Locator(locator)) + locator.Flags = locator.Flags; + */ + } + + if (_bufPos != _bufSize) + return S_FALSE; + + return S_OK; +} + + +bool CInArchive::ReadFileHeader(const CHeader &header, CItem &item) +{ + item.UnixMTime = 0; + item.CRC = 0; + item.Flags = 0; + + item.CommonFlags = (UInt32)header.Flags; + item.PackSize = header.DataSize; + + UInt64 flags64; + if (!ReadVar(flags64)) return false; + item.Flags = (UInt32)flags64; + + if (!ReadVar(item.Size)) return false; + + { + UInt64 attrib; + if (!ReadVar(attrib)) return false; + item.Attrib = (UInt32)attrib; + } + + if (item.Has_UnixMTime()) + { + if (_bufSize - _bufPos < 4) + return false; + item.UnixMTime = Get32(_buf + _bufPos); + _bufPos += 4; + } + + if (item.Has_CRC()) + { + if (_bufSize - _bufPos < 4) + return false; + item.CRC = Get32(_buf + _bufPos); + _bufPos += 4; + } + + { + UInt64 method; + if (!ReadVar(method)) return false; + item.Method = (UInt32)method; + } + + if (!ReadVar(item.HostOS)) return false; + + { + UInt64 len; + if (!ReadVar(len)) return false; + if (len > _bufSize - _bufPos) + return false; + item.Name.SetFrom_CalcLen((const char *)(_buf + _bufPos), (unsigned)len); + _bufPos += (unsigned)len; + } + + item.Extra.Free(); + size_t extraSize = header.ExtraSize; + if (extraSize != 0) + { + if (_bufSize - _bufPos < extraSize) + return false; + item.Extra.Alloc(extraSize); + memcpy(item.Extra, _buf + _bufPos, extraSize); + _bufPos += extraSize; + } + + + return (_bufPos == _bufSize); +} + + + +struct CLinkFile +{ + unsigned Index; + unsigned NumLinks; + CByteBuffer Data; + HRESULT Res; + bool crcOK; + + CLinkFile(): Index(0), NumLinks(0), Res(S_OK), crcOK(true) {} +}; + + +struct CUnpacker +{ + NCompress::CCopyCoder *copyCoderSpec; + CMyComPtr<ICompressCoder> copyCoder; + + CMyComPtr<ICompressCoder> LzCoders[2]; + bool NeedClearSolid[2]; + + CFilterCoder *filterStreamSpec; + CMyComPtr<ISequentialInStream> filterStream; + + NCrypto::NRar5::CDecoder *cryptoDecoderSpec; + CMyComPtr<ICompressFilter> cryptoDecoder; + + CMyComPtr<ICryptoGetTextPassword> getTextPassword; + + COutStreamWithHash *outStreamSpec; + CMyComPtr<ISequentialOutStream> outStream; + + CByteBuffer _tempBuf; + + CLinkFile *linkFile; + + CUnpacker(): linkFile(NULL) { NeedClearSolid[0] = NeedClearSolid[1] = true; } + + HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS const CItem &item, bool isSolid, bool &wrongPassword); + + HRESULT Code(const CItem &item, const CItem &lastItem, UInt64 packSize, + ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress, + bool &isCrcOK); + + HRESULT DecodeToBuf(DECL_EXTERNAL_CODECS_LOC_VARS const CItem &item, UInt64 packSize, ISequentialInStream *inStream, CByteBuffer &buffer); +}; + + +static const unsigned kLzMethodMax = 5; + +HRESULT CUnpacker::Create(DECL_EXTERNAL_CODECS_LOC_VARS const CItem &item, bool isSolid, bool &wrongPassword) +{ + wrongPassword = false; + + if (item.GetAlgoVersion() != 0) + return E_NOTIMPL; + + if (!outStream) + { + outStreamSpec = new COutStreamWithHash; + outStream = outStreamSpec; + } + + unsigned method = item.GetMethod(); + + if (method == 0) + { + if (!copyCoder) + { + copyCoderSpec = new NCompress::CCopyCoder; + copyCoder = copyCoderSpec; + } + } + else + { + if (method > kLzMethodMax) + return E_NOTIMPL; + + /* + if (item.IsSplitBefore()) + return S_FALSE; + */ + + int lzIndex = item.IsService() ? 1 : 0; + CMyComPtr<ICompressCoder> &lzCoder = LzCoders[lzIndex]; + + if (!lzCoder) + { + const UInt32 methodID = 0x40305; + RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS methodID, false, lzCoder)); + if (!lzCoder) + return E_NOTIMPL; + } + + CMyComPtr<ICompressSetDecoderProperties2> csdp; + RINOK(lzCoder.QueryInterface(IID_ICompressSetDecoderProperties2, &csdp)); + + Byte props[2] = { (Byte)(item.GetDictSize()), (Byte)(isSolid ? 1 : 0) }; + RINOK(csdp->SetDecoderProperties2(props, 2)); + } + + unsigned cryptoSize = 0; + int cryptoOffset = item.FindExtra(NExtraRecordType::kCrypto, cryptoSize); + + if (cryptoOffset >= 0) + { + if (!filterStream) + { + filterStreamSpec = new CFilterCoder(false); + filterStream = filterStreamSpec; + } + + if (!cryptoDecoder) + { + cryptoDecoderSpec = new NCrypto::NRar5::CDecoder; + cryptoDecoder = cryptoDecoderSpec; + } + + RINOK(cryptoDecoderSpec->SetDecoderProps(item.Extra + (unsigned)cryptoOffset, cryptoSize, true, item.IsService())); + + if (!getTextPassword) + { + wrongPassword = True; + return E_NOTIMPL; + } + + RINOK(MySetPassword(getTextPassword, cryptoDecoderSpec)); + + if (!cryptoDecoderSpec->CalcKey_and_CheckPassword()) + wrongPassword = True; + } + + return S_OK; +} + + +HRESULT CUnpacker::Code(const CItem &item, const CItem &lastItem, UInt64 packSize, + ISequentialInStream *volsInStream, ISequentialOutStream *realOutStream, ICompressProgressInfo *progress, + bool &isCrcOK) +{ + isCrcOK = true; + + unsigned method = item.GetMethod(); + if (method > kLzMethodMax) + return E_NOTIMPL; + + if (linkFile && !lastItem.Is_UnknownSize()) + { + size_t dataSize = (size_t)lastItem.Size; + if (dataSize != lastItem.Size) + return E_NOTIMPL; + linkFile->Data.Alloc(dataSize); + } + + bool isCryptoMode = false; + ISequentialInStream *inStream; + + if (item.IsEncrypted()) + { + filterStreamSpec->Filter = cryptoDecoder; + filterStreamSpec->SetInStream(volsInStream); + filterStreamSpec->SetOutStreamSize(NULL); + inStream = filterStream; + isCryptoMode = true; + } + else + inStream = volsInStream; + + ICompressCoder *commonCoder = (method == 0) ? copyCoder : LzCoders[item.IsService() ? 1 : 0]; + + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(lastItem, (linkFile ? (Byte *)linkFile->Data : NULL)); + + NeedClearSolid[item.IsService() ? 1 : 0] = false; + + HRESULT res = S_OK; + if (packSize != 0 || lastItem.Is_UnknownSize() || lastItem.Size != 0) + { + res = commonCoder->Code(inStream, outStream, &packSize, + lastItem.Is_UnknownSize() ? NULL : &lastItem.Size, progress); + } + else + { + res = res; + } + + if (isCryptoMode) + filterStreamSpec->ReleaseInStream(); + + UInt64 processedSize = outStreamSpec->GetPos(); + if (res == S_OK && !lastItem.Is_UnknownSize() && processedSize != lastItem.Size) + res = S_FALSE; + + // if (res == S_OK) + { + unsigned cryptoSize = 0; + int cryptoOffset = lastItem.FindExtra(NExtraRecordType::kCrypto, cryptoSize); + NCrypto::NRar5::CDecoder *crypto = NULL; + + if (cryptoOffset >= 0) + { + CCryptoInfo cryptoInfo; + if (cryptoInfo.Parse(lastItem.Extra + (unsigned)cryptoOffset, cryptoSize)) + if (cryptoInfo.UseMAC()) + crypto = cryptoDecoderSpec; + } + + isCrcOK = outStreamSpec->_hash.Check(lastItem, crypto); + } + + if (linkFile) + { + linkFile->Res = res; + linkFile->crcOK = isCrcOK; + if (!lastItem.Is_UnknownSize() && processedSize != lastItem.Size) + linkFile->Data.ChangeSize_KeepData((size_t)processedSize, (size_t)processedSize); + } + + return res; +} + + +HRESULT CUnpacker::DecodeToBuf(DECL_EXTERNAL_CODECS_LOC_VARS const CItem &item, UInt64 packSize, ISequentialInStream *inStream, CByteBuffer &buffer) +{ + CBufPtrSeqOutStream *outSpec = new CBufPtrSeqOutStream; + CMyComPtr<ISequentialOutStream> out = outSpec; + _tempBuf.AllocAtLeast((size_t)item.Size); + outSpec->Init(_tempBuf, (size_t)item.Size); + + bool wrongPassword; + + if (item.IsSolid()) + return E_NOTIMPL; + + HRESULT res = Create(EXTERNAL_CODECS_LOC_VARS item, item.IsSolid(), wrongPassword); + + if (res == S_OK) + { + if (wrongPassword) + return S_FALSE; + + CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> limitedStream(limitedStreamSpec); + limitedStreamSpec->SetStream(inStream); + limitedStreamSpec->Init(packSize); + + bool crcOK = true; + res = Code(item, item, packSize, limitedStream, out, NULL, crcOK); + if (res == S_OK) + { + if (!crcOK || outSpec->GetPos() != item.Size) + res = S_FALSE; + else + buffer.CopyFrom(_tempBuf, (size_t)item.Size); + } + } + + return res; +} + + +struct CTempBuf +{ + CByteBuffer _buf; + size_t _offset; + bool _isOK; + + void Clear() + { + _offset = 0; + _isOK = true; + } + + CTempBuf() { Clear(); } + + HRESULT Decode(DECL_EXTERNAL_CODECS_LOC_VARS + const CItem &item, + ISequentialInStream *inStream, CUnpacker &unpacker, CByteBuffer &destBuf); +}; + + +HRESULT CTempBuf::Decode(DECL_EXTERNAL_CODECS_LOC_VARS + const CItem &item, + ISequentialInStream *inStream, + CUnpacker &unpacker, + CByteBuffer &destBuf) +{ + const size_t kPackSize_Max = (1 << 24); + if (item.Size > (1 << 24) + || item.Size == 0 + || item.PackSize >= kPackSize_Max) + { + Clear(); + return S_OK; + } + + if (item.IsSplit() /* && _isOK */) + { + size_t packSize = (size_t)item.PackSize; + if (packSize > kPackSize_Max - _offset) + return S_OK; + size_t newSize = _offset + packSize; + if (newSize > _buf.Size()) + _buf.ChangeSize_KeepData(newSize, _offset); + + Byte *data = (Byte *)_buf + _offset; + RINOK(ReadStream_FALSE(inStream, data, packSize)); + + _offset += packSize; + + if (item.IsSplitAfter()) + { + CHash hash; + hash.Init(item); + hash.Update(data, packSize); + _isOK = hash.Check(item, NULL); // RAR5 doesn't use HMAC for packed part + } + } + + if (_isOK) + { + if (!item.IsSplitAfter()) + { + if (_offset == 0) + { + RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_LOC_VARS + item, item.PackSize, inStream, destBuf)); + } + else + { + CBufInStream *bufInStreamSpec = new CBufInStream; + CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec; + bufInStreamSpec->Init(_buf, _offset); + RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_LOC_VARS + item, _offset, bufInStream, destBuf)); + } + } + } + + return S_OK; +} + + + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidAttrib, + + kpidIsAltStream, + kpidEncrypted, + kpidSolid, + kpidSplitBefore, + kpidSplitAfter, + kpidCRC, + kpidHostOS, + kpidMethod, + + kpidSymLink, + kpidHardLink, + kpidCopyLink, +}; + + +static const Byte kArcProps[] = +{ + kpidTotalPhySize, + kpidCharacts, + kpidSolid, + kpidNumBlocks, + kpidEncrypted, + kpidIsVolume, + kpidVolumeIndex, + kpidNumVolumes, + kpidComment +}; + + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + + +UInt64 CHandler::GetPackSize(unsigned refIndex) const +{ + UInt64 size = 0; + unsigned index = _refs[refIndex].Item; + for (;;) + { + const CItem &item = _items[index]; + size += item.PackSize; + if (item.NextItem < 0) + return size; + index = item.NextItem; + } +} + + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + + NCOM::CPropVariant prop; + + const CInArcInfo *arcInfo = NULL; + if (!_arcs.IsEmpty()) + arcInfo = &_arcs[0].Info; + + switch (propID) + { + case kpidVolumeIndex: if (arcInfo && arcInfo->IsVolume()) prop = arcInfo->GetVolIndex(); break; + case kpidSolid: if (arcInfo) prop = arcInfo->IsSolid(); break; + case kpidCharacts: + { + if (!_arcs.IsEmpty()) + { + FLAGS_TO_PROP(k_ArcFlags, (UInt32)arcInfo->Flags, prop); + } + break; + } + case kpidEncrypted: if (arcInfo) prop = arcInfo->IsEncrypted; break; // it's for encrypted names. + case kpidIsVolume: if (arcInfo) prop = arcInfo->IsVolume(); break; + case kpidNumVolumes: prop = (UInt32)_arcs.Size(); break; + case kpidOffset: if (arcInfo && arcInfo->StartPos != 0) prop = arcInfo->StartPos; break; + + case kpidTotalPhySize: + { + if (_arcs.Size() > 1) + { + UInt64 sum = 0; + FOR_VECTOR (v, _arcs) + sum += _arcs[v].Info.GetPhySize(); + prop = sum; + } + break; + } + + case kpidPhySize: + { + if (arcInfo) + prop = arcInfo->GetPhySize(); + break; + } + + case kpidComment: + { + // if (!_arcs.IsEmpty()) + { + // const CArc &arc = _arcs[0]; + const CByteBuffer &cmt = _comment; + if (cmt.Size() != 0 && cmt.Size() < (1 << 16)) + { + AString s; + s.SetFrom_CalcLen((const char *)(const Byte *)cmt, (unsigned)cmt.Size()); + UString unicode; + if (ConvertUTF8ToUnicode(s, unicode)) + prop = unicode; + } + } + break; + } + + case kpidNumBlocks: + { + UInt32 numBlocks = 0; + FOR_VECTOR (i, _refs) + if (!_items[_refs[i].Item].IsSolid()) + numBlocks++; + prop = (UInt32)numBlocks; + 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->IsVolume()) + { + char sz[32]; + ConvertUInt64ToString(arcInfo->GetVolIndex() + 1, sz); + unsigned len = MyStringLen(sz); + AString s = "part"; + for (; len < 2; len++) + s += '0'; + s += sz; + s += ".rar"; + prop = s; + } + } + break; + + case kpidIsAltStream: prop = true; break; + } + + prop.Detach(value); + return S_OK; + + COM_TRY_END +} + + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _refs.Size(); + return S_OK; +} + + +static const Byte kRawProps[] = +{ + kpidChecksum, + kpidNtSecure +}; + + +STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) +{ + *numProps = ARRAY_SIZE(kRawProps); + return S_OK; +} + +STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) +{ + *propID = kRawProps[index]; + *name = 0; + return S_OK; +} + +STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType) +{ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; + + if (index >= _refs.Size()) + return S_OK; + + const CRefItem &ref = _refs[index]; + const CItem &item = _items[ref.Item]; + + if (item.Is_STM() && ref.Parent >= 0) + { + *parent = (UInt32)ref.Parent; + *parentType = NParentType::kAltStream; + } + + return S_OK; +} + + +STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + + if (index >= _refs.Size()) + return E_INVALIDARG; + + const CItem &item = _items[_refs[index].Item]; + + if (propID == kpidNtSecure) + { + if (item.ACL >= 0) + { + const CByteBuffer &buf = _acls[item.ACL]; + *dataSize = (UInt32)buf.Size(); + *propType = NPropDataType::kRaw; + *data = (const Byte *)buf; + } + return S_OK; + } + + if (propID == kpidChecksum) + { + int hashRecOffset = item.FindExtra_Blake(); + if (hashRecOffset >= 0) + { + *dataSize = BLAKE2S_DIGEST_SIZE; + *propType = NPropDataType::kRaw; + *data = &item.Extra[hashRecOffset]; + } + return S_OK; + } + + return S_OK; +} + + +static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CPropVariant &prop) +{ + unsigned size; + int offset = item.FindExtra(NExtraRecordType::kTime, size); + if (offset < 0) + return; + + const Byte *p = item.Extra + (unsigned)offset; + UInt64 flags; + { + unsigned num = ReadVarInt(p, size, &flags); + if (num == 0) + return; + p += num; + size -= num; + } + + if ((flags & (NTimeRecord::NFlags::kMTime << stampIndex)) == 0) + return; + + unsigned numStamps = 0; + unsigned i; + for (i = 0; i < 3; i++) + if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0) + numStamps++; + unsigned stampSizeLog = ((flags & NTimeRecord::NFlags::kUnixTime) != 0) ? 2 : 3; + + if ((numStamps << stampSizeLog) != size) + return; + + numStamps = 0; + for (i = 0; i < stampIndex; i++) + if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0) + numStamps++; + + p += (numStamps << stampSizeLog); + + FILETIME ft; + if ((flags & NTimeRecord::NFlags::kUnixTime) != 0) + NWindows::NTime::UnixTimeToFileTime(Get32(p), ft); + else + { + ft.dwLowDateTime = Get32(p); + ft.dwHighDateTime = Get32(p + 4); + } + + prop = ft; +} + + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + + NCOM::CPropVariant prop; + const CRefItem &ref = _refs[index]; + const CItem &item = _items[ref.Item]; + const CItem &lastItem = _items[ref.Last]; + + switch (propID) + { + case kpidPath: + { + UString unicodeName; + + if (item.Is_STM()) + { + AString s; + if (ref.Parent >= 0) + { + CItem &mainItem = _items[_refs[ref.Parent].Item]; + s = mainItem.Name; + } + + AString name; + item.GetAltStreamName(name); + if (name[0] != ':') + s += ':'; + s += name; + if (!ConvertUTF8ToUnicode(s, unicodeName)) + break; + } + else + { + if (!ConvertUTF8ToUnicode(item.Name, unicodeName)) + break; + if (item.Version_Defined) + { + wchar_t temp[32]; + // temp[0] = ';'; + // ConvertUInt64ToString(item.Version, temp + 1); + // unicodeName += temp; + ConvertUInt64ToString(item.Version, temp); + UString s2 = L"[VER]" WSTRING_PATH_SEPARATOR; + s2 += temp; + s2.Add_PathSepar(); + unicodeName.Insert(0, s2); + } + } + + NItemName::ConvertToOSName2(unicodeName); + prop = unicodeName; + + break; + } + + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: if (!lastItem.Is_UnknownSize()) prop = lastItem.Size; break; + case kpidPackSize: prop = GetPackSize(index); break; + + case kpidMTime: + { + TimeRecordToProp(item, NTimeRecord::k_Index_MTime, prop); + if (prop.vt == VT_EMPTY && item.Has_UnixMTime()) + { + FILETIME ft; + NWindows::NTime::UnixTimeToFileTime(item.UnixMTime, ft); + prop = ft; + } + if (prop.vt == VT_EMPTY && ref.Parent >= 0) + { + const CItem &baseItem = _items[_refs[ref.Parent].Item]; + TimeRecordToProp(baseItem, NTimeRecord::k_Index_MTime, prop); + if (prop.vt == VT_EMPTY && baseItem.Has_UnixMTime()) + { + FILETIME ft; + NWindows::NTime::UnixTimeToFileTime(baseItem.UnixMTime, ft); + prop = ft; + } + } + break; + } + case kpidCTime: TimeRecordToProp(item, NTimeRecord::k_Index_CTime, prop); break; + case kpidATime: TimeRecordToProp(item, NTimeRecord::k_Index_ATime, prop); break; + + case kpidName: + { + if (item.Is_STM()) + { + AString name; + item.GetAltStreamName(name); + if (name[0] == ':') + { + name.DeleteFrontal(1); + UString unicodeName; + if (ConvertUTF8ToUnicode(name, unicodeName)) + prop = unicodeName; + } + } + break; + } + + case kpidIsAltStream: prop = item.Is_STM(); break; + + case kpidSymLink: item.Link_to_Prop(NLinkType::kUnixSymLink, prop); break; + case kpidHardLink: item.Link_to_Prop(NLinkType::kHardLink, prop); break; + case kpidCopyLink: item.Link_to_Prop(NLinkType::kFileCopy, prop); break; + + case kpidAttrib: prop = item.GetWinAttrib(); break; + case kpidEncrypted: prop = item.IsEncrypted(); break; + case kpidSolid: prop = item.IsSolid(); break; + + case kpidSplitBefore: prop = item.IsSplitBefore(); break; + case kpidSplitAfter: prop = lastItem.IsSplitAfter(); break; + case kpidCRC: + { + const CItem *item2 = (lastItem.IsSplitAfter() ? &item : &lastItem); + if (item2->Has_CRC()) + prop = item2->CRC; + break; + } + + case kpidMethod: + { + char temp[64]; + unsigned algo = item.GetAlgoVersion(); + char *s = temp; + if (algo != 0) + { + ConvertUInt32ToString(algo, s); + s += MyStringLen(s); + *s++ = ':'; + } + unsigned m = item.GetMethod(); + { + s[0] = 'm'; + s[1] = (char)(m + '0'); + s[2] = 0; + if (!item.IsDir()) + { + s[2] = ':'; + ConvertUInt32ToString(item.GetDictSize() + 17, s + 3); + } + } + + unsigned cryptoSize = 0; + int cryptoOffset = item.FindExtra(NExtraRecordType::kCrypto, cryptoSize); + if (cryptoOffset >= 0) + { + s = temp + strlen(temp); + *s++ = ' '; + strcpy(s, "AES:"); + CCryptoInfo cryptoInfo; + if (cryptoInfo.Parse(item.Extra + (unsigned)cryptoOffset, cryptoSize)) + { + s += strlen(s); + ConvertUInt32ToString(cryptoInfo.Cnt, s); + s += strlen(s); + *s++ = ':'; + ConvertUInt64ToString(cryptoInfo.Flags, s); + } + } + + prop = temp; + break; + } + + case kpidHostOS: + if (item.HostOS < ARRAY_SIZE(kHostOS)) + prop = kHostOS[(size_t)item.HostOS]; + else + prop = (UInt64)item.HostOS; + break; + } + + prop.Detach(value); + return S_OK; + + COM_TRY_END +} + + + +// ---------- Copy Links ---------- + +static int CompareItemsPaths(const CHandler &handler, unsigned p1, unsigned p2, const AString *name1) +{ + const CItem &item1 = handler._items[handler._refs[p1].Item]; + const CItem &item2 = handler._items[handler._refs[p2].Item]; + + if (item1.Version_Defined) + { + if (!item2.Version_Defined) + return -1; + int res = MyCompare(item1.Version, item2.Version); + if (res != 0) + return res; + } + else if (item2.Version_Defined) + return 1; + + if (!name1) + name1 = &item1.Name; + return strcmp(*name1, item2.Name); +} + +static int CompareItemsPaths2(const CHandler &handler, unsigned p1, unsigned p2, const AString *name1) +{ + int res = CompareItemsPaths(handler, p1, p2, name1); + if (res != 0) + return res; + return MyCompare(p1, p2); +} + +static int CompareItemsPaths_Sort(const unsigned *p1, const unsigned *p2, void *param) +{ + return CompareItemsPaths2(*(const CHandler *)param, *p1, *p2, NULL); +} + +static int FindLink(const CHandler &handler, const CUIntVector &sorted, + const AString &s, unsigned index) +{ + unsigned left = 0, right = sorted.Size(); + for (;;) + { + if (left == right) + { + if (left > 0) + { + unsigned refIndex = sorted[left - 1]; + if (CompareItemsPaths(handler, index, refIndex, &s) == 0) + return refIndex; + } + if (right < sorted.Size()) + { + unsigned refIndex = sorted[right]; + if (CompareItemsPaths(handler, index, refIndex, &s) == 0) + return refIndex; + } + return -1; + } + + unsigned mid = (left + right) / 2; + unsigned refIndex = sorted[mid]; + int compare = CompareItemsPaths2(handler, index, refIndex, &s); + if (compare == 0) + return refIndex; + if (compare < 0) + right = mid; + else + left = mid + 1; + } +} + +void CHandler::FillLinks() +{ + unsigned i; + + for (i = 0; i < _refs.Size(); i++) + { + const CItem &item = _items[_refs[i].Item]; + if (!item.IsDir() && !item.IsService() && item.NeedUse_as_CopyLink()) + break; + } + + if (i == _refs.Size()) + return; + + CUIntVector sorted; + for (i = 0; i < _refs.Size(); i++) + { + const CItem &item = _items[_refs[i].Item]; + if (!item.IsDir() && !item.IsService()) + sorted.Add(i); + } + + if (sorted.IsEmpty()) + return; + + sorted.Sort(CompareItemsPaths_Sort, (void *)this); + + AString link; + + for (i = 0; i < _refs.Size(); i++) + { + CRefItem &ref = _refs[i]; + const CItem &item = _items[ref.Item]; + if (item.IsDir() || item.IsService() || item.PackSize != 0) + continue; + CItem::CLinkInfo linkInfo; + if (!item.FindExtra_Link(linkInfo) || linkInfo.Type != NLinkType::kFileCopy) + continue; + link.SetFrom_CalcLen((const char *)(item.Extra + linkInfo.NameOffset), linkInfo.NameLen); + int linkIndex = FindLink(*this, sorted, link, i); + if (linkIndex < 0) + continue; + if ((unsigned)linkIndex >= i) + continue; // we don't support forward links that can lead to loops + const CRefItem &linkRef = _refs[linkIndex]; + const CItem &linkItem = _items[linkRef.Item]; + if (linkItem.Size == item.Size) + { + if (linkRef.Link >= 0) + ref.Link = linkRef.Link; + else if (!linkItem.NeedUse_as_CopyLink()) + ref.Link = linkIndex; + } + } +} + + + +HRESULT CHandler::Open2(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback) +{ + CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; + CMyComPtr<ICryptoGetTextPassword> getTextPassword; + + NRar::CVolumeName seqName; + + UInt64 totalBytes = 0; + UInt64 curBytes = 0; + + if (openCallback) + { + openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + openCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); + } + + CTempBuf tempBuf; + + CUnpacker unpacker; + unpacker.getTextPassword = getTextPassword; + + int prevSplitFile = -1; + int prevMainFile = -1; + + CInArchive arch; + + for (;;) + { + CMyComPtr<IInStream> inStream; + + if (_arcs.IsEmpty()) + inStream = stream; + else + { + if (!openVolumeCallback) + break; + + if (_arcs.Size() == 1) + { + UString baseName; + { + NCOM::CPropVariant prop; + RINOK(openVolumeCallback->GetProperty(kpidName, &prop)); + if (prop.vt != VT_BSTR) + break; + baseName = prop.bstrVal; + } + if (!seqName.InitName(baseName)) + break; + } + + HRESULT result = openVolumeCallback->GetStream(seqName.GetNextName(), &inStream); + if (result == S_FALSE) + break; + if (result != S_OK) + return result; + if (!inStream) + break; + } + + UInt64 endPos = 0; + RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &arch.StreamStartPosition)); + RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(inStream->Seek(arch.StreamStartPosition, STREAM_SEEK_SET, NULL)); + + if (openCallback) + { + totalBytes += endPos; + RINOK(openCallback->SetTotal(NULL, &totalBytes)); + } + + CInArcInfo arcInfoOpen; + HRESULT res = arch.Open(inStream, maxCheckStartPosition, getTextPassword, arcInfoOpen); + if (arch.IsArc && arch.UnexpectedEnd) + _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; + if (_arcs.IsEmpty()) + { + _isArc = arch.IsArc; + } + + if (res != S_OK) + { + if (res != S_FALSE) + return res; + if (_arcs.IsEmpty()) + return res; + break; + } + + CArc &arc = _arcs.AddNew(); + CInArcInfo &arcInfo = arc.Info; + arcInfo = arcInfoOpen; + arc.Stream = inStream; + + CItem item; + + for (;;) + { + item.Clear(); + + arcInfo.EndPos = arch.Position; + + if (arch.Position > endPos) + { + _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; + break; + } + + RINOK(inStream->Seek(arch.Position, STREAM_SEEK_SET, NULL)); + + { + CInArchive::CHeader h; + HRESULT res = arch.ReadBlockHeader(h); + if (res != S_OK) + { + if (res != S_FALSE) + return res; + if (arch.UnexpectedEnd) + { + _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; + if (arcInfo.EndPos < arch.Position) + arcInfo.EndPos = arch.Position; + if (arcInfo.EndPos < endPos) + arcInfo.EndPos = endPos; + } + else + _errorFlags |= kpv_ErrorFlags_HeadersError; + break; + } + + if (h.Type == NHeaderType::kEndOfArc) + { + arcInfo.EndPos = arch.Position; + arcInfo.EndOfArchive_was_Read = true; + if (!arch.ReadVar(arcInfo.EndFlags)) + _errorFlags |= kpv_ErrorFlags_HeadersError; + if (arcInfo.IsVolume()) + { + // for multivolume archives RAR can add ZERO bytes at the end for alignment. + // We must skip these bytes to prevent phySize warning. + RINOK(inStream->Seek(arcInfo.EndPos, STREAM_SEEK_SET, NULL)); + bool areThereNonZeros; + UInt64 numZeros; + const UInt64 maxSize = 1 << 12; + RINOK(NRar::ReadZeroTail(inStream, areThereNonZeros, numZeros, maxSize)); + if (!areThereNonZeros && numZeros != 0 && numZeros <= maxSize) + arcInfo.EndPos += numZeros; + } + break; + } + + if (h.Type != NHeaderType::kFile && + h.Type != NHeaderType::kService) + { + _errorFlags |= kpv_ErrorFlags_UnsupportedFeature; + break; + } + + item.RecordType = (Byte)h.Type; + + if (!arch.ReadFileHeader(h, item)) + { + _errorFlags |= kpv_ErrorFlags_HeadersError; + break; + } + + // item.MainPartSize = (UInt32)(Position - item.Position); + item.DataPos = arch.Position; + } + + bool isOk_packSize = true; + { + arcInfo.EndPos = arch.Position; + if (arch.Position + item.PackSize < arch.Position) + { + isOk_packSize = false; + _errorFlags |= kpv_ErrorFlags_HeadersError; + if (arcInfo.EndPos < endPos) + arcInfo.EndPos = endPos; + } + else + { + arch.AddToSeekValue(item.PackSize); // Position points to next header; + arcInfo.EndPos = arch.Position; + } + } + + bool needAdd = true; + + { + if (_comment.Size() == 0 + && item.Is_CMT() + && item.PackSize < kCommentSize_Max + && item.PackSize == item.Size + && item.PackSize != 0 + && item.GetMethod() == 0 + && !item.IsSplit()) + { + RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_VARS item, item.PackSize, inStream, _comment)); + needAdd = false; + } + } + + if (needAdd) + { + CRefItem ref; + ref.Item = _items.Size(); + ref.Last = ref.Item; + ref.Parent = -1; + ref.Link = -1; + + if (item.IsService()) + { + if (item.Is_STM()) + { + if (prevMainFile >= 0) + ref.Parent = prevMainFile; + } + else + { + needAdd = false; + if (item.Is_ACL() && (!item.IsEncrypted() || arch.m_CryptoMode)) + { + if (prevMainFile >= 0 && item.Size < (1 << 24) && item.Size != 0) + { + CItem &mainItem = _items[_refs[prevMainFile].Item]; + + if (mainItem.ACL < 0) + { + CByteBuffer acl; + HRESULT res = tempBuf.Decode(EXTERNAL_CODECS_VARS item, inStream, unpacker, acl); + if (!item.IsSplitAfter()) + tempBuf.Clear(); + if (res != S_OK) + { + tempBuf.Clear(); + if (res != S_FALSE && res != E_NOTIMPL) + return res; + } + // RINOK(); + + if (res == S_OK && acl.Size() != 0) + { + if (_acls.IsEmpty() || acl != _acls.Back()) + _acls.Add(acl); + mainItem.ACL = _acls.Size() - 1; + } + } + } + } + } + } + + if (needAdd) + { + if (item.IsSplitBefore()) + { + if (prevSplitFile >= 0) + { + CRefItem &ref = _refs[prevSplitFile]; + CItem &prevItem = _items[ref.Last]; + if (item.IsNextForItem(prevItem)) + { + ref.Last = _items.Size(); + prevItem.NextItem = ref.Last; + needAdd = false; + } + } + } + } + + if (needAdd) + { + if (item.IsSplitAfter()) + prevSplitFile = _refs.Size(); + if (!item.IsService()) + prevMainFile = _refs.Size(); + _refs.Add(ref); + } + } + + { + UInt64 version; + if (item.FindExtra_Version(version)) + { + item.Version_Defined = true; + item.Version = version; + } + } + + item.VolIndex = _arcs.Size() - 1; + _items.Add(item); + + if (openCallback && (_items.Size() & 0xFF) == 0) + { + UInt64 numFiles = _items.Size(); + UInt64 numBytes = curBytes + item.DataPos; + RINOK(openCallback->SetCompleted(&numFiles, &numBytes)); + } + + if (!isOk_packSize) + break; + } + + curBytes += endPos; + if (!arcInfo.IsVolume()) + break; + if (arcInfo.EndOfArchive_was_Read + && !arcInfo.AreMoreVolumes()) + break; + } + + FillLinks(); + + return S_OK; +} + + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback) +{ + COM_TRY_BEGIN + Close(); + return Open2(stream, maxCheckStartPosition, openCallback); + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + COM_TRY_BEGIN + _errorFlags = 0; + // _warningFlags = 0; + _isArc = false; + _refs.Clear(); + _items.Clear(); + _arcs.Clear(); + _acls.Clear(); + _comment.Free(); + return S_OK; + COM_TRY_END +} + + +class CVolsInStream: + public ISequentialInStream, + public CMyUnknownImp +{ + UInt64 _rem; + ISequentialInStream *_stream; + const CObjectVector<CArc> *_arcs; + const CObjectVector<CItem> *_items; + int _itemIndex; +public: + bool CrcIsOK; +private: + CHash _hash; +public: + MY_UNKNOWN_IMP + void Init(const CObjectVector<CArc> *arcs, + const CObjectVector<CItem> *items, + unsigned itemIndex) + { + _arcs = arcs; + _items = items; + _itemIndex = itemIndex; + _stream = NULL; + CrcIsOK = true; + } + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CVolsInStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + UInt32 realProcessedSize = 0; + + while (size != 0) + { + if (!_stream) + { + if (_itemIndex < 0) + break; + const CItem &item = (*_items)[_itemIndex]; + IInStream *s = (*_arcs)[item.VolIndex].Stream; + RINOK(s->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL)); + _stream = s; + if (CrcIsOK && item.IsSplitAfter()) + _hash.Init(item); + else + _hash.Init_NoCalc(); + _rem = item.PackSize; + } + { + UInt32 cur = size; + if (cur > _rem) + cur = (UInt32)_rem; + UInt32 num = cur; + HRESULT res = _stream->Read(data, cur, &cur); + _hash.Update(data, cur); + realProcessedSize += cur; + if (processedSize) + *processedSize = realProcessedSize; + data = (Byte *)data + cur; + size -= cur; + _rem -= cur; + if (_rem == 0) + { + const CItem &item = (*_items)[_itemIndex]; + _itemIndex = item.NextItem; + if (!_hash.Check(item, NULL)) // RAR doesn't use MAC here + CrcIsOK = false; + _stream = NULL; + } + if (res != S_OK) + return res; + if (realProcessedSize != 0) + return S_OK; + if (cur == 0 && num != 0) + return S_OK; + } + } + + return S_OK; +} + + +static int FindLinkBuf(CObjectVector<CLinkFile> &linkFiles, unsigned index) +{ + unsigned left = 0, right = linkFiles.Size(); + for (;;) + { + if (left == right) + return -1; + unsigned mid = (left + right) / 2; + unsigned linkIndex = linkFiles[mid].Index; + if (index == linkIndex) + return mid; + if (index < linkIndex) + right = mid; + else + left = mid + 1; + } +} + + +static inline int DecoderRes_to_OpRes(HRESULT res, bool crcOK) +{ + if (res == E_NOTIMPL) + return NExtract::NOperationResult::kUnsupportedMethod; + // if (res == S_FALSE) + if (res != S_OK) + return NExtract::NOperationResult::kDataError; + return crcOK ? + NExtract::NOperationResult::kOK : + NExtract::NOperationResult::kCRCError; +} + + +static HRESULT CopyData_with_Progress(const Byte *data, size_t size, + ISequentialOutStream *outStream, ICompressProgressInfo *progress) +{ + size_t pos = 0; + + while (pos < size) + { + const UInt32 kStepSize = ((UInt32)1 << 24); + UInt32 cur32; + { + size_t cur = size - pos; + if (cur > kStepSize) + cur = kStepSize; + cur32 = (UInt32)cur; + } + RINOK(outStream->Write(data + pos, cur32, &cur32)); + if (cur32 == 0) + return E_FAIL; + pos += cur32; + if (progress) + { + UInt64 pos64 = pos; + RINOK(progress->SetRatioInfo(&pos64, &pos64)); + } + } + + return S_OK; +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + + bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _refs.Size(); + if (numItems == 0) + return S_OK; + + CByteArr extractStatuses(_refs.Size()); + memset(extractStatuses, 0, _refs.Size()); + + // we don't want to use temp buffer for big link files. + const size_t k_CopyLinkFile_MaxSize = (size_t)1 << (28 + sizeof(size_t) / 2); + + const Byte kStatus_Extract = 1 << 0; + const Byte kStatus_Skip = 1 << 1; + const Byte kStatus_Link = 1 << 2; + + CObjectVector<CLinkFile> linkFiles; + + { + UInt64 total = 0; + bool thereAreLinks = false; + + { + unsigned solidLimit = 0; + for (UInt32 t = 0; t < numItems; t++) + { + unsigned index = allFilesMode ? t : indices[t]; + const CRefItem &ref = _refs[index]; + const CItem &item = _items[ref.Item]; + + extractStatuses[index] |= kStatus_Extract; + total += item.Size; + + if (ref.Link >= 0) + { + if (!testMode) + { + if ((unsigned)ref.Link < index) + { + const CItem &linkItem = _items[_refs[(unsigned)ref.Link].Item]; + if (linkItem.IsSolid() && linkItem.Size <= k_CopyLinkFile_MaxSize) + { + if (extractStatuses[(unsigned)ref.Link] == 0) + total += linkItem.Size; + extractStatuses[(unsigned)ref.Link] |= kStatus_Link; + thereAreLinks = true; + } + } + } + continue; + } + + if (item.IsService()) + continue; + + if (item.IsSolid()) + { + unsigned j = index; + + while (j > solidLimit) + { + j--; + const CItem &item2 = _items[_refs[j].Item]; + if (!item2.IsService()) + { + if (extractStatuses[j] == 0) + total += item2.Size; + extractStatuses[j] |= kStatus_Skip; + if (!item2.IsSolid()) + break; + } + } + } + + solidLimit = index + 1; + } + } + + if (thereAreLinks) + { + unsigned solidLimit = 0; + + FOR_VECTOR(i, _refs) + { + if ((extractStatuses[i] & kStatus_Link) == 0) + continue; + const CItem &item = _items[_refs[i].Item]; + /* + if (item.IsService()) + continue; + */ + + CLinkFile &linkFile = linkFiles.AddNew(); + linkFile.Index = i; + + if (item.IsSolid()) + { + unsigned j = i; + + while (j > solidLimit) + { + j--; + const CItem &item2 = _items[_refs[j].Item]; + if (!item2.IsService()) + { + if (extractStatuses[j] != 0) + break; + extractStatuses[j] = kStatus_Skip; + total += item2.Size; + if (!item2.IsSolid()) + break; + } + } + } + + solidLimit = i + 1; + } + + for (UInt32 t = 0; t < numItems; t++) + { + unsigned index = allFilesMode ? t : indices[t]; + const CRefItem &ref = _refs[index]; + + int linkIndex = ref.Link; + if (linkIndex < 0 || (unsigned)linkIndex >= index) + continue; + const CItem &linkItem = _items[_refs[(unsigned)linkIndex].Item]; + if (!linkItem.IsSolid() || linkItem.Size > k_CopyLinkFile_MaxSize) + continue; + int bufIndex = FindLinkBuf(linkFiles, linkIndex); + if (bufIndex < 0) + return E_FAIL; + linkFiles[bufIndex].NumLinks++; + } + } + + RINOK(extractCallback->SetTotal(total)); + } + + + UInt64 totalUnpacked = 0; + UInt64 totalPacked = 0; + UInt64 curUnpackSize = 0; + UInt64 curPackSize = 0; + + CUnpacker unpacker; + + CVolsInStream *volsInStreamSpec = new CVolsInStream; + CMyComPtr<ISequentialInStream> volsInStream = volsInStreamSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + // bool needClearSolid = true; + + FOR_VECTOR(i, _refs) + { + if (extractStatuses[i] == 0) + continue; + + totalUnpacked += curUnpackSize; + totalPacked += curPackSize; + lps->InSize = totalPacked; + lps->OutSize = totalUnpacked; + RINOK(lps->SetCur()); + + CMyComPtr<ISequentialOutStream> realOutStream; + + Int32 askMode = + ((extractStatuses[i] & kStatus_Extract) != 0) ? (testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract) : + NExtract::NAskMode::kSkip; + + unpacker.linkFile = NULL; + + if (((extractStatuses[i] & kStatus_Link) != 0)) + { + int bufIndex = FindLinkBuf(linkFiles, i); + if (bufIndex < 0) + return E_FAIL; + unpacker.linkFile = &linkFiles[bufIndex]; + } + + UInt32 index = i; + + const CRefItem *ref = &_refs[index]; + const CItem *item = &_items[ref->Item]; + + curUnpackSize = item->Size; + curPackSize = GetPackSize(index); + + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + bool isSolid; + { + bool &needClearSolid = unpacker.NeedClearSolid[item->IsService() ? 1 : 0]; + isSolid = (item->IsSolid() && !needClearSolid); + if (item->IsService()) + isSolid = false; + needClearSolid = !item->IsSolid(); + } + + if (item->IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + + int index2 = ref->Link; + + int bufIndex = -1; + + if (index2 >= 0) + { + const CRefItem &ref2 = _refs[index2]; + const CItem &item2 = _items[ref2.Item]; + if (!item2.IsSolid()) + { + item = &item2; + ref = &ref2; + curUnpackSize = item->Size; + curPackSize = GetPackSize(index2); + } + else if ((unsigned)index2 < index) + bufIndex = FindLinkBuf(linkFiles, index2); + } + + if (!realOutStream) + { + if (testMode) + { + if (item->Is_CopyLink() && item->PackSize == 0) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + } + else + { + if (item->IsService()) + continue; + + bool needDecode = false; + + for (unsigned n = i + 1; n < _refs.Size(); n++) + { + const CItem &nextItem = _items[_refs[n].Item]; + if (nextItem.IsService()) + continue; + if (!nextItem.IsSolid()) + break; + if (extractStatuses[i] != 0) + { + needDecode = true; + break; + } + } + + if (!needDecode) + continue; + + askMode = NExtract::NAskMode::kSkip; + } + } + + RINOK(extractCallback->PrepareOperation(askMode)); + + if (bufIndex >= 0) + { + CLinkFile &linkFile = linkFiles[bufIndex]; + if (linkFile.NumLinks == 0) + return E_FAIL; + if (realOutStream) + { + RINOK(CopyData_with_Progress(linkFile.Data, linkFile.Data.Size(), realOutStream, progress)); + } + if (--linkFile.NumLinks == 0) + linkFile.Data.Free(); + RINOK(extractCallback->SetOperationResult(DecoderRes_to_OpRes(linkFile.Res, linkFile.crcOK))); + continue; + } + + if (item->Is_CopyLink() && item->PackSize == 0) + { + RINOK(extractCallback->SetOperationResult( + realOutStream ? + NExtract::NOperationResult::kUnsupportedMethod: + NExtract::NOperationResult::kOK)); + continue; + } + + volsInStreamSpec->Init(&_arcs, &_items, ref->Item); + + UInt64 packSize = curPackSize; + + if (item->IsEncrypted()) + if (!unpacker.getTextPassword) + extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&unpacker.getTextPassword); + + bool wrongPassword; + HRESULT result = unpacker.Create(EXTERNAL_CODECS_VARS *item, isSolid, wrongPassword); + + if (wrongPassword) + { + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kWrongPassword)); + continue; + } + + bool crcOK = true; + if (result == S_OK) + result = unpacker.Code(*item, _items[ref->Last], packSize, volsInStream, realOutStream, progress, crcOK); + realOutStream.Release(); + if (!volsInStreamSpec->CrcIsOK) + crcOK = false; + + int opRes = crcOK ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kCRCError; + + if (result != S_OK) + { + if (result == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else if (result == E_NOTIMPL) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else + return result; + } + + RINOK(extractCallback->SetOperationResult(opRes)); + } + + { + FOR_VECTOR(i, linkFiles) + if (linkFiles[i].NumLinks != 0) + return E_FAIL; + } + + return S_OK; + + COM_TRY_END +} + + +IMPL_ISetCompressCodecsInfo + +REGISTER_ARC_I( + "Rar5", "rar r00", 0, 0xCC, + kMarker, + 0, + NArcInfoFlags::kFindSignature, + NULL) + +}} + + +class CBlake2spHasher: + public IHasher, + public CMyUnknownImp +{ + CBlake2sp _blake; + Byte mtDummy[1 << 7]; + +public: + CBlake2spHasher() { Init(); } + + MY_UNKNOWN_IMP + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CBlake2spHasher::Init() throw() +{ + Blake2sp_Init(&_blake); +} + +STDMETHODIMP_(void) CBlake2spHasher::Update(const void *data, UInt32 size) throw() +{ + Blake2sp_Update(&_blake, (const Byte *)data, size); +} + +STDMETHODIMP_(void) CBlake2spHasher::Final(Byte *digest) throw() +{ + Blake2sp_Final(&_blake, digest); +} + +REGISTER_HASHER(CBlake2spHasher, 0x202, "BLAKE2sp", BLAKE2S_DIGEST_SIZE) diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.h b/CPP/7zip/Archive/Rar/Rar5Handler.h new file mode 100644 index 00000000..5eaf0075 --- /dev/null +++ b/CPP/7zip/Archive/Rar/Rar5Handler.h @@ -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 diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp index 516e5d7f..d6d894f4 100644 --- a/CPP/7zip/Archive/Rar/RarHandler.cpp +++ b/CPP/7zip/Archive/Rar/RarHandler.cpp @@ -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); - - 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; -} + MY_UNKNOWN_IMP -HRESULT CFolderInStream::OpenStream() -{ - while (_curIndex < _refItem.NumItems) + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + + void Init(const CObjectVector<CArc> *arcs, + const CObjectVector<CItem> *items, + const CRefItem &refItem) { - 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; + _arcs = arcs; + _items = items; + _refItem = refItem; + _curIndex = 0; + _stream = NULL; + CrcIsOK = true; } - return S_OK; -} -HRESULT CFolderInStream::CloseStream() -{ - CRCs.Add(CRC_GET_DIGEST(_crc)); - _stream.Release(); - _fileIsOpen = false; - return S_OK; -} + bool CrcIsOK; +}; -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++) - { - 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) + if (!volsInStream) { - 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()) - */ - { - 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)); - } - /* - else + if (result != S_OK) { - 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)); + if (result == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else if (result == E_NOTIMPL) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else + return result; } - */ + RINOK(extractCallback->SetOperationResult(opRes)); } + return S_OK; COM_TRY_END } diff --git a/CPP/7zip/Archive/Rar/RarVol.h b/CPP/7zip/Archive/Rar/RarVol.h new file mode 100644 index 00000000..d0f91de6 --- /dev/null +++ b/CPP/7zip/Archive/Rar/RarVol.h @@ -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 diff --git a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp index ae005ac5..8dd99869 100644 --- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp +++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp @@ -29,11 +29,13 @@ HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID pro { NCOM::CPropVariant prop; RINOK(callback->GetProperty(index, propId, &prop)); + if (prop.vt == VT_BSTR) { UString s = prop.bstrVal; if (convertSlash) s = NItemName::MakeLegalName(s); + if (codePage == CP_UTF8) { ConvertUnicodeToUTF8(s, res); @@ -44,9 +46,11 @@ HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID pro } else if (prop.vt != VT_EMPTY) return E_INVALIDARG; + return S_OK; } + // sort old files with original order. static int CompareUpdateItems(void *const *p1, void *const *p2, void *) @@ -57,33 +61,39 @@ static int CompareUpdateItems(void *const *p1, void *const *p2, void *) { if (u2.NewProps) return -1; - return MyCompare(u1.IndexInArchive, u2.IndexInArchive); + return MyCompare(u1.IndexInArc, u2.IndexInArc); } if (!u2.NewProps) return 1; return MyCompare(u1.IndexInClient, u2.IndexInClient); } + STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *callback) { COM_TRY_BEGIN + if ((_stream && (_error != k_ErrorType_OK /* || _isSparse */)) || _seqStream) return E_NOTIMPL; CObjectVector<CUpdateItem> updateItems; UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage); + for (UInt32 i = 0; i < numItems; i++) { CUpdateItem ui; Int32 newData; Int32 newProps; - UInt32 indexInArchive; + UInt32 indexInArc; + if (!callback) return E_FAIL; - RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); + + RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc)); + ui.NewProps = IntToBool(newProps); ui.NewData = IntToBool(newData); - ui.IndexInArchive = indexInArchive; + ui.IndexInArc = indexInArc; ui.IndexInClient = i; if (IntToBool(newProps)) @@ -109,6 +119,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt else ui.Mode = prop.ulVal; } + { NCOM::CPropVariant prop; RINOK(callback->GetProperty(i, kpidMTime, &prop)); @@ -119,6 +130,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt else ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime); } + RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, true)); if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/') ui.Name += '/'; @@ -139,14 +151,18 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return E_INVALIDARG; */ } + updateItems.Add(ui); } + if (_thereIsPaxExtendedHeader) { // we restore original order of files, if there is pax header block updateItems.Sort(CompareUpdateItems, NULL); } + return UpdateArchive(_stream, outStream, _items, updateItems, codePage, callback); + COM_TRY_END } diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp index 3adbdee9..0cdb30d1 100644 --- a/CPP/7zip/Archive/Tar/TarUpdate.cpp +++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp @@ -43,7 +43,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, if (ui.NewData) complexity += ui.Size; else - complexity += inputItems[ui.IndexInArchive].GetFullSize(); + complexity += inputItems[ui.IndexInArc].GetFullSize(); } RINOK(updateCallback->SetTotal(complexity)); @@ -68,12 +68,14 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, const CUpdateItem &ui = updateItems[i]; CItem item; + if (ui.NewProps) { item.Mode = ui.Mode; item.Name = ui.Name; item.User = ui.User; item.Group = ui.Group; + if (ui.IsDir) { item.LinkFlag = NFileHeader::NLinkFlag::kDirectory; @@ -84,6 +86,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, item.LinkFlag = NFileHeader::NLinkFlag::kNormal; item.PackSize = ui.Size; } + item.MTime = ui.MTime; item.DeviceMajorDefined = false; item.DeviceMinorDefined = false; @@ -92,7 +95,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, memcpy(item.Magic, NFileHeader::NMagic::kUsTar_00, 8); } else - item = inputItems[ui.IndexInArchive]; + item = inputItems[ui.IndexInArc]; AString symLink; if (ui.NewData || ui.NewProps) @@ -116,6 +119,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, CMyComPtr<ISequentialInStream> fileInStream; bool needWrite = true; + if (!symLink.IsEmpty()) { item.PackSize = 0; @@ -124,6 +128,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, else { HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); + if (res == S_FALSE) needWrite = false; else @@ -141,10 +146,17 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK) { item.PackSize = size2; + item.Size = size2; item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);; } } } + else + { + item.PackSize = 0; + item.Size = 0; + } + { AString hardLink; RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, codePage, true)); @@ -183,13 +195,15 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, RINOK(outArchive.FillDataResidual(item.PackSize)); } } + complexity += item.PackSize; RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } else { - const CItemEx &existItem = inputItems[ui.IndexInArchive]; + const CItemEx &existItem = inputItems[ui.IndexInArc]; UInt64 size; + if (ui.NewProps) { // memcpy(item.Magic, NFileHeader::NMagic::kEmpty, 8); @@ -225,12 +239,13 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL)); size = existItem.GetFullSize(); } + streamSpec->Init(size); if (opCallback) { RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArchive, + NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc, NUpdateNotifyOp::kReplicate)) } @@ -242,6 +257,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, complexity += size; } } + lps->InSize = lps->OutSize = complexity; RINOK(lps->SetCur()); return outArchive.WriteFinishHeader(); diff --git a/CPP/7zip/Archive/Tar/TarUpdate.h b/CPP/7zip/Archive/Tar/TarUpdate.h index c2393416..b758635f 100644 --- a/CPP/7zip/Archive/Tar/TarUpdate.h +++ b/CPP/7zip/Archive/Tar/TarUpdate.h @@ -4,6 +4,7 @@ #define __TAR_UPDATE_H #include "../IArchive.h" + #include "TarItem.h" namespace NArchive { @@ -11,10 +12,10 @@ namespace NTar { struct CUpdateItem { - int IndexInArchive; + int IndexInArc; int IndexInClient; - Int64 MTime; UInt64 Size; + Int64 MTime; UInt32 Mode; bool NewData; bool NewProps; @@ -22,6 +23,8 @@ struct CUpdateItem AString Name; AString User; AString Group; + + CUpdateItem(): Size(0), IsDir(false) {} }; HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp index 7e89bf48..5ef3bdf9 100644 --- a/CPP/7zip/Archive/XarHandler.cpp +++ b/CPP/7zip/Archive/XarHandler.cpp @@ -358,15 +358,24 @@ HRESULT CHandler::Open2(IInStream *stream) return S_FALSE; UInt64 totalPackSize = 0; + unsigned numMainFiles = 0; + FOR_VECTOR(i, _files) { const CFile &file = _files[i]; file.UpdateTotalPackSize(totalPackSize); if (file.Name == "Payload") + { _mainSubfile = i; + numMainFiles++; + } if (file.Name == "PackageInfo") _is_pkg = true; } + + if (numMainFiles > 1) + _mainSubfile = -1; + _phySize = _dataStartPos + totalPackSize; return S_OK; diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp index f1c8b227..aa06c4f8 100644 --- a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp @@ -207,7 +207,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt } if (IntToBool(newData)) { - UInt64 size; + UInt64 size = 0; + if (!ui.IsDir) { NCOM::CPropVariant prop; RINOK(callback->GetProperty(i, kpidSize, &prop)); @@ -219,6 +220,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt largestSizeDefined = true; } ui.Size = size; + // ui.Size -= ui.Size / 2; } updateItems.Add(ui); diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index 6f495305..3c466424 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -591,6 +591,29 @@ static bool FlagsAreSame(const CItem &i1, const CItem &i2) return ((i1.Flags & mask) == (i2.Flags & mask)); } +// #ifdef _WIN32 +static bool AreEqualPaths_IgnoreSlashes(const char *s1, const char *s2) +{ + for (;;) + { + char c1 = *s1++; + char c2 = *s2++; + if (c1 == c2) + { + if (c1 == 0) + return true; + } + else + { + if (c1 == '\\') c1 = '/'; + if (c2 == '\\') c2 = '/'; + if (c1 != c2) + return false; + } + } +} +// #endif + static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem) { if (!FlagsAreSame(cdItem, localItem)) @@ -611,7 +634,30 @@ static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem) return false; */ if (cdItem.Name != localItem.Name) - return false; + { + // #ifdef _WIN32 + // some xap files use backslash in central dir items. + // we can ignore such errors in windows, where all slashes are converted to backslashes + unsigned hostOs = cdItem.GetHostOS(); + + if (hostOs == NFileHeader::NHostOS::kFAT || + hostOs == NFileHeader::NHostOS::kNTFS) + { + if (!AreEqualPaths_IgnoreSlashes(cdItem.Name, localItem.Name)) + { + // pkzip 2.50 uses DOS encoding in central dir and WIN encoding in local header. + // so we ignore that error + if (hostOs != NFileHeader::NHostOS::kFAT + || cdItem.MadeByVersion.Version != 25) + return false; + } + } + /* + else + #endif + return false; + */ + } return true; } diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index 9a9526cc..7d03056c 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -103,7 +103,8 @@ static void SetFileHeader( item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir; item.Method = kMethodForDirectory; item.PackSize = 0; - item.Crc = 0; // test it + item.Size = 0; + item.Crc = 0; } } |