mirror of
https://github.com/holub/mame
synced 2025-07-12 21:19:14 +03:00
1087 lines
29 KiB
C++
1087 lines
29 KiB
C++
// 7zHandlerOut.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "../../../Common/ComTry.h"
|
|
#include "../../../Common/StringToInt.h"
|
|
#include "../../../Common/Wildcard.h"
|
|
|
|
#include "../Common/ItemNameUtils.h"
|
|
#include "../Common/ParseProperties.h"
|
|
|
|
#include "7zHandler.h"
|
|
#include "7zOut.h"
|
|
#include "7zUpdate.h"
|
|
|
|
#ifndef Z7_EXTRACT_ONLY
|
|
|
|
using namespace NWindows;
|
|
|
|
namespace NArchive {
|
|
namespace N7z {
|
|
|
|
#define k_LZMA_Name "LZMA"
|
|
#define kDefaultMethodName "LZMA2"
|
|
#define k_Copy_Name "Copy"
|
|
|
|
#define k_MatchFinder_ForHeaders "BT2"
|
|
|
|
static const UInt32 k_NumFastBytes_ForHeaders = 273;
|
|
static const UInt32 k_Level_ForHeaders = 5;
|
|
static const UInt32 k_Dictionary_ForHeaders =
|
|
#ifdef UNDER_CE
|
|
1 << 18;
|
|
#else
|
|
1 << 20;
|
|
#endif
|
|
|
|
Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type))
|
|
{
|
|
*type = NFileTimeType::kWindows;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m)
|
|
{
|
|
bool isFilter;
|
|
dest.CodecIndex = FindMethod_Index(
|
|
EXTERNAL_CODECS_VARS
|
|
m.MethodName, true,
|
|
dest.Id, dest.NumStreams, isFilter);
|
|
if (dest.CodecIndex < 0)
|
|
return E_INVALIDARG;
|
|
(CProps &)dest = (CProps &)m;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod)
|
|
{
|
|
if (!_compressHeaders)
|
|
return S_OK;
|
|
COneMethodInfo m;
|
|
m.MethodName = k_LZMA_Name;
|
|
m.AddProp_Ascii(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders);
|
|
m.AddProp_Level(k_Level_ForHeaders);
|
|
m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders);
|
|
m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders);
|
|
m.AddProp_NumThreads(1);
|
|
|
|
CMethodFull &methodFull = headerMethod.Methods.AddNew();
|
|
return PropsMethod_To_FullMethod(methodFull, m);
|
|
}
|
|
|
|
|
|
HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode)
|
|
{
|
|
methodMode.Bonds = _bonds;
|
|
|
|
// we create local copy of _methods. So we can modify it.
|
|
CObjectVector<COneMethodInfo> methods = _methods;
|
|
|
|
{
|
|
FOR_VECTOR (i, methods)
|
|
{
|
|
AString &methodName = methods[i].MethodName;
|
|
if (methodName.IsEmpty())
|
|
methodName = kDefaultMethodName;
|
|
}
|
|
if (methods.IsEmpty())
|
|
{
|
|
COneMethodInfo &m = methods.AddNew();
|
|
m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName);
|
|
methodMode.DefaultMethod_was_Inserted = true;
|
|
}
|
|
}
|
|
|
|
if (!_filterMethod.MethodName.IsEmpty())
|
|
{
|
|
// if (methodMode.Bonds.IsEmpty())
|
|
{
|
|
FOR_VECTOR (k, methodMode.Bonds)
|
|
{
|
|
CBond2 &bond = methodMode.Bonds[k];
|
|
bond.InCoder++;
|
|
bond.OutCoder++;
|
|
}
|
|
methods.Insert(0, _filterMethod);
|
|
methodMode.Filter_was_Inserted = true;
|
|
}
|
|
}
|
|
|
|
const UInt64 kSolidBytes_Min = (1 << 24);
|
|
const UInt64 kSolidBytes_Max = ((UInt64)1 << 32);
|
|
|
|
bool needSolid = false;
|
|
|
|
FOR_VECTOR (i, methods)
|
|
{
|
|
COneMethodInfo &oneMethodInfo = methods[i];
|
|
|
|
SetGlobalLevelTo(oneMethodInfo);
|
|
|
|
#ifndef Z7_ST
|
|
const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0);
|
|
if (!numThreads_WasSpecifiedInMethod)
|
|
{
|
|
// here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already
|
|
CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, methodMode.NumThreads);
|
|
}
|
|
#endif
|
|
|
|
CMethodFull &methodFull = methodMode.Methods.AddNew();
|
|
RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo))
|
|
|
|
#ifndef Z7_ST
|
|
methodFull.Set_NumThreads = true;
|
|
methodFull.NumThreads = methodMode.NumThreads;
|
|
#endif
|
|
|
|
if (methodFull.Id != k_Copy)
|
|
needSolid = true;
|
|
|
|
UInt64 dicSize;
|
|
switch (methodFull.Id)
|
|
{
|
|
case k_LZMA:
|
|
case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break;
|
|
case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break;
|
|
case k_Deflate: dicSize = (UInt32)1 << 15; break;
|
|
case k_Deflate64: dicSize = (UInt32)1 << 16; break;
|
|
case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break;
|
|
// case k_ZSTD: dicSize = 1 << 23; break;
|
|
default: continue;
|
|
}
|
|
|
|
UInt64 numSolidBytes;
|
|
|
|
/*
|
|
if (methodFull.Id == k_ZSTD)
|
|
{
|
|
// continue;
|
|
NCompress::NZstd::CEncoderProps encoderProps;
|
|
RINOK(oneMethodInfo.Set_PropsTo_zstd(encoderProps));
|
|
CZstdEncProps &zstdProps = encoderProps.EncProps;
|
|
ZstdEncProps_NormalizeFull(&zstdProps);
|
|
UInt64 cs = (UInt64)(zstdProps.jobSize);
|
|
UInt32 winSize = (UInt32)(1 << zstdProps.windowLog);
|
|
if (cs < winSize)
|
|
cs = winSize;
|
|
numSolidBytes = cs << 6;
|
|
const UInt64 kSolidBytes_Zstd_Max = ((UInt64)1 << 34);
|
|
if (numSolidBytes > kSolidBytes_Zstd_Max)
|
|
numSolidBytes = kSolidBytes_Zstd_Max;
|
|
|
|
methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder
|
|
|
|
#ifndef Z7_ST
|
|
if (!numThreads_WasSpecifiedInMethod
|
|
&& !methodMode.NumThreads_WasForced
|
|
&& methodMode.MemoryUsageLimit_WasSet
|
|
)
|
|
{
|
|
const UInt32 numThreads_Original = methodMode.NumThreads;
|
|
const UInt32 numThreads_New = ZstdEncProps_GetNumThreads_for_MemUsageLimit(
|
|
&zstdProps,
|
|
methodMode.MemoryUsageLimit,
|
|
numThreads_Original);
|
|
if (numThreads_Original != numThreads_New)
|
|
{
|
|
CMultiMethodProps::SetMethodThreadsTo_Replace(methodFull, numThreads_New);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
*/
|
|
if (methodFull.Id == k_LZMA2)
|
|
{
|
|
// he we calculate default chunk Size for LZMA2 as defined in LZMA2 encoder code
|
|
/* lzma2 code use dictionary up to fake 4 GiB to calculate ChunkSize.
|
|
So we do same */
|
|
UInt64 cs = (UInt64)dicSize << 2;
|
|
const UInt32 kMinSize = (UInt32)1 << 20;
|
|
const UInt32 kMaxSize = (UInt32)1 << 28;
|
|
if (cs < kMinSize) cs = kMinSize;
|
|
if (cs > kMaxSize) cs = kMaxSize;
|
|
if (cs < dicSize) cs = dicSize;
|
|
cs += (kMinSize - 1);
|
|
cs &= ~(UInt64)(kMinSize - 1);
|
|
// we want to use at least 64 chunks (threads) per one solid block.
|
|
|
|
// here we don't use chunkSize property
|
|
numSolidBytes = cs << 6;
|
|
|
|
// here we get real chunkSize
|
|
cs = oneMethodInfo.Get_Xz_BlockSize();
|
|
if (dicSize > cs)
|
|
dicSize = cs;
|
|
|
|
const UInt64 kSolidBytes_Lzma2_Max = ((UInt64)1 << 34);
|
|
if (numSolidBytes > kSolidBytes_Lzma2_Max)
|
|
numSolidBytes = kSolidBytes_Lzma2_Max;
|
|
|
|
methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder
|
|
|
|
#ifndef Z7_ST
|
|
if (!numThreads_WasSpecifiedInMethod
|
|
&& !methodMode.NumThreads_WasForced
|
|
&& methodMode.MemoryUsageLimit_WasSet
|
|
)
|
|
{
|
|
const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads();
|
|
const UInt32 numBlockThreads_Original = methodMode.NumThreads / lzmaThreads;
|
|
|
|
if (numBlockThreads_Original > 1)
|
|
{
|
|
/*
|
|
const UInt32 kNumThreads_Max = 1024;
|
|
if (numBlockThreads > kNumMaxThreads)
|
|
numBlockThreads = kNumMaxThreads;
|
|
*/
|
|
|
|
UInt32 numBlockThreads = numBlockThreads_Original;
|
|
const UInt64 lzmaMemUsage = oneMethodInfo.Get_Lzma_MemUsage(false); // solid
|
|
|
|
for (; numBlockThreads > 1; numBlockThreads--)
|
|
{
|
|
UInt64 size = numBlockThreads * (lzmaMemUsage + cs);
|
|
UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1;
|
|
if (cs < ((UInt32)1 << 26)) numPackChunks++;
|
|
if (cs < ((UInt32)1 << 24)) numPackChunks++;
|
|
if (cs < ((UInt32)1 << 22)) numPackChunks++;
|
|
size += numPackChunks * cs;
|
|
// printf("\nnumBlockThreads = %d, size = %d\n", (unsigned)(numBlockThreads), (unsigned)(size >> 20));
|
|
if (size <= methodMode.MemoryUsageLimit)
|
|
break;
|
|
}
|
|
|
|
if (numBlockThreads == 0)
|
|
numBlockThreads = 1;
|
|
if (numBlockThreads != numBlockThreads_Original)
|
|
{
|
|
const UInt32 numThreads_New = numBlockThreads * lzmaThreads;
|
|
CMultiMethodProps::SetMethodThreadsTo_Replace(methodFull, numThreads_New);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
numSolidBytes = (UInt64)dicSize << 7;
|
|
if (numSolidBytes > kSolidBytes_Max)
|
|
numSolidBytes = kSolidBytes_Max;
|
|
}
|
|
|
|
if (_numSolidBytesDefined)
|
|
continue;
|
|
|
|
if (numSolidBytes < kSolidBytes_Min)
|
|
numSolidBytes = kSolidBytes_Min;
|
|
_numSolidBytes = numSolidBytes;
|
|
_numSolidBytesDefined = true;
|
|
}
|
|
|
|
if (!_numSolidBytesDefined)
|
|
{
|
|
if (needSolid)
|
|
_numSolidBytes = kSolidBytes_Max;
|
|
else
|
|
_numSolidBytes = 0;
|
|
}
|
|
_numSolidBytesDefined = true;
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, unsigned index, PROPID propID, UInt64 &ft, bool &ftDefined)
|
|
{
|
|
// ft = 0;
|
|
// ftDefined = false;
|
|
NCOM::CPropVariant prop;
|
|
RINOK(updateCallback->GetProperty(index, propID, &prop))
|
|
if (prop.vt == VT_FILETIME)
|
|
{
|
|
ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32);
|
|
ftDefined = true;
|
|
}
|
|
else if (prop.vt != VT_EMPTY)
|
|
return E_INVALIDARG;
|
|
else
|
|
{
|
|
ft = 0;
|
|
ftDefined = false;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
|
|
#ifdef _WIN32
|
|
static const wchar_t kDirDelimiter1 = L'\\';
|
|
#endif
|
|
static const wchar_t kDirDelimiter2 = L'/';
|
|
|
|
static inline bool IsCharDirLimiter(wchar_t c)
|
|
{
|
|
return (
|
|
#ifdef _WIN32
|
|
c == kDirDelimiter1 ||
|
|
#endif
|
|
c == kDirDelimiter2);
|
|
}
|
|
|
|
static int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex)
|
|
{
|
|
CTreeFolder &tf = treeFolders[cur];
|
|
tf.SortIndex = curSortIndex++;
|
|
for (int i = 0; i < tf.SubFolders.Size(); i++)
|
|
curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex);
|
|
tf.SortIndexEnd = curSortIndex;
|
|
return curSortIndex;
|
|
}
|
|
|
|
static int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos)
|
|
{
|
|
const CIntVector &subFolders = treeFolders[cur].SubFolders;
|
|
int left = 0, right = subFolders.Size();
|
|
insertPos = -1;
|
|
for (;;)
|
|
{
|
|
if (left == right)
|
|
{
|
|
insertPos = left;
|
|
return -1;
|
|
}
|
|
int mid = (left + right) / 2;
|
|
int midFolder = subFolders[mid];
|
|
int compare = CompareFileNames(name, treeFolders[midFolder].Name);
|
|
if (compare == 0)
|
|
return midFolder;
|
|
if (compare < 0)
|
|
right = mid;
|
|
else
|
|
left = mid + 1;
|
|
}
|
|
}
|
|
|
|
static int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name)
|
|
{
|
|
int insertPos;
|
|
int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos);
|
|
if (folderIndex < 0)
|
|
{
|
|
folderIndex = treeFolders.Size();
|
|
CTreeFolder &newFolder = treeFolders.AddNew();
|
|
newFolder.Parent = cur;
|
|
newFolder.Name = name;
|
|
treeFolders[cur].SubFolders.Insert(insertPos, folderIndex);
|
|
}
|
|
// else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234;
|
|
return folderIndex;
|
|
}
|
|
*/
|
|
|
|
Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
|
IArchiveUpdateCallback *updateCallback))
|
|
{
|
|
COM_TRY_BEGIN
|
|
|
|
const CDbEx *db = NULL;
|
|
#ifdef Z7_7Z_VOL
|
|
if (_volumes.Size() > 1)
|
|
return E_FAIL;
|
|
const CVolume *volume = 0;
|
|
if (_volumes.Size() == 1)
|
|
{
|
|
volume = &_volumes.Front();
|
|
db = &volume->Database;
|
|
}
|
|
#else
|
|
if (_inStream)
|
|
db = &_db;
|
|
#endif
|
|
|
|
if (db && !db->CanUpdate())
|
|
return E_NOTIMPL;
|
|
|
|
/*
|
|
Z7_DECL_CMyComPtr_QI_FROM(
|
|
IArchiveGetRawProps,
|
|
getRawProps, updateCallback)
|
|
|
|
CUniqBlocks secureBlocks;
|
|
secureBlocks.AddUniq(NULL, 0);
|
|
|
|
CObjectVector<CTreeFolder> treeFolders;
|
|
{
|
|
CTreeFolder folder;
|
|
folder.Parent = -1;
|
|
treeFolders.Add(folder);
|
|
}
|
|
*/
|
|
|
|
CObjectVector<CUpdateItem> updateItems;
|
|
|
|
bool need_CTime = (TimeOptions.Write_CTime.Def && TimeOptions.Write_CTime.Val);
|
|
bool need_ATime = (TimeOptions.Write_ATime.Def && TimeOptions.Write_ATime.Val);
|
|
bool need_MTime = (TimeOptions.Write_MTime.Def ? TimeOptions.Write_MTime.Val : true);
|
|
bool need_Attrib = (Write_Attrib.Def ? Write_Attrib.Val : true);
|
|
|
|
if (db && !db->Files.IsEmpty())
|
|
{
|
|
if (!TimeOptions.Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
|
|
if (!TimeOptions.Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
|
|
if (!TimeOptions.Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
|
|
if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty();
|
|
}
|
|
|
|
// UString s;
|
|
UString name;
|
|
|
|
for (UInt32 i = 0; i < numItems; i++)
|
|
{
|
|
Int32 newData, newProps;
|
|
UInt32 indexInArchive;
|
|
if (!updateCallback)
|
|
return E_FAIL;
|
|
RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive))
|
|
CUpdateItem ui;
|
|
ui.NewProps = IntToBool(newProps);
|
|
ui.NewData = IntToBool(newData);
|
|
ui.IndexInArchive = (int)indexInArchive;
|
|
ui.IndexInClient = i;
|
|
ui.IsAnti = false;
|
|
ui.Size = 0;
|
|
|
|
name.Empty();
|
|
// bool isAltStream = false;
|
|
if (ui.IndexInArchive != -1)
|
|
{
|
|
if (!db || (unsigned)ui.IndexInArchive >= db->Files.Size())
|
|
return E_INVALIDARG;
|
|
const CFileItem &fi = db->Files[(unsigned)ui.IndexInArchive];
|
|
if (!ui.NewProps)
|
|
{
|
|
_db.GetPath((unsigned)ui.IndexInArchive, name);
|
|
}
|
|
ui.IsDir = fi.IsDir;
|
|
ui.Size = fi.Size;
|
|
// isAltStream = fi.IsAltStream;
|
|
ui.IsAnti = db->IsItemAnti((unsigned)ui.IndexInArchive);
|
|
|
|
if (!ui.NewProps)
|
|
{
|
|
ui.CTimeDefined = db->CTime.GetItem((unsigned)ui.IndexInArchive, ui.CTime);
|
|
ui.ATimeDefined = db->ATime.GetItem((unsigned)ui.IndexInArchive, ui.ATime);
|
|
ui.MTimeDefined = db->MTime.GetItem((unsigned)ui.IndexInArchive, ui.MTime);
|
|
}
|
|
}
|
|
|
|
if (ui.NewProps)
|
|
{
|
|
bool folderStatusIsDefined;
|
|
if (need_Attrib)
|
|
{
|
|
NCOM::CPropVariant prop;
|
|
RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop))
|
|
if (prop.vt == VT_EMPTY)
|
|
ui.AttribDefined = false;
|
|
else if (prop.vt != VT_UI4)
|
|
return E_INVALIDARG;
|
|
else
|
|
{
|
|
ui.Attrib = prop.ulVal;
|
|
ui.AttribDefined = true;
|
|
}
|
|
}
|
|
|
|
// we need MTime to sort files.
|
|
if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined))
|
|
if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined))
|
|
if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined))
|
|
|
|
/*
|
|
if (getRawProps)
|
|
{
|
|
const void *data;
|
|
UInt32 dataSize;
|
|
UInt32 propType;
|
|
|
|
getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType);
|
|
if (dataSize != 0 && propType != NPropDataType::kRaw)
|
|
return E_FAIL;
|
|
ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize);
|
|
}
|
|
*/
|
|
|
|
{
|
|
NCOM::CPropVariant prop;
|
|
RINOK(updateCallback->GetProperty(i, kpidPath, &prop))
|
|
if (prop.vt == VT_EMPTY)
|
|
{
|
|
}
|
|
else if (prop.vt != VT_BSTR)
|
|
return E_INVALIDARG;
|
|
else
|
|
{
|
|
name = prop.bstrVal;
|
|
NItemName::ReplaceSlashes_OsToUnix(name);
|
|
}
|
|
}
|
|
{
|
|
NCOM::CPropVariant prop;
|
|
RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop))
|
|
if (prop.vt == VT_EMPTY)
|
|
folderStatusIsDefined = false;
|
|
else if (prop.vt != VT_BOOL)
|
|
return E_INVALIDARG;
|
|
else
|
|
{
|
|
ui.IsDir = (prop.boolVal != VARIANT_FALSE);
|
|
folderStatusIsDefined = true;
|
|
}
|
|
}
|
|
|
|
{
|
|
NCOM::CPropVariant prop;
|
|
RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop))
|
|
if (prop.vt == VT_EMPTY)
|
|
ui.IsAnti = false;
|
|
else if (prop.vt != VT_BOOL)
|
|
return E_INVALIDARG;
|
|
else
|
|
ui.IsAnti = (prop.boolVal != VARIANT_FALSE);
|
|
}
|
|
|
|
/*
|
|
{
|
|
NCOM::CPropVariant prop;
|
|
RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop));
|
|
if (prop.vt == VT_EMPTY)
|
|
isAltStream = false;
|
|
else if (prop.vt != VT_BOOL)
|
|
return E_INVALIDARG;
|
|
else
|
|
isAltStream = (prop.boolVal != VARIANT_FALSE);
|
|
}
|
|
*/
|
|
|
|
if (ui.IsAnti)
|
|
{
|
|
ui.AttribDefined = false;
|
|
|
|
ui.CTimeDefined = false;
|
|
ui.ATimeDefined = false;
|
|
ui.MTimeDefined = false;
|
|
|
|
ui.Size = 0;
|
|
}
|
|
|
|
if (!folderStatusIsDefined && ui.AttribDefined)
|
|
ui.SetDirStatusFromAttrib();
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
if (_db.SecureIDs.IsEmpty())
|
|
ui.SecureIndex = secureBlocks.AddUniq(NULL, 0);
|
|
else
|
|
{
|
|
int id = _db.SecureIDs[ui.IndexInArchive];
|
|
size_t offs = _db.SecureOffsets[id];
|
|
size_t size = _db.SecureOffsets[id + 1] - offs;
|
|
ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size);
|
|
}
|
|
*/
|
|
}
|
|
|
|
/*
|
|
{
|
|
int folderIndex = 0;
|
|
if (_useParents)
|
|
{
|
|
int j;
|
|
s.Empty();
|
|
for (j = 0; j < name.Len(); j++)
|
|
{
|
|
wchar_t c = name[j];
|
|
if (IsCharDirLimiter(c))
|
|
{
|
|
folderIndex = AddFolder(treeFolders, folderIndex, s);
|
|
s.Empty();
|
|
continue;
|
|
}
|
|
s += c;
|
|
}
|
|
if (isAltStream)
|
|
{
|
|
int colonPos = s.Find(':');
|
|
if (colonPos < 0)
|
|
{
|
|
// isAltStream = false;
|
|
return E_INVALIDARG;
|
|
}
|
|
UString mainName = s.Left(colonPos);
|
|
int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName);
|
|
if (treeFolders[newFolderIndex].UpdateItemIndex < 0)
|
|
{
|
|
for (int j = updateItems.Size() - 1; j >= 0; j--)
|
|
{
|
|
CUpdateItem &ui2 = updateItems[j];
|
|
if (ui2.ParentFolderIndex == folderIndex
|
|
&& ui2.Name == mainName)
|
|
{
|
|
ui2.TreeFolderIndex = newFolderIndex;
|
|
treeFolders[newFolderIndex].UpdateItemIndex = j;
|
|
}
|
|
}
|
|
}
|
|
folderIndex = newFolderIndex;
|
|
s.Delete(0, colonPos + 1);
|
|
}
|
|
ui.Name = s;
|
|
}
|
|
else
|
|
ui.Name = name;
|
|
ui.IsAltStream = isAltStream;
|
|
ui.ParentFolderIndex = folderIndex;
|
|
ui.TreeFolderIndex = -1;
|
|
if (ui.IsDir && !s.IsEmpty())
|
|
{
|
|
ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s);
|
|
treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size();
|
|
}
|
|
}
|
|
*/
|
|
ui.Name = name;
|
|
|
|
if (ui.NewData)
|
|
{
|
|
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);
|
|
}
|
|
|
|
/*
|
|
FillSortIndex(treeFolders, 0, 0);
|
|
for (i = 0; i < (UInt32)updateItems.Size(); i++)
|
|
{
|
|
CUpdateItem &ui = updateItems[i];
|
|
ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex;
|
|
ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd;
|
|
}
|
|
*/
|
|
|
|
CCompressionMethodMode methodMode, headerMethod;
|
|
|
|
methodMode.MemoryUsageLimit = _memUsage_Compress;
|
|
methodMode.MemoryUsageLimit_WasSet = _memUsage_WasSet;
|
|
|
|
#ifndef Z7_ST
|
|
{
|
|
UInt32 numThreads = _numThreads;
|
|
const UInt32 kNumThreads_Max = 1024;
|
|
if (numThreads > kNumThreads_Max)
|
|
numThreads = kNumThreads_Max;
|
|
methodMode.NumThreads = numThreads;
|
|
methodMode.NumThreads_WasForced = _numThreads_WasForced;
|
|
methodMode.MultiThreadMixer = _useMultiThreadMixer;
|
|
// headerMethod.NumThreads = 1;
|
|
headerMethod.MultiThreadMixer = _useMultiThreadMixer;
|
|
}
|
|
#endif
|
|
|
|
const HRESULT res = SetMainMethod(methodMode);
|
|
RINOK(res)
|
|
|
|
RINOK(SetHeaderMethod(headerMethod))
|
|
|
|
Z7_DECL_CMyComPtr_QI_FROM(
|
|
ICryptoGetTextPassword2,
|
|
getPassword2, updateCallback)
|
|
|
|
methodMode.PasswordIsDefined = false;
|
|
methodMode.Password.Wipe_and_Empty();
|
|
if (getPassword2)
|
|
{
|
|
CMyComBSTR_Wipe password;
|
|
Int32 passwordIsDefined;
|
|
RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password))
|
|
methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
|
|
if (methodMode.PasswordIsDefined && password)
|
|
methodMode.Password = password;
|
|
}
|
|
|
|
bool compressMainHeader = _compressHeaders; // check it
|
|
|
|
bool encryptHeaders = false;
|
|
|
|
#ifndef Z7_NO_CRYPTO
|
|
if (!methodMode.PasswordIsDefined && _passwordIsDefined)
|
|
{
|
|
// if header is compressed, we use that password for updated archive
|
|
methodMode.PasswordIsDefined = true;
|
|
methodMode.Password = _password;
|
|
}
|
|
#endif
|
|
|
|
if (methodMode.PasswordIsDefined)
|
|
{
|
|
if (_encryptHeadersSpecified)
|
|
encryptHeaders = _encryptHeaders;
|
|
#ifndef Z7_NO_CRYPTO
|
|
else
|
|
encryptHeaders = _passwordIsDefined;
|
|
#endif
|
|
compressMainHeader = true;
|
|
if (encryptHeaders)
|
|
{
|
|
headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined;
|
|
headerMethod.Password = methodMode.Password;
|
|
}
|
|
}
|
|
|
|
if (numItems < 2)
|
|
compressMainHeader = false;
|
|
|
|
const int level = GetLevel();
|
|
|
|
CUpdateOptions options;
|
|
options.Need_CTime = need_CTime;
|
|
options.Need_ATime = need_ATime;
|
|
options.Need_MTime = need_MTime;
|
|
options.Need_Attrib = need_Attrib;
|
|
// options.Need_Crc = (_crcSize != 0); // for debug
|
|
|
|
options.Method = &methodMode;
|
|
options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL;
|
|
options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted);
|
|
options.MaxFilter = (level >= 8);
|
|
options.AnalysisLevel = GetAnalysisLevel();
|
|
|
|
options.HeaderOptions.CompressMainHeader = compressMainHeader;
|
|
/*
|
|
options.HeaderOptions.WriteCTime = Write_CTime;
|
|
options.HeaderOptions.WriteATime = Write_ATime;
|
|
options.HeaderOptions.WriteMTime = Write_MTime;
|
|
options.HeaderOptions.WriteAttrib = Write_Attrib;
|
|
*/
|
|
|
|
options.NumSolidFiles = _numSolidFiles;
|
|
options.NumSolidBytes = _numSolidBytes;
|
|
options.SolidExtension = _solidExtension;
|
|
options.UseTypeSorting = _useTypeSorting;
|
|
|
|
options.RemoveSfxBlock = _removeSfxBlock;
|
|
// options.VolumeMode = _volumeMode;
|
|
|
|
options.MultiThreadMixer = _useMultiThreadMixer;
|
|
|
|
/*
|
|
if (secureBlocks.Sorted.Size() > 1)
|
|
{
|
|
secureBlocks.GetReverseMap();
|
|
for (int i = 0; i < updateItems.Size(); i++)
|
|
{
|
|
int &secureIndex = updateItems[i].SecureIndex;
|
|
secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex];
|
|
}
|
|
}
|
|
*/
|
|
|
|
return Update(
|
|
EXTERNAL_CODECS_VARS
|
|
#ifdef Z7_7Z_VOL
|
|
volume ? volume->Stream: 0,
|
|
volume ? db : 0,
|
|
#else
|
|
_inStream,
|
|
db,
|
|
#endif
|
|
updateItems,
|
|
// treeFolders,
|
|
// secureBlocks,
|
|
outStream, updateCallback, options);
|
|
|
|
COM_TRY_END
|
|
}
|
|
|
|
static HRESULT ParseBond(UString &srcString, UInt32 &coder, UInt32 &stream)
|
|
{
|
|
stream = 0;
|
|
{
|
|
const unsigned index = ParseStringToUInt32(srcString, coder);
|
|
if (index == 0)
|
|
return E_INVALIDARG;
|
|
srcString.DeleteFrontal(index);
|
|
}
|
|
if (srcString[0] == 's')
|
|
{
|
|
srcString.Delete(0);
|
|
const unsigned index = ParseStringToUInt32(srcString, stream);
|
|
if (index == 0)
|
|
return E_INVALIDARG;
|
|
srcString.DeleteFrontal(index);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
void COutHandler::InitProps7z()
|
|
{
|
|
_removeSfxBlock = false;
|
|
_compressHeaders = true;
|
|
_encryptHeadersSpecified = false;
|
|
_encryptHeaders = false;
|
|
// _useParents = false;
|
|
|
|
TimeOptions.Init();
|
|
Write_Attrib.Init();
|
|
|
|
_useMultiThreadMixer = true;
|
|
|
|
// _volumeMode = false;
|
|
|
|
InitSolid();
|
|
_useTypeSorting = false;
|
|
}
|
|
|
|
void COutHandler::InitProps()
|
|
{
|
|
CMultiMethodProps::Init();
|
|
InitProps7z();
|
|
}
|
|
|
|
|
|
|
|
HRESULT COutHandler::SetSolidFromString(const UString &s)
|
|
{
|
|
UString s2 = s;
|
|
s2.MakeLower_Ascii();
|
|
for (unsigned i = 0; i < s2.Len();)
|
|
{
|
|
const wchar_t *start = ((const wchar_t *)s2) + i;
|
|
const wchar_t *end;
|
|
UInt64 v = ConvertStringToUInt64(start, &end);
|
|
if (start == end)
|
|
{
|
|
if (s2[i++] != 'e')
|
|
return E_INVALIDARG;
|
|
_solidExtension = true;
|
|
continue;
|
|
}
|
|
i += (unsigned)(end - start);
|
|
if (i == s2.Len())
|
|
return E_INVALIDARG;
|
|
const wchar_t c = s2[i++];
|
|
if (c == 'f')
|
|
{
|
|
if (v < 1)
|
|
v = 1;
|
|
_numSolidFiles = v;
|
|
}
|
|
else
|
|
{
|
|
unsigned numBits;
|
|
switch (c)
|
|
{
|
|
case 'b': numBits = 0; break;
|
|
case 'k': numBits = 10; break;
|
|
case 'm': numBits = 20; break;
|
|
case 'g': numBits = 30; break;
|
|
case 't': numBits = 40; break;
|
|
default: return E_INVALIDARG;
|
|
}
|
|
_numSolidBytes = (v << numBits);
|
|
_numSolidBytesDefined = true;
|
|
/*
|
|
if (_numSolidBytes == 0)
|
|
_numSolidFiles = 1;
|
|
*/
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value)
|
|
{
|
|
bool isSolid;
|
|
switch (value.vt)
|
|
{
|
|
case VT_EMPTY: isSolid = true; break;
|
|
case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
|
|
case VT_BSTR:
|
|
if (StringToBool(value.bstrVal, isSolid))
|
|
break;
|
|
return SetSolidFromString(value.bstrVal);
|
|
default: return E_INVALIDARG;
|
|
}
|
|
if (isSolid)
|
|
InitSolid();
|
|
else
|
|
_numSolidFiles = 1;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest)
|
|
{
|
|
RINOK(PROPVARIANT_to_bool(prop, dest.Val))
|
|
dest.Def = true;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
|
|
{
|
|
UString name = nameSpec;
|
|
name.MakeLower_Ascii();
|
|
if (name.IsEmpty())
|
|
return E_INVALIDARG;
|
|
|
|
if (name[0] == L's')
|
|
{
|
|
name.Delete(0);
|
|
if (name.IsEmpty())
|
|
return SetSolidFromPROPVARIANT(value);
|
|
if (value.vt != VT_EMPTY)
|
|
return E_INVALIDARG;
|
|
return SetSolidFromString(name);
|
|
}
|
|
|
|
UInt32 number;
|
|
const unsigned index = ParseStringToUInt32(name, number);
|
|
// UString realName = name.Ptr(index);
|
|
if (index == 0)
|
|
{
|
|
if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock);
|
|
if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders);
|
|
// if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents);
|
|
|
|
if (name.IsEqualTo("hcf"))
|
|
{
|
|
bool compressHeadersFull = true;
|
|
RINOK(PROPVARIANT_to_bool(value, compressHeadersFull))
|
|
return compressHeadersFull ? S_OK: E_INVALIDARG;
|
|
}
|
|
|
|
if (name.IsEqualTo("he"))
|
|
{
|
|
RINOK(PROPVARIANT_to_bool(value, _encryptHeaders))
|
|
_encryptHeadersSpecified = true;
|
|
return S_OK;
|
|
}
|
|
|
|
{
|
|
bool processed;
|
|
RINOK(TimeOptions.Parse(name, value, processed))
|
|
if (processed)
|
|
{
|
|
if ( TimeOptions.Prec != (UInt32)(Int32)-1
|
|
&& TimeOptions.Prec != k_PropVar_TimePrec_0
|
|
&& TimeOptions.Prec != k_PropVar_TimePrec_HighPrec
|
|
&& TimeOptions.Prec != k_PropVar_TimePrec_100ns)
|
|
return E_INVALIDARG;
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib);
|
|
|
|
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);
|
|
}
|
|
|
|
Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
|
|
{
|
|
COM_TRY_BEGIN
|
|
_bonds.Clear();
|
|
InitProps();
|
|
|
|
for (UInt32 i = 0; i < numProps; i++)
|
|
{
|
|
UString name = names[i];
|
|
name.MakeLower_Ascii();
|
|
if (name.IsEmpty())
|
|
return E_INVALIDARG;
|
|
|
|
const PROPVARIANT &value = values[i];
|
|
|
|
if (name.Find(L':') >= 0) // 'b' was used as NCoderPropID::kBlockSize2 before v23
|
|
if (name[0] == 'b')
|
|
{
|
|
if (value.vt != VT_EMPTY)
|
|
return E_INVALIDARG;
|
|
name.Delete(0);
|
|
|
|
CBond2 bond;
|
|
RINOK(ParseBond(name, bond.OutCoder, bond.OutStream))
|
|
if (name[0] != ':')
|
|
return E_INVALIDARG;
|
|
name.Delete(0);
|
|
UInt32 inStream = 0;
|
|
RINOK(ParseBond(name, bond.InCoder, inStream))
|
|
if (inStream != 0)
|
|
return E_INVALIDARG;
|
|
if (!name.IsEmpty())
|
|
return E_INVALIDARG;
|
|
_bonds.Add(bond);
|
|
continue;
|
|
}
|
|
|
|
RINOK(SetProperty(name, value))
|
|
}
|
|
|
|
unsigned numEmptyMethods = GetNumEmptyMethods();
|
|
if (numEmptyMethods > 0)
|
|
{
|
|
unsigned k;
|
|
for (k = 0; k < _bonds.Size(); k++)
|
|
{
|
|
const CBond2 &bond = _bonds[k];
|
|
if (bond.InCoder < (UInt32)numEmptyMethods ||
|
|
bond.OutCoder < (UInt32)numEmptyMethods)
|
|
return E_INVALIDARG;
|
|
}
|
|
for (k = 0; k < _bonds.Size(); k++)
|
|
{
|
|
CBond2 &bond = _bonds[k];
|
|
bond.InCoder -= (UInt32)numEmptyMethods;
|
|
bond.OutCoder -= (UInt32)numEmptyMethods;
|
|
}
|
|
_methods.DeleteFrontal(numEmptyMethods);
|
|
}
|
|
|
|
FOR_VECTOR (k, _bonds)
|
|
{
|
|
const CBond2 &bond = _bonds[k];
|
|
if (bond.InCoder >= (UInt32)_methods.Size() ||
|
|
bond.OutCoder >= (UInt32)_methods.Size())
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
}}
|
|
|
|
#endif
|