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

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive')
-rw-r--r--CPP/7zip/Archive/7z/7zDecode.cpp6
-rw-r--r--CPP/7zip/Archive/7z/7zHandler.h1
-rw-r--r--CPP/7zip/Archive/7z/7zHandlerOut.cpp24
-rw-r--r--CPP/7zip/Archive/7z/7zUpdate.cpp14
-rw-r--r--CPP/7zip/Archive/7z/7zUpdate.h4
-rw-r--r--CPP/7zip/Archive/7z/makefile8
-rw-r--r--CPP/7zip/Archive/Common/CoderMixer.cpp19
-rw-r--r--CPP/7zip/Archive/Common/CoderMixer.h32
-rw-r--r--CPP/7zip/Archive/Common/CoderMixer2MT.cpp254
-rw-r--r--CPP/7zip/Archive/Common/CoderMixer2MT.h77
-rw-r--r--CPP/7zip/Archive/Common/CoderMixer2ST.cpp562
-rw-r--r--CPP/7zip/Archive/Common/CoderMixer2ST.h129
-rw-r--r--CPP/7zip/Archive/Common/CoderMixerMT.cpp99
-rw-r--r--CPP/7zip/Archive/Common/CoderMixerMT.h70
-rw-r--r--CPP/7zip/Archive/Common/FindSignature.cpp2
-rw-r--r--CPP/7zip/Archive/Common/FindSignature.h4
-rw-r--r--CPP/7zip/Archive/DllExports2.cpp2
-rw-r--r--CPP/7zip/Archive/Nsis/NsisIn.h2
-rw-r--r--CPP/7zip/Archive/Rar/Rar5Handler.cpp2683
-rw-r--r--CPP/7zip/Archive/Rar/Rar5Handler.h410
-rw-r--r--CPP/7zip/Archive/Rar/RarHandler.cpp417
-rw-r--r--CPP/7zip/Archive/Rar/RarVol.h129
-rw-r--r--CPP/7zip/Archive/Tar/TarHandlerOut.cpp24
-rw-r--r--CPP/7zip/Archive/Tar/TarUpdate.cpp24
-rw-r--r--CPP/7zip/Archive/Tar/TarUpdate.h7
-rw-r--r--CPP/7zip/Archive/XarHandler.cpp9
-rw-r--r--CPP/7zip/Archive/Zip/ZipHandlerOut.cpp4
-rw-r--r--CPP/7zip/Archive/Zip/ZipIn.cpp48
-rw-r--r--CPP/7zip/Archive/Zip/ZipUpdate.cpp3
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;
}
}