mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-07 01:15:00 -06:00
17.00
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "../../Compress/LzmaEncoder.h"
|
||||
#include "../../Compress/PpmdZip.h"
|
||||
#include "../../Compress/XzEncoder.h"
|
||||
|
||||
#include "../Common/InStreamWithCRC.h"
|
||||
|
||||
@@ -26,8 +27,8 @@
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
static const CMethodId kMethodId_ZipBase = 0x040100;
|
||||
static const CMethodId kMethodId_BZip2 = 0x040202;
|
||||
using namespace NFileHeader;
|
||||
|
||||
|
||||
static const UInt32 kLzmaPropsSize = 5;
|
||||
static const UInt32 kLzmaHeaderSize = 4 + kLzmaPropsSize;
|
||||
@@ -37,10 +38,11 @@ class CLzmaEncoder:
|
||||
public ICompressSetCoderProperties,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
NCompress::NLzma::CEncoder *EncoderSpec;
|
||||
CMyComPtr<ICompressCoder> Encoder;
|
||||
Byte Header[kLzmaHeaderSize];
|
||||
public:
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
@@ -81,7 +83,8 @@ CAddCommon::CAddCommon(const CCompressionMethodMode &options):
|
||||
_options(options),
|
||||
_copyCoderSpec(NULL),
|
||||
_cryptoStreamSpec(NULL),
|
||||
_buf(NULL)
|
||||
_buf(NULL),
|
||||
_isLzmaEos(false)
|
||||
{}
|
||||
|
||||
CAddCommon::~CAddCommon()
|
||||
@@ -114,49 +117,100 @@ HRESULT CAddCommon::CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultC
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT CAddCommon::Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, CCompressingResult &opRes) const
|
||||
{
|
||||
// We use Zip64, if unPackSize size is larger than 0xF8000000 to support
|
||||
// cases when compressed size can be about 3% larger than uncompressed size
|
||||
|
||||
const UInt32 kUnpackZip64Limit = 0xF8000000;
|
||||
|
||||
opRes.UnpackSize = unpackSize;
|
||||
opRes.PackSize = (UInt64)1 << 60; // we use big value to force Zip64 mode.
|
||||
|
||||
if (unpackSize < kUnpackZip64Limit)
|
||||
opRes.PackSize = (UInt32)0xFFFFFFFF - 1; // it will not use Zip64 for that size
|
||||
|
||||
if (opRes.PackSize < unpackSize)
|
||||
opRes.PackSize = unpackSize;
|
||||
|
||||
Byte method = _options.MethodSequence[0];
|
||||
|
||||
if (method == NCompressionMethod::kStore && !_options.PasswordIsDefined)
|
||||
opRes.PackSize = unpackSize;
|
||||
|
||||
opRes.CRC = 0;
|
||||
|
||||
opRes.LzmaEos = false;
|
||||
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
|
||||
opRes.FileTimeWasUsed = false;
|
||||
|
||||
if (_options.PasswordIsDefined)
|
||||
{
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_ZipCrypto;
|
||||
if (_options.IsAesMode)
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes;
|
||||
else
|
||||
{
|
||||
if (seqMode)
|
||||
opRes.FileTimeWasUsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
opRes.Method = method;
|
||||
Byte ver = 0;
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case NCompressionMethod::kStore: break;
|
||||
case NCompressionMethod::kDeflate: ver = NCompressionMethod::kExtractVersion_Deflate; break;
|
||||
case NCompressionMethod::kDeflate64: ver = NCompressionMethod::kExtractVersion_Deflate64; break;
|
||||
case NCompressionMethod::kXz : ver = NCompressionMethod::kExtractVersion_Xz; break;
|
||||
case NCompressionMethod::kPPMd : ver = NCompressionMethod::kExtractVersion_PPMd; break;
|
||||
case NCompressionMethod::kBZip2: ver = NCompressionMethod::kExtractVersion_BZip2; break;
|
||||
case NCompressionMethod::kLZMA :
|
||||
{
|
||||
ver = NCompressionMethod::kExtractVersion_LZMA;
|
||||
const COneMethodInfo *oneMethodMain = &_options._methods[0];
|
||||
opRes.LzmaEos = oneMethodMain->Get_Lzma_Eos();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (opRes.ExtractVersion < ver)
|
||||
opRes.ExtractVersion = ver;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CAddCommon::Compress(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
ISequentialInStream *inStream, IOutStream *outStream,
|
||||
UInt32 /* fileTime */,
|
||||
bool seqMode, UInt32 fileTime,
|
||||
ICompressProgressInfo *progress, CCompressingResult &opRes)
|
||||
{
|
||||
opRes.LzmaEos = false;
|
||||
|
||||
if (!inStream)
|
||||
{
|
||||
// We can create empty stream here. But it was already implemented in caller code in 9.33+
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
// CSequentialInStreamWithCRC *inSecCrcStreamSpec = NULL;
|
||||
CInStreamWithCRC *inCrcStreamSpec = NULL;
|
||||
CMyComPtr<ISequentialInStream> inCrcStream;
|
||||
{
|
||||
CMyComPtr<IInStream> inStream2;
|
||||
|
||||
CSequentialInStreamWithCRC *inSecCrcStreamSpec = new CSequentialInStreamWithCRC;
|
||||
CMyComPtr<ISequentialInStream> inCrcStream = inSecCrcStreamSpec;
|
||||
|
||||
CMyComPtr<IInStream> inStream2;
|
||||
if (!seqMode)
|
||||
inStream->QueryInterface(IID_IInStream, (void **)&inStream2);
|
||||
|
||||
if (inStream2)
|
||||
{
|
||||
inCrcStreamSpec = new CInStreamWithCRC;
|
||||
inCrcStream = inCrcStreamSpec;
|
||||
inCrcStreamSpec->SetStream(inStream2);
|
||||
inCrcStreamSpec->Init();
|
||||
}
|
||||
else
|
||||
{
|
||||
// we don't support stdin, since stream from stdin can require 64-bit size header
|
||||
return E_NOTIMPL;
|
||||
/*
|
||||
inSecCrcStreamSpec = new CSequentialInStreamWithCRC;
|
||||
inCrcStream = inSecCrcStreamSpec;
|
||||
inSecCrcStreamSpec->SetStream(inStream);
|
||||
inSecCrcStreamSpec->Init();
|
||||
*/
|
||||
}
|
||||
}
|
||||
inSecCrcStreamSpec->SetStream(inStream);
|
||||
inSecCrcStreamSpec->Init();
|
||||
|
||||
unsigned numTestMethods = _options.MethodSequence.Size();
|
||||
|
||||
if (numTestMethods > 1 && !inCrcStreamSpec)
|
||||
if (seqMode || (numTestMethods > 1 && !inStream2))
|
||||
numTestMethods = 1;
|
||||
|
||||
UInt32 crc = 0;
|
||||
@@ -164,20 +218,24 @@ HRESULT CAddCommon::Compress(
|
||||
|
||||
Byte method = 0;
|
||||
CFilterCoder::C_OutStream_Releaser outStreamReleaser;
|
||||
opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default;
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
|
||||
opRes.FileTimeWasUsed = false;
|
||||
|
||||
for (unsigned i = 0; i < numTestMethods; i++)
|
||||
{
|
||||
opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default;
|
||||
if (inCrcStreamSpec)
|
||||
RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
opRes.LzmaEos = false;
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
|
||||
if (inStream2 && i != 0)
|
||||
{
|
||||
inSecCrcStreamSpec->Init();
|
||||
RINOK(inStream2->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
RINOK(outStream->SetSize(0));
|
||||
RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
|
||||
if (_options.PasswordIsDefined)
|
||||
{
|
||||
opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_ZipCrypto;
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_ZipCrypto;
|
||||
|
||||
if (!_cryptoStream)
|
||||
{
|
||||
@@ -187,7 +245,7 @@ HRESULT CAddCommon::Compress(
|
||||
|
||||
if (_options.IsAesMode)
|
||||
{
|
||||
opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Aes;
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes;
|
||||
if (!_cryptoStreamSpec->Filter)
|
||||
{
|
||||
_cryptoStreamSpec->Filter = _filterAesSpec = new NCrypto::NWzAes::CEncoder;
|
||||
@@ -206,23 +264,22 @@ HRESULT CAddCommon::Compress(
|
||||
|
||||
UInt32 check;
|
||||
|
||||
// if (inCrcStreamSpec)
|
||||
if (inStream2)
|
||||
{
|
||||
if (!crc_IsCalculated)
|
||||
{
|
||||
RINOK(CalcStreamCRC(inStream, crc));
|
||||
crc_IsCalculated = true;
|
||||
RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
RINOK(inStream2->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
inSecCrcStreamSpec->Init();
|
||||
}
|
||||
check = (crc >> 16);
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
opRes.FileTimeWasUsed = true;
|
||||
check = (fileTime & 0xFFFF);
|
||||
}
|
||||
*/
|
||||
|
||||
RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check));
|
||||
}
|
||||
@@ -236,7 +293,7 @@ HRESULT CAddCommon::Compress(
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case NFileHeader::NCompressionMethod::kStored:
|
||||
case NCompressionMethod::kStore:
|
||||
{
|
||||
if (_copyCoderSpec == NULL)
|
||||
{
|
||||
@@ -256,15 +313,22 @@ HRESULT CAddCommon::Compress(
|
||||
{
|
||||
if (!_compressEncoder)
|
||||
{
|
||||
if (method == NFileHeader::NCompressionMethod::kLZMA)
|
||||
CLzmaEncoder *_lzmaEncoder = NULL;
|
||||
if (method == NCompressionMethod::kLZMA)
|
||||
{
|
||||
_compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_LZMA;
|
||||
CLzmaEncoder *_lzmaEncoder = new CLzmaEncoder();
|
||||
_compressExtractVersion = NCompressionMethod::kExtractVersion_LZMA;
|
||||
_lzmaEncoder = new CLzmaEncoder();
|
||||
_compressEncoder = _lzmaEncoder;
|
||||
}
|
||||
else if (method == NFileHeader::NCompressionMethod::kPPMd)
|
||||
else if (method == NCompressionMethod::kXz)
|
||||
{
|
||||
_compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_PPMd;
|
||||
_compressExtractVersion = NCompressionMethod::kExtractVersion_Xz;
|
||||
NCompress::NXz::CEncoder *encoder = new NCompress::NXz::CEncoder();
|
||||
_compressEncoder = encoder;
|
||||
}
|
||||
else if (method == NCompressionMethod::kPPMd)
|
||||
{
|
||||
_compressExtractVersion = NCompressionMethod::kExtractVersion_PPMd;
|
||||
NCompress::NPpmdZip::CEncoder *encoder = new NCompress::NPpmdZip::CEncoder();
|
||||
_compressEncoder = encoder;
|
||||
}
|
||||
@@ -273,14 +337,14 @@ HRESULT CAddCommon::Compress(
|
||||
CMethodId methodId;
|
||||
switch (method)
|
||||
{
|
||||
case NFileHeader::NCompressionMethod::kBZip2:
|
||||
case NCompressionMethod::kBZip2:
|
||||
methodId = kMethodId_BZip2;
|
||||
_compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_BZip2;
|
||||
_compressExtractVersion = NCompressionMethod::kExtractVersion_BZip2;
|
||||
break;
|
||||
default:
|
||||
_compressExtractVersion = ((method == NFileHeader::NCompressionMethod::kDeflated64) ?
|
||||
NFileHeader::NCompressionMethod::kExtractVersion_Deflate64 :
|
||||
NFileHeader::NCompressionMethod::kExtractVersion_Deflate);
|
||||
_compressExtractVersion = ((method == NCompressionMethod::kDeflate64) ?
|
||||
NCompressionMethod::kExtractVersion_Deflate64 :
|
||||
NCompressionMethod::kExtractVersion_Deflate);
|
||||
methodId = kMethodId_ZipBase + method;
|
||||
break;
|
||||
}
|
||||
@@ -290,11 +354,11 @@ HRESULT CAddCommon::Compress(
|
||||
if (!_compressEncoder)
|
||||
return E_NOTIMPL;
|
||||
|
||||
if (method == NFileHeader::NCompressionMethod::kDeflated ||
|
||||
method == NFileHeader::NCompressionMethod::kDeflated64)
|
||||
if (method == NCompressionMethod::kDeflate ||
|
||||
method == NCompressionMethod::kDeflate64)
|
||||
{
|
||||
}
|
||||
else if (method == NFileHeader::NCompressionMethod::kBZip2)
|
||||
else if (method == NCompressionMethod::kBZip2)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -303,11 +367,22 @@ HRESULT CAddCommon::Compress(
|
||||
_compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProps);
|
||||
if (setCoderProps)
|
||||
{
|
||||
RINOK(_options.MethodInfo.SetCoderProps(setCoderProps,
|
||||
_options._dataSizeReduceDefined ? &_options._dataSizeReduce : NULL));
|
||||
if (!_options._methods.IsEmpty())
|
||||
{
|
||||
COneMethodInfo *oneMethodMain = &_options._methods[0];
|
||||
|
||||
RINOK(oneMethodMain->SetCoderProps(setCoderProps,
|
||||
_options._dataSizeReduceDefined ? &_options._dataSizeReduce : NULL));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (method == NCompressionMethod::kLZMA)
|
||||
_isLzmaEos = _lzmaEncoder->EncoderSpec->IsWriteEndMark();
|
||||
}
|
||||
|
||||
if (method == NCompressionMethod::kLZMA)
|
||||
opRes.LzmaEos = _isLzmaEos;
|
||||
|
||||
CMyComPtr<ISequentialOutStream> outStreamNew;
|
||||
if (_options.PasswordIsDefined)
|
||||
outStreamNew = _cryptoStream;
|
||||
@@ -332,18 +407,10 @@ HRESULT CAddCommon::Compress(
|
||||
|
||||
RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize));
|
||||
|
||||
// if (inCrcStreamSpec)
|
||||
{
|
||||
opRes.CRC = inCrcStreamSpec->GetCRC();
|
||||
opRes.UnpackSize = inCrcStreamSpec->GetSize();
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
opRes.CRC = inSecCrcStreamSpec->GetCRC();
|
||||
opRes.UnpackSize = inSecCrcStreamSpec->GetSize();
|
||||
}
|
||||
*/
|
||||
|
||||
if (_options.PasswordIsDefined)
|
||||
{
|
||||
|
||||
@@ -27,6 +27,7 @@ struct CCompressingResult
|
||||
UInt16 Method;
|
||||
Byte ExtractVersion;
|
||||
bool FileTimeWasUsed;
|
||||
bool LzmaEos;
|
||||
};
|
||||
|
||||
class CAddCommon
|
||||
@@ -37,6 +38,7 @@ class CAddCommon
|
||||
|
||||
CMyComPtr<ICompressCoder> _compressEncoder;
|
||||
Byte _compressExtractVersion;
|
||||
bool _isLzmaEos;
|
||||
|
||||
CFilterCoder *_cryptoStreamSpec;
|
||||
CMyComPtr<ISequentialOutStream> _cryptoStream;
|
||||
@@ -50,11 +52,14 @@ class CAddCommon
|
||||
public:
|
||||
CAddCommon(const CCompressionMethodMode &options);
|
||||
~CAddCommon();
|
||||
|
||||
HRESULT Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, CCompressingResult &opRes) const;
|
||||
|
||||
HRESULT Compress(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
ISequentialInStream *inStream, IOutStream *outStream,
|
||||
UInt32 fileTime,
|
||||
ICompressProgressInfo *progress, CCompressingResult &operationResult);
|
||||
bool seqMode, UInt32 fileTime,
|
||||
ICompressProgressInfo *progress, CCompressingResult &opRes);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -14,26 +14,18 @@
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
struct CBaseProps
|
||||
{
|
||||
CMethodProps MethodInfo;
|
||||
Int32 Level;
|
||||
const CMethodId kMethodId_ZipBase = 0x040100;
|
||||
const CMethodId kMethodId_BZip2 = 0x040202;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
UInt32 NumThreads;
|
||||
bool NumThreadsWasChanged;
|
||||
#endif
|
||||
struct CBaseProps: public CMultiMethodProps
|
||||
{
|
||||
bool IsAesMode;
|
||||
Byte AesKeyMode;
|
||||
|
||||
void Init()
|
||||
{
|
||||
MethodInfo.Clear();
|
||||
Level = -1;
|
||||
#ifndef _7ZIP_ST
|
||||
NumThreads = NWindows::NSystem::GetNumberOfProcessors();;
|
||||
NumThreadsWasChanged = false;
|
||||
#endif
|
||||
CMultiMethodProps::Init();
|
||||
|
||||
IsAesMode = false;
|
||||
AesKeyMode = 3;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../Common/ComTry.h"
|
||||
#include "../../../Common/IntToString.h"
|
||||
#include "../../../Common/StringConvert.h"
|
||||
|
||||
#include "../../../Windows/PropVariant.h"
|
||||
#include "../../../Windows/PropVariantUtils.h"
|
||||
#include "../../../Windows/TimeUtils.h"
|
||||
|
||||
#include "../../IPassword.h"
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "../../Compress/ImplodeDecoder.h"
|
||||
#include "../../Compress/PpmdZip.h"
|
||||
#include "../../Compress/ShrinkDecoder.h"
|
||||
#include "../../Compress/XzDecoder.h"
|
||||
|
||||
#include "../../Crypto/WzAes.h"
|
||||
#include "../../Crypto/ZipCrypto.h"
|
||||
@@ -30,7 +31,6 @@
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
#include "../Common/OutStreamWithCRC.h"
|
||||
|
||||
#include "../XzHandler.h"
|
||||
|
||||
#include "ZipHandler.h"
|
||||
|
||||
@@ -39,9 +39,6 @@ using namespace NWindows;
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
static const CMethodId kMethodId_ZipBase = 0x040100;
|
||||
static const CMethodId kMethodId_BZip2 = 0x040202;
|
||||
|
||||
static const char * const kHostOS[] =
|
||||
{
|
||||
"FAT"
|
||||
@@ -66,24 +63,57 @@ static const char * const kHostOS[] =
|
||||
, "OS/X"
|
||||
};
|
||||
|
||||
static const char * const kMethods[] =
|
||||
|
||||
const char * const kMethodNames1[kNumMethodNames1] =
|
||||
{
|
||||
"Store"
|
||||
, "Shrink"
|
||||
, "Reduced1"
|
||||
, "Reduced2"
|
||||
, "Reduced3"
|
||||
, "Reduced4"
|
||||
, "Reduce1"
|
||||
, "Reduce2"
|
||||
, "Reduce3"
|
||||
, "Reduce4"
|
||||
, "Implode"
|
||||
, "Tokenizing"
|
||||
, NULL // "Tokenize"
|
||||
, "Deflate"
|
||||
, "Deflate64"
|
||||
, "PKImploding"
|
||||
, NULL
|
||||
, "BZip2"
|
||||
, NULL
|
||||
, "LZMA"
|
||||
};
|
||||
|
||||
static const char *kMethod_AES = "AES";
|
||||
static const char *kMethod_ZipCrypto = "ZipCrypto";
|
||||
static const char *kMethod_StrongCrypto = "StrongCrypto";
|
||||
|
||||
const char * const kMethodNames2[kNumMethodNames2] =
|
||||
{
|
||||
"xz"
|
||||
, "Jpeg"
|
||||
, "WavPack"
|
||||
, "PPMd"
|
||||
, "WzAES"
|
||||
};
|
||||
|
||||
#define kMethod_AES "AES"
|
||||
#define kMethod_ZipCrypto "ZipCrypto"
|
||||
#define kMethod_StrongCrypto "StrongCrypto"
|
||||
|
||||
static const char * const kDeflateLevels[4] =
|
||||
{
|
||||
"Normal"
|
||||
, "Maximum"
|
||||
, "Fast"
|
||||
, "Fastest"
|
||||
};
|
||||
|
||||
|
||||
static const CUInt32PCharPair g_HeaderCharacts[] =
|
||||
{
|
||||
{ 0, "Encrypt" },
|
||||
{ 3, "Descriptor" },
|
||||
// { 5, "Patched" },
|
||||
{ 6, kMethod_StrongCrypto },
|
||||
{ 11, "UTF8" }
|
||||
};
|
||||
|
||||
struct CIdToNamePair
|
||||
{
|
||||
@@ -91,15 +121,6 @@ struct CIdToNamePair
|
||||
const char *Name;
|
||||
};
|
||||
|
||||
static const CIdToNamePair k_MethodIdNamePairs[] =
|
||||
{
|
||||
{ NFileHeader::NCompressionMethod::kBZip2, "BZip2" },
|
||||
{ NFileHeader::NCompressionMethod::kLZMA, "LZMA" },
|
||||
{ NFileHeader::NCompressionMethod::kXz, "xz" },
|
||||
{ NFileHeader::NCompressionMethod::kJpeg, "Jpeg" },
|
||||
{ NFileHeader::NCompressionMethod::kWavPack, "WavPack" },
|
||||
{ NFileHeader::NCompressionMethod::kPPMd, "PPMd" }
|
||||
};
|
||||
|
||||
static const CIdToNamePair k_StrongCryptoPairs[] =
|
||||
{
|
||||
@@ -116,7 +137,7 @@ static const CIdToNamePair k_StrongCryptoPairs[] =
|
||||
{ NStrongCrypto_AlgId::kRC4, "RC4" }
|
||||
};
|
||||
|
||||
const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id)
|
||||
static const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id)
|
||||
{
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
{
|
||||
@@ -127,6 +148,7 @@ const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const Byte kProps[] =
|
||||
{
|
||||
kpidPath,
|
||||
@@ -142,9 +164,11 @@ static const Byte kProps[] =
|
||||
kpidComment,
|
||||
kpidCRC,
|
||||
kpidMethod,
|
||||
kpidCharacts,
|
||||
kpidHostOS,
|
||||
kpidUnpackVer,
|
||||
kpidVolumeIndex
|
||||
kpidVolumeIndex,
|
||||
kpidOffset
|
||||
};
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
@@ -152,6 +176,7 @@ static const Byte kArcProps[] =
|
||||
kpidEmbeddedStubSize,
|
||||
kpidBit64,
|
||||
kpidComment,
|
||||
kpidCharacts,
|
||||
kpidTotalPhySize,
|
||||
kpidIsVolume,
|
||||
kpidVolumeIndex,
|
||||
@@ -193,11 +218,34 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidTotalPhySize: if (m_Archive.IsMultiVol) prop = m_Archive.Vols.GetTotalSize(); break;
|
||||
case kpidTotalPhySize: if (m_Archive.IsMultiVol) prop = m_Archive.Vols.TotalBytesSize; break;
|
||||
case kpidVolumeIndex: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.StartVolIndex; break;
|
||||
case kpidIsVolume: if (m_Archive.IsMultiVol) prop = true; break;
|
||||
case kpidNumVolumes: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.Streams.Size(); break;
|
||||
|
||||
case kpidCharacts:
|
||||
{
|
||||
AString s;
|
||||
|
||||
if (m_Archive.LocalsWereRead)
|
||||
{
|
||||
s.Add_OptSpaced("Local");
|
||||
|
||||
if (m_Archive.LocalsCenterMerged)
|
||||
s.Add_OptSpaced("Central");
|
||||
}
|
||||
|
||||
if (m_Archive.IsZip64)
|
||||
s.Add_OptSpaced("Zip64");
|
||||
|
||||
if (m_Archive.ExtraMinorError)
|
||||
s.Add_OptSpaced("Minor_Extra_ERROR");
|
||||
|
||||
if (!s.IsEmpty())
|
||||
prop = s;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidWarningFlags:
|
||||
{
|
||||
UInt32 v = 0;
|
||||
@@ -208,12 +256,23 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidWarning:
|
||||
{
|
||||
AString s;
|
||||
if (m_Archive.Overflow32bit)
|
||||
s.Add_OptSpaced("32-bit overflow in headers");
|
||||
if (m_Archive.Cd_NumEntries_Overflow_16bit)
|
||||
s.Add_OptSpaced("16-bit overflow for number of files in headers");
|
||||
if (!s.IsEmpty())
|
||||
prop = s;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidError:
|
||||
{
|
||||
if (!m_Archive.Vols.MissingName.IsEmpty())
|
||||
{
|
||||
UString s;
|
||||
s.SetFromAscii("Missing volume : ");
|
||||
UString s("Missing volume : ");
|
||||
s += m_Archive.Vols.MissingName;
|
||||
prop = s;
|
||||
}
|
||||
@@ -273,13 +332,19 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
{
|
||||
UString res;
|
||||
item.GetUnicodeString(res, item.Name, false, _forceCodePage, _specifiedCodePage);
|
||||
NItemName::ConvertToOSName2(res);
|
||||
NItemName::ReplaceToOsSlashes_Remove_TailSlash(res);
|
||||
prop = res;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidIsDir: prop = item.IsDir(); break;
|
||||
case kpidSize: prop = item.Size; break;
|
||||
case kpidSize:
|
||||
{
|
||||
if (item.FromCentral || !item.FromLocal || !item.HasDescriptor() || item.DescriptorWasRead)
|
||||
prop = item.Size;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidPackSize: prop = item.PackSize; break;
|
||||
|
||||
case kpidTimeType:
|
||||
@@ -299,17 +364,36 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
|
||||
case kpidCTime:
|
||||
{
|
||||
FILETIME ft;
|
||||
if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, ft))
|
||||
prop = ft;
|
||||
FILETIME utc;
|
||||
bool defined = true;
|
||||
if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, utc))
|
||||
{
|
||||
UInt32 unixTime = 0;
|
||||
if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kCTime, unixTime))
|
||||
NTime::UnixTimeToFileTime(unixTime, utc);
|
||||
else
|
||||
defined = false;
|
||||
}
|
||||
if (defined)
|
||||
prop = utc;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidATime:
|
||||
{
|
||||
FILETIME ft;
|
||||
if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, ft))
|
||||
prop = ft;
|
||||
FILETIME utc;
|
||||
bool defined = true;
|
||||
if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, utc))
|
||||
{
|
||||
UInt32 unixTime = 0;
|
||||
if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kATime, unixTime))
|
||||
NTime::UnixTimeToFileTime(unixTime, utc);
|
||||
else
|
||||
defined = false;
|
||||
}
|
||||
if (defined)
|
||||
prop = utc;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -375,10 +459,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
CWzAesExtra aesField;
|
||||
if (extra.GetWzAes(aesField))
|
||||
{
|
||||
char s[16];
|
||||
s[0] = '-';
|
||||
ConvertUInt32ToString(((unsigned)aesField.Strength + 1) * 64 , s + 1);
|
||||
m += s;
|
||||
m += '-';
|
||||
m.Add_UInt32(((unsigned)aesField.Strength + 1) * 64);
|
||||
id = aesField.Method;
|
||||
}
|
||||
}
|
||||
@@ -394,10 +476,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
else
|
||||
{
|
||||
m += kMethod_StrongCrypto;
|
||||
char temp[16];
|
||||
temp[0] = ':';
|
||||
ConvertUInt32ToString(f.AlgId, temp + 1);
|
||||
m += temp;
|
||||
m += ':';
|
||||
m.Add_UInt32(f.AlgId);
|
||||
}
|
||||
if (f.CertificateIsUsed())
|
||||
m += "-Cert";
|
||||
@@ -411,41 +491,96 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
}
|
||||
|
||||
{
|
||||
char temp[16];
|
||||
const char *s = NULL;
|
||||
if (id < ARRAY_SIZE(kMethods))
|
||||
s = kMethods[id];
|
||||
if (id < kNumMethodNames1)
|
||||
s = kMethodNames1[id];
|
||||
else
|
||||
{
|
||||
s = FindNameForId(k_MethodIdNamePairs, ARRAY_SIZE(k_MethodIdNamePairs), id);
|
||||
if (!s)
|
||||
int id2 = (int)id - (int)kMethodNames2Start;
|
||||
if (id2 >= 0 && id2 < kNumMethodNames2)
|
||||
s = kMethodNames2[id2];
|
||||
}
|
||||
if (s)
|
||||
m += s;
|
||||
else
|
||||
m.Add_UInt32(id);
|
||||
}
|
||||
{
|
||||
unsigned level = item.GetDeflateLevel();
|
||||
if (level != 0)
|
||||
{
|
||||
if (id == NFileHeader::NCompressionMethod::kLZMA)
|
||||
{
|
||||
ConvertUInt32ToString(id, temp);
|
||||
s = temp;
|
||||
if (level & 1)
|
||||
m += ":eos";
|
||||
level &= ~1;
|
||||
}
|
||||
else if (id == NFileHeader::NCompressionMethod::kDeflate)
|
||||
{
|
||||
m += ':';
|
||||
m += kDeflateLevels[level];
|
||||
level = 0;
|
||||
}
|
||||
|
||||
if (level != 0)
|
||||
{
|
||||
m += ":v";
|
||||
m.Add_UInt32(level);
|
||||
}
|
||||
}
|
||||
m += s;
|
||||
if (id == NFileHeader::NCompressionMethod::kLZMA && item.IsLzmaEOS())
|
||||
m += ":EOS";
|
||||
}
|
||||
|
||||
prop = m;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidCharacts:
|
||||
{
|
||||
AString s;
|
||||
|
||||
if (item.FromLocal)
|
||||
{
|
||||
s.Add_OptSpaced("Local");
|
||||
|
||||
item.LocalExtra.PrintInfo(s);
|
||||
|
||||
if (item.FromCentral)
|
||||
{
|
||||
s.Add_OptSpaced(":");
|
||||
s.Add_OptSpaced("Central");
|
||||
}
|
||||
}
|
||||
|
||||
if (item.FromCentral)
|
||||
{
|
||||
item.CentralExtra.PrintInfo(s);
|
||||
}
|
||||
|
||||
UInt32 flags = item.Flags;
|
||||
flags &= ~(6); // we don't need compression related bits here.
|
||||
|
||||
if (flags != 0)
|
||||
{
|
||||
AString s2 = FlagsToString(g_HeaderCharacts, ARRAY_SIZE(g_HeaderCharacts), flags);
|
||||
if (!s2.IsEmpty())
|
||||
{
|
||||
s.Add_OptSpaced(":");
|
||||
s.Add_OptSpaced(s2);
|
||||
}
|
||||
}
|
||||
|
||||
if (!item.FromCentral && item.FromLocal && item.HasDescriptor() && !item.DescriptorWasRead)
|
||||
s.Add_OptSpaced("Descriptor_ERROR");
|
||||
|
||||
if (!s.IsEmpty())
|
||||
prop = s;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidHostOS:
|
||||
{
|
||||
Byte hostOS = item.GetHostOS();
|
||||
char temp[16];
|
||||
const char *s = NULL;
|
||||
if (hostOS < ARRAY_SIZE(kHostOS))
|
||||
s = kHostOS[hostOS];
|
||||
else
|
||||
{
|
||||
ConvertUInt32ToString(hostOS, temp);
|
||||
s = temp;
|
||||
}
|
||||
prop = s;
|
||||
const Byte hostOS = item.GetHostOS();
|
||||
TYPE_TO_PROP(kHostOS, hostOS, prop);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -456,6 +591,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
case kpidVolumeIndex:
|
||||
prop = item.Disk;
|
||||
break;
|
||||
|
||||
case kpidOffset:
|
||||
prop = item.LocalHeaderPos;
|
||||
break;
|
||||
}
|
||||
|
||||
prop.Detach(value);
|
||||
@@ -475,7 +614,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
if (res != S_OK)
|
||||
{
|
||||
m_Items.Clear();
|
||||
m_Archive.ClearRefs();
|
||||
m_Archive.ClearRefs(); // we don't want to clear error flags
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -493,16 +632,24 @@ STDMETHODIMP CHandler::Close()
|
||||
|
||||
class CLzmaDecoder:
|
||||
public ICompressCoder,
|
||||
public ICompressSetFinishMode,
|
||||
public ICompressGetInStreamProcessedSize,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
NCompress::NLzma::CDecoder *DecoderSpec;
|
||||
CMyComPtr<ICompressCoder> Decoder;
|
||||
public:
|
||||
CLzmaDecoder();
|
||||
|
||||
MY_UNKNOWN_IMP2(
|
||||
ICompressSetFinishMode,
|
||||
ICompressGetInStreamProcessedSize)
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetFinishMode)(UInt32 finishMode);
|
||||
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
CLzmaDecoder();
|
||||
};
|
||||
|
||||
CLzmaDecoder::CLzmaDecoder()
|
||||
@@ -511,43 +658,44 @@ CLzmaDecoder::CLzmaDecoder()
|
||||
Decoder = DecoderSpec;
|
||||
}
|
||||
|
||||
static const unsigned kZipLzmaPropsSize = 4 + LZMA_PROPS_SIZE;
|
||||
|
||||
HRESULT CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
Byte buf[9];
|
||||
RINOK(ReadStream_FALSE(inStream, buf, 9));
|
||||
if (buf[2] != 5 || buf[3] != 0)
|
||||
Byte buf[kZipLzmaPropsSize];
|
||||
RINOK(ReadStream_FALSE(inStream, buf, kZipLzmaPropsSize));
|
||||
if (buf[2] != LZMA_PROPS_SIZE || buf[3] != 0)
|
||||
return E_NOTIMPL;
|
||||
RINOK(DecoderSpec->SetDecoderProperties2(buf + 4, 5));
|
||||
return Decoder->Code(inStream, outStream, NULL, outSize, progress);
|
||||
RINOK(DecoderSpec->SetDecoderProperties2(buf + 4, LZMA_PROPS_SIZE));
|
||||
UInt64 inSize2 = 0;
|
||||
if (inSize)
|
||||
{
|
||||
inSize2 = *inSize;
|
||||
if (inSize2 < kZipLzmaPropsSize)
|
||||
return S_FALSE;
|
||||
inSize2 -= kZipLzmaPropsSize;
|
||||
}
|
||||
return Decoder->Code(inStream, outStream, inSize ? &inSize2 : NULL, outSize, progress);
|
||||
}
|
||||
|
||||
|
||||
class CXzDecoder:
|
||||
public ICompressCoder,
|
||||
public CMyUnknownImp
|
||||
STDMETHODIMP CLzmaDecoder::SetFinishMode(UInt32 finishMode)
|
||||
{
|
||||
NArchive::NXz::CDecoder _decoder;
|
||||
public:
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
};
|
||||
|
||||
HRESULT CXzDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
|
||||
{
|
||||
RINOK(_decoder.Decode(inStream, outStream, progress));
|
||||
Int32 opRes = _decoder.Get_Extract_OperationResult();
|
||||
if (opRes == NExtract::NOperationResult::kUnsupportedMethod)
|
||||
return E_NOTIMPL;
|
||||
if (opRes != NExtract::NOperationResult::kOK)
|
||||
return S_FALSE;
|
||||
DecoderSpec->FinishStream = (finishMode != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CLzmaDecoder::GetInStreamProcessedSize(UInt64 *value)
|
||||
{
|
||||
*value = DecoderSpec->GetInputProcessedSize() + kZipLzmaPropsSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct CMethodItem
|
||||
{
|
||||
@@ -572,12 +720,15 @@ class CZipDecoder
|
||||
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
|
||||
CObjectVector<CMethodItem> methodItems;
|
||||
|
||||
CLzmaDecoder *lzmaDecoderSpec;
|
||||
public:
|
||||
CZipDecoder():
|
||||
_zipCryptoDecoderSpec(0),
|
||||
_pkAesDecoderSpec(0),
|
||||
_wzAesDecoderSpec(0),
|
||||
filterStreamSpec(0) {}
|
||||
filterStreamSpec(0),
|
||||
lzmaDecoderSpec(0)
|
||||
{}
|
||||
|
||||
HRESULT Decode(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
@@ -592,19 +743,18 @@ public:
|
||||
};
|
||||
|
||||
|
||||
static HRESULT SkipStreamData(ISequentialInStream *stream, UInt64 size)
|
||||
static HRESULT SkipStreamData(ISequentialInStream *stream, bool &thereAreData)
|
||||
{
|
||||
thereAreData = false;
|
||||
const size_t kBufSize = 1 << 12;
|
||||
Byte buf[kBufSize];
|
||||
for (;;)
|
||||
{
|
||||
size_t size = kBufSize;
|
||||
RINOK(ReadStream(stream, buf, &size));
|
||||
if (size == 0)
|
||||
return S_OK;
|
||||
size_t curSize = kBufSize;
|
||||
if (curSize > size)
|
||||
curSize = (size_t)size;
|
||||
RINOK(ReadStream_FALSE(stream, buf, curSize));
|
||||
size -= curSize;
|
||||
thereAreData = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,12 +770,15 @@ HRESULT CZipDecoder::Decode(
|
||||
#endif
|
||||
Int32 &res)
|
||||
{
|
||||
res = NExtract::NOperationResult::kDataError;
|
||||
res = NExtract::NOperationResult::kHeadersError;
|
||||
|
||||
CFilterCoder::C_InStream_Releaser inStreamReleaser;
|
||||
CFilterCoder::C_Filter_Releaser filterReleaser;
|
||||
|
||||
bool needCRC = true;
|
||||
bool wzAesMode = false;
|
||||
bool pkAesMode = false;
|
||||
|
||||
unsigned id = item.Method;
|
||||
|
||||
if (item.IsEncrypted())
|
||||
@@ -633,27 +786,23 @@ HRESULT CZipDecoder::Decode(
|
||||
if (item.IsStrongEncrypted())
|
||||
{
|
||||
CStrongCryptoExtra f;
|
||||
if (item.CentralExtra.GetStrongCrypto(f))
|
||||
{
|
||||
pkAesMode = true;
|
||||
}
|
||||
if (!pkAesMode)
|
||||
if (!item.CentralExtra.GetStrongCrypto(f))
|
||||
{
|
||||
res = NExtract::NOperationResult::kUnsupportedMethod;
|
||||
return S_OK;
|
||||
}
|
||||
pkAesMode = true;
|
||||
}
|
||||
if (!pkAesMode && id == NFileHeader::NCompressionMethod::kWzAES)
|
||||
else if (id == NFileHeader::NCompressionMethod::kWzAES)
|
||||
{
|
||||
CWzAesExtra aesField;
|
||||
if (item.GetMainExtra().GetWzAes(aesField))
|
||||
{
|
||||
wzAesMode = true;
|
||||
needCRC = aesField.NeedCrc();
|
||||
}
|
||||
if (!item.GetMainExtra().GetWzAes(aesField))
|
||||
return S_OK;
|
||||
wzAesMode = true;
|
||||
needCRC = aesField.NeedCrc();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
|
||||
CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
@@ -681,6 +830,9 @@ HRESULT CZipDecoder::Decode(
|
||||
limitedStreamSpec->SetStream(packStream);
|
||||
limitedStreamSpec->Init(packSize);
|
||||
}
|
||||
|
||||
|
||||
res = NExtract::NOperationResult::kDataError;
|
||||
|
||||
CMyComPtr<ICompressFilter> cryptoFilter;
|
||||
|
||||
@@ -725,6 +877,8 @@ HRESULT CZipDecoder::Decode(
|
||||
|
||||
CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
|
||||
RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword));
|
||||
if (!cryptoSetPassword)
|
||||
return E_FAIL;
|
||||
|
||||
if (!getTextPassword)
|
||||
extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
|
||||
@@ -736,39 +890,35 @@ HRESULT CZipDecoder::Decode(
|
||||
AString charPassword;
|
||||
if (password)
|
||||
{
|
||||
UnicodeStringToMultiByte2(charPassword, (const wchar_t *)password, CP_ACP);
|
||||
/*
|
||||
if (wzAesMode || pkAesMode)
|
||||
{
|
||||
charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP);
|
||||
/*
|
||||
for (unsigned i = 0;; i++)
|
||||
{
|
||||
wchar_t c = password[i];
|
||||
if (c == 0)
|
||||
break;
|
||||
if (c >= 0x80)
|
||||
{
|
||||
res = NExtract::NOperationResult::kDataError;
|
||||
return S_OK;
|
||||
}
|
||||
charPassword += (char)c;
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
/* pkzip25 / WinZip / Windows probably use ANSI for some files
|
||||
We use OEM for compatibility with previous versions of 7-Zip? */
|
||||
charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
|
||||
// PASSWORD encoding for ZipCrypto:
|
||||
// pkzip25 / WinZip / Windows probably use ANSI
|
||||
// 7-Zip < 4.43 creates ZIP archives with OEM encoding in password
|
||||
// 7-Zip >= 4.43 creates ZIP archives only with ASCII characters in password
|
||||
// 7-Zip < 17.00 uses CP_OEMCP for password decoding
|
||||
// 7-Zip >= 17.00 uses CP_ACP for password decoding
|
||||
}
|
||||
*/
|
||||
}
|
||||
HRESULT result = cryptoSetPassword->CryptoSetPassword(
|
||||
(const Byte *)(const char *)charPassword, charPassword.Len());
|
||||
if (result != S_OK)
|
||||
{
|
||||
res = NExtract::NOperationResult::kWrongPassword;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
|
||||
res = NExtract::NOperationResult::kWrongPassword;
|
||||
return S_OK;
|
||||
// RINOK(cryptoSetPassword->CryptoSetPassword(NULL, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -781,16 +931,19 @@ HRESULT CZipDecoder::Decode(
|
||||
{
|
||||
CMethodItem mi;
|
||||
mi.ZipMethod = id;
|
||||
if (id == NFileHeader::NCompressionMethod::kStored)
|
||||
if (id == NFileHeader::NCompressionMethod::kStore)
|
||||
mi.Coder = new NCompress::CCopyCoder;
|
||||
else if (id == NFileHeader::NCompressionMethod::kShrunk)
|
||||
else if (id == NFileHeader::NCompressionMethod::kShrink)
|
||||
mi.Coder = new NCompress::NShrink::CDecoder;
|
||||
else if (id == NFileHeader::NCompressionMethod::kImploded)
|
||||
else if (id == NFileHeader::NCompressionMethod::kImplode)
|
||||
mi.Coder = new NCompress::NImplode::NDecoder::CCoder;
|
||||
else if (id == NFileHeader::NCompressionMethod::kLZMA)
|
||||
mi.Coder = new CLzmaDecoder;
|
||||
{
|
||||
lzmaDecoderSpec = new CLzmaDecoder;
|
||||
mi.Coder = lzmaDecoderSpec;
|
||||
}
|
||||
else if (id == NFileHeader::NCompressionMethod::kXz)
|
||||
mi.Coder = new CXzDecoder;
|
||||
mi.Coder = new NCompress::NXz::CComDecoder;
|
||||
else if (id == NFileHeader::NCompressionMethod::kPPMd)
|
||||
mi.Coder = new NCompress::NPpmdZip::CDecoder(true);
|
||||
else
|
||||
@@ -810,7 +963,7 @@ HRESULT CZipDecoder::Decode(
|
||||
|
||||
RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, false, mi.Coder));
|
||||
|
||||
if (mi.Coder == 0)
|
||||
if (!mi.Coder)
|
||||
{
|
||||
res = NExtract::NOperationResult::kUnsupportedMethod;
|
||||
return S_OK;
|
||||
@@ -842,9 +995,17 @@ HRESULT CZipDecoder::Decode(
|
||||
}
|
||||
#endif
|
||||
|
||||
CMyComPtr<ISequentialInStream> inStreamNew;
|
||||
|
||||
bool isFullStreamExpected = (!item.HasDescriptor() || item.PackSize != 0);
|
||||
bool needReminderCheck = false;
|
||||
|
||||
bool dataAfterEnd = false;
|
||||
bool truncatedError = false;
|
||||
bool lzmaEosError = false;
|
||||
|
||||
{
|
||||
HRESULT result = S_OK;
|
||||
CMyComPtr<ISequentialInStream> inStreamNew;
|
||||
if (item.IsEncrypted())
|
||||
{
|
||||
if (!filterStream)
|
||||
@@ -853,6 +1014,7 @@ HRESULT CZipDecoder::Decode(
|
||||
filterStream = filterStreamSpec;
|
||||
}
|
||||
|
||||
filterReleaser.FilterCoder = filterStreamSpec;
|
||||
filterStreamSpec->Filter = cryptoFilter;
|
||||
|
||||
if (wzAesMode)
|
||||
@@ -869,6 +1031,7 @@ HRESULT CZipDecoder::Decode(
|
||||
}
|
||||
else if (pkAesMode)
|
||||
{
|
||||
isFullStreamExpected = false;
|
||||
result =_pkAesDecoderSpec->ReadHeader(inStream, item.Crc, item.Size);
|
||||
if (result == S_OK)
|
||||
{
|
||||
@@ -926,7 +1089,70 @@ HRESULT CZipDecoder::Decode(
|
||||
inStreamNew = inStream;
|
||||
|
||||
if (result == S_OK)
|
||||
result = coder->Code(inStreamNew, outStream, NULL, &item.Size, compressProgress);
|
||||
{
|
||||
CMyComPtr<ICompressSetFinishMode> setFinishMode;
|
||||
coder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode);
|
||||
if (setFinishMode)
|
||||
{
|
||||
RINOK(setFinishMode->SetFinishMode(BoolToInt(true)));
|
||||
}
|
||||
|
||||
const UInt64 coderPackSize = limitedStreamSpec->GetRem();
|
||||
|
||||
bool useUnpackLimit = (id == 0
|
||||
|| !item.HasDescriptor()
|
||||
|| item.Size >= ((UInt64)1 << 32)
|
||||
|| item.LocalExtra.IsZip64
|
||||
|| item.CentralExtra.IsZip64
|
||||
);
|
||||
|
||||
result = coder->Code(inStreamNew, outStream,
|
||||
isFullStreamExpected ? &coderPackSize : NULL,
|
||||
// NULL,
|
||||
useUnpackLimit ? &item.Size : NULL,
|
||||
compressProgress);
|
||||
|
||||
if (result == S_OK)
|
||||
{
|
||||
CMyComPtr<ICompressGetInStreamProcessedSize> getInStreamProcessedSize;
|
||||
coder->QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize);
|
||||
if (getInStreamProcessedSize && setFinishMode)
|
||||
{
|
||||
UInt64 processed;
|
||||
RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed));
|
||||
if (processed != (UInt64)(Int64)-1)
|
||||
{
|
||||
if (pkAesMode)
|
||||
{
|
||||
const UInt32 padSize = _pkAesDecoderSpec->GetPadSize((UInt32)processed);
|
||||
if (processed + padSize > coderPackSize)
|
||||
truncatedError = true;
|
||||
else
|
||||
{
|
||||
if (processed + padSize < coderPackSize)
|
||||
dataAfterEnd = true;
|
||||
// also here we can check PKCS7 padding data from reminder (it can be inside stream buffer in coder).
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (processed < coderPackSize)
|
||||
{
|
||||
if (isFullStreamExpected)
|
||||
dataAfterEnd = true;
|
||||
}
|
||||
else if (processed > coderPackSize)
|
||||
truncatedError = true;
|
||||
needReminderCheck = isFullStreamExpected;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result == S_OK && id == NFileHeader::NCompressionMethod::kLZMA)
|
||||
if (!lzmaDecoderSpec->DecoderSpec->CheckFinishStatus(item.IsLzmaEOS()))
|
||||
lzmaEosError = true;
|
||||
}
|
||||
|
||||
if (result == S_FALSE)
|
||||
return S_OK;
|
||||
@@ -947,19 +1173,40 @@ HRESULT CZipDecoder::Decode(
|
||||
|
||||
if (wzAesMode)
|
||||
{
|
||||
const UInt64 rem = limitedStreamSpec->GetRem();
|
||||
if (rem != 0)
|
||||
if (SkipStreamData(inStream, rem) != S_OK)
|
||||
authOk = false;
|
||||
bool thereAreData = false;
|
||||
if (SkipStreamData(inStreamNew, thereAreData) != S_OK)
|
||||
authOk = false;
|
||||
|
||||
if (needReminderCheck && thereAreData)
|
||||
dataAfterEnd = true;
|
||||
|
||||
limitedStreamSpec->Init(NCrypto::NWzAes::kMacSize);
|
||||
if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK)
|
||||
authOk = false;
|
||||
}
|
||||
|
||||
res = ((crcOK && authOk) ?
|
||||
NExtract::NOperationResult::kOK :
|
||||
NExtract::NOperationResult::kCRCError);
|
||||
|
||||
res = NExtract::NOperationResult::kCRCError;
|
||||
|
||||
if (crcOK && authOk)
|
||||
{
|
||||
res = NExtract::NOperationResult::kOK;
|
||||
|
||||
if (dataAfterEnd)
|
||||
res = NExtract::NOperationResult::kDataAfterEnd;
|
||||
else if (truncatedError)
|
||||
res = NExtract::NOperationResult::kUnexpectedEnd;
|
||||
else if (lzmaEosError)
|
||||
res = NExtract::NOperationResult::kHeadersError;
|
||||
|
||||
// CheckDescriptor() supports only data descriptor with signature and
|
||||
// it doesn't support "old" pkzip's data descriptor without signature.
|
||||
// So we disable that check.
|
||||
/*
|
||||
if (item.HasDescriptor() && archive.CheckDescriptor(item) != S_OK)
|
||||
res = NExtract::NOperationResult::kHeadersError;
|
||||
*/
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -1026,11 +1273,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnavailable));
|
||||
continue;
|
||||
}
|
||||
|
||||
bool headersError = false;
|
||||
|
||||
if (!item.FromLocal)
|
||||
{
|
||||
bool isAvail = true;
|
||||
HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item, isAvail);
|
||||
HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item, isAvail, headersError);
|
||||
if (res == S_FALSE)
|
||||
{
|
||||
if (item.IsDir() || realOutStream || testMode)
|
||||
@@ -1069,12 +1318,16 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
m_Archive, item, realOutStream, extractCallback,
|
||||
progress,
|
||||
#ifndef _7ZIP_ST
|
||||
_props.NumThreads,
|
||||
_props._numThreads,
|
||||
#endif
|
||||
res);
|
||||
|
||||
RINOK(hres);
|
||||
realOutStream.Release();
|
||||
|
||||
if (res == NExtract::NOperationResult::kOK && headersError)
|
||||
res = NExtract::NOperationResult::kHeadersError;
|
||||
|
||||
RINOK(extractCallback->SetOperationResult(res))
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,20 @@
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
|
||||
#include "ZipIn.h"
|
||||
#include "ZipCompressionMode.h"
|
||||
#include "ZipIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
const unsigned kNumMethodNames1 = NFileHeader::NCompressionMethod::kLZMA + 1;
|
||||
const unsigned kMethodNames2Start = NFileHeader::NCompressionMethod::kXz;
|
||||
const unsigned kNumMethodNames2 = NFileHeader::NCompressionMethod::kWzAES + 1 - kMethodNames2Start;
|
||||
|
||||
extern const char * const kMethodNames1[kNumMethodNames1];
|
||||
extern const char * const kMethodNames2[kNumMethodNames2];
|
||||
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IOutArchive,
|
||||
|
||||
@@ -46,6 +46,30 @@ static bool IsSimpleAsciiString(const wchar_t *s)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int FindZipMethod(const char *s, const char * const *names, unsigned num)
|
||||
{
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
{
|
||||
const char *name = names[i];
|
||||
if (name && StringsAreEqualNoCase_Ascii(s, name))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int FindZipMethod(const char *s)
|
||||
{
|
||||
int k = FindZipMethod(s, kMethodNames1, kNumMethodNames1);
|
||||
if (k >= 0)
|
||||
return k;
|
||||
k = FindZipMethod(s, kMethodNames2, kNumMethodNames2);
|
||||
if (k >= 0)
|
||||
return kMethodNames2Start + k;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#define COM_TRY_BEGIN2 try {
|
||||
#define COM_TRY_END2 } \
|
||||
catch(const CSystemException &e) { return e.ErrorCode; } \
|
||||
@@ -63,6 +87,7 @@ static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propI
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
||||
IArchiveUpdateCallback *callback)
|
||||
{
|
||||
@@ -75,31 +100,46 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
}
|
||||
|
||||
CObjectVector<CUpdateItem> updateItems;
|
||||
updateItems.ClearAndReserve(numItems);
|
||||
|
||||
bool thereAreAesUpdates = false;
|
||||
UInt64 largestSize = 0;
|
||||
bool largestSizeDefined = false;
|
||||
|
||||
UString name;
|
||||
CUpdateItem ui;
|
||||
|
||||
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));
|
||||
|
||||
name.Empty();
|
||||
ui.Clear();
|
||||
|
||||
ui.NewProps = IntToBool(newProps);
|
||||
ui.NewData = IntToBool(newData);
|
||||
ui.IndexInArc = indexInArchive;
|
||||
ui.IndexInArc = indexInArc;
|
||||
ui.IndexInClient = i;
|
||||
bool existInArchive = (indexInArchive != (UInt32)(Int32)-1);
|
||||
if (existInArchive && newData)
|
||||
if (m_Items[indexInArchive].IsAesEncrypted())
|
||||
|
||||
bool existInArchive = (indexInArc != (UInt32)(Int32)-1);
|
||||
if (existInArchive)
|
||||
{
|
||||
const CItemEx &inputItem = m_Items[indexInArc];
|
||||
if (inputItem.IsAesEncrypted())
|
||||
thereAreAesUpdates = true;
|
||||
if (!IntToBool(newProps))
|
||||
ui.IsDir = inputItem.IsDir();
|
||||
}
|
||||
|
||||
if (IntToBool(newProps))
|
||||
{
|
||||
UString name;
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(callback->GetProperty(i, kpidAttrib, &prop));
|
||||
@@ -115,12 +155,15 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(callback->GetProperty(i, kpidPath, &prop));
|
||||
if (prop.vt == VT_EMPTY)
|
||||
name.Empty();
|
||||
{
|
||||
// name.Empty();
|
||||
}
|
||||
else if (prop.vt != VT_BSTR)
|
||||
return E_INVALIDARG;
|
||||
else
|
||||
name = prop.bstrVal;
|
||||
}
|
||||
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(callback->GetProperty(i, kpidIsDir, &prop));
|
||||
@@ -153,7 +196,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
FileTimeToDosTime(localFileTime, ui.Time);
|
||||
}
|
||||
|
||||
name = NItemName::MakeLegalName(name);
|
||||
NItemName::ReplaceSlashes_OsToUnix(name);
|
||||
|
||||
bool needSlash = ui.IsDir;
|
||||
const wchar_t kSlash = L'/';
|
||||
if (!name.IsEmpty())
|
||||
@@ -188,11 +232,37 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
if (ui.Name.Len() >= (1 << 16))
|
||||
return E_INVALIDARG;
|
||||
|
||||
ui.IndexInClient = i;
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(callback->GetProperty(i, kpidComment, &prop));
|
||||
if (prop.vt == VT_EMPTY)
|
||||
{
|
||||
// ui.Comment.Free();
|
||||
}
|
||||
else if (prop.vt != VT_BSTR)
|
||||
return E_INVALIDARG;
|
||||
else
|
||||
{
|
||||
UString s = prop.bstrVal;
|
||||
AString a;
|
||||
if (ui.IsUtf8)
|
||||
ConvertUnicodeToUTF8(s, a);
|
||||
else
|
||||
{
|
||||
bool defaultCharWasUsed;
|
||||
a = UnicodeStringToMultiByte(s, codePage, '_', defaultCharWasUsed);
|
||||
}
|
||||
if (a.Len() >= (1 << 16))
|
||||
return E_INVALIDARG;
|
||||
ui.Comment.CopyFrom((const Byte *)(const char *)a, a.Len());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
if (existInArchive)
|
||||
{
|
||||
const CItemEx &itemInfo = m_Items[indexInArchive];
|
||||
const CItemEx &itemInfo = m_Items[indexInArc];
|
||||
// ui.Commented = itemInfo.IsCommented();
|
||||
ui.Commented = false;
|
||||
if (ui.Commented)
|
||||
@@ -205,6 +275,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
ui.Commented = false;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
if (IntToBool(newData))
|
||||
{
|
||||
UInt64 size = 0;
|
||||
@@ -220,12 +292,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
largestSizeDefined = true;
|
||||
}
|
||||
ui.Size = size;
|
||||
|
||||
// ui.Size -= ui.Size / 2;
|
||||
}
|
||||
|
||||
updateItems.Add(ui);
|
||||
}
|
||||
|
||||
|
||||
CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
|
||||
{
|
||||
CMyComPtr<IArchiveUpdateCallback> udateCallBack2(callback);
|
||||
@@ -261,16 +333,52 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
}
|
||||
}
|
||||
|
||||
Byte mainMethod;
|
||||
if (m_MainMethod < 0)
|
||||
mainMethod = (Byte)(((_props.Level == 0) ?
|
||||
NFileHeader::NCompressionMethod::kStored :
|
||||
NFileHeader::NCompressionMethod::kDeflated));
|
||||
|
||||
int mainMethod = m_MainMethod;
|
||||
|
||||
if (mainMethod < 0)
|
||||
{
|
||||
if (!_props._methods.IsEmpty())
|
||||
{
|
||||
const AString &methodName = _props._methods.Front().MethodName;
|
||||
if (!methodName.IsEmpty())
|
||||
{
|
||||
mainMethod = FindZipMethod(methodName);
|
||||
if (mainMethod < 0)
|
||||
{
|
||||
CMethodId methodId;
|
||||
UInt32 numStreams;
|
||||
if (!FindMethod(EXTERNAL_CODECS_VARS methodName, methodId, numStreams))
|
||||
return E_NOTIMPL;
|
||||
if (numStreams != 1)
|
||||
return E_NOTIMPL;
|
||||
if (methodId == kMethodId_BZip2)
|
||||
mainMethod = NFileHeader::NCompressionMethod::kBZip2;
|
||||
else
|
||||
{
|
||||
if (methodId < kMethodId_ZipBase)
|
||||
return E_NOTIMPL;
|
||||
methodId -= kMethodId_ZipBase;
|
||||
if (methodId > 0xFF)
|
||||
return E_NOTIMPL;
|
||||
mainMethod = (int)methodId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mainMethod < 0)
|
||||
mainMethod = (Byte)(((_props.GetLevel() == 0) ?
|
||||
NFileHeader::NCompressionMethod::kStore :
|
||||
NFileHeader::NCompressionMethod::kDeflate));
|
||||
else
|
||||
mainMethod = (Byte)m_MainMethod;
|
||||
options.MethodSequence.Add(mainMethod);
|
||||
if (mainMethod != NFileHeader::NCompressionMethod::kStored)
|
||||
options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStored);
|
||||
mainMethod = (Byte)mainMethod;
|
||||
|
||||
options.MethodSequence.Add((Byte)mainMethod);
|
||||
|
||||
if (mainMethod != NFileHeader::NCompressionMethod::kStore)
|
||||
options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStore);
|
||||
|
||||
return Update(
|
||||
EXTERNAL_CODECS_VARS
|
||||
@@ -281,28 +389,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
COM_TRY_END2
|
||||
}
|
||||
|
||||
struct CMethodIndexToName
|
||||
{
|
||||
unsigned Method;
|
||||
const char *Name;
|
||||
};
|
||||
|
||||
static const CMethodIndexToName k_SupportedMethods[] =
|
||||
{
|
||||
{ NFileHeader::NCompressionMethod::kStored, "copy" },
|
||||
{ NFileHeader::NCompressionMethod::kDeflated, "deflate" },
|
||||
{ NFileHeader::NCompressionMethod::kDeflated64, "deflate64" },
|
||||
{ NFileHeader::NCompressionMethod::kBZip2, "bzip2" },
|
||||
{ NFileHeader::NCompressionMethod::kLZMA, "lzma" },
|
||||
{ NFileHeader::NCompressionMethod::kPPMd, "ppmd" }
|
||||
};
|
||||
|
||||
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
|
||||
{
|
||||
InitMethodProps();
|
||||
#ifndef _7ZIP_ST
|
||||
const UInt32 numProcessors = _props.NumThreads;
|
||||
#endif
|
||||
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
@@ -313,82 +404,27 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
|
||||
|
||||
const PROPVARIANT &prop = values[i];
|
||||
|
||||
if (name[0] == L'x')
|
||||
{
|
||||
UInt32 level = 9;
|
||||
RINOK(ParsePropToUInt32(name.Ptr(1), prop, level));
|
||||
_props.Level = level;
|
||||
_props.MethodInfo.AddProp_Level(level);
|
||||
}
|
||||
else if (name == L"m")
|
||||
{
|
||||
if (prop.vt == VT_BSTR)
|
||||
{
|
||||
UString m = prop.bstrVal, m2;
|
||||
m.MakeLower_Ascii();
|
||||
int colonPos = m.Find(L':');
|
||||
if (colonPos >= 0)
|
||||
{
|
||||
m2 = m.Ptr(colonPos + 1);
|
||||
m.DeleteFrom(colonPos);
|
||||
}
|
||||
unsigned k;
|
||||
for (k = 0; k < ARRAY_SIZE(k_SupportedMethods); k++)
|
||||
{
|
||||
const CMethodIndexToName &pair = k_SupportedMethods[k];
|
||||
if (m.IsEqualTo(pair.Name))
|
||||
{
|
||||
if (!m2.IsEmpty())
|
||||
{
|
||||
RINOK(_props.MethodInfo.ParseParamsFromString(m2));
|
||||
}
|
||||
m_MainMethod = pair.Method;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (k == ARRAY_SIZE(k_SupportedMethods))
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
else if (prop.vt == VT_UI4)
|
||||
{
|
||||
unsigned k;
|
||||
for (k = 0; k < ARRAY_SIZE(k_SupportedMethods); k++)
|
||||
{
|
||||
unsigned method = k_SupportedMethods[k].Method;
|
||||
if (prop.ulVal == method)
|
||||
{
|
||||
m_MainMethod = method;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (k == ARRAY_SIZE(k_SupportedMethods))
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
else if (name.IsPrefixedBy(L"em"))
|
||||
if (name.IsEqualTo_Ascii_NoCase("em"))
|
||||
{
|
||||
if (prop.vt != VT_BSTR)
|
||||
return E_INVALIDARG;
|
||||
{
|
||||
UString m = prop.bstrVal;
|
||||
m.MakeLower_Ascii();
|
||||
if (m.IsPrefixedBy(L"aes"))
|
||||
const wchar_t *m = prop.bstrVal;
|
||||
if (IsString1PrefixedByString2_NoCase_Ascii(m, "aes"))
|
||||
{
|
||||
m.DeleteFrontal(3);
|
||||
if (m == L"128")
|
||||
m += 3;
|
||||
if (StringsAreEqual_Ascii(m, "128"))
|
||||
_props.AesKeyMode = 1;
|
||||
else if (m == L"192")
|
||||
else if (StringsAreEqual_Ascii(m, "192"))
|
||||
_props.AesKeyMode = 2;
|
||||
else if (m == L"256" || m.IsEmpty())
|
||||
else if (StringsAreEqual_Ascii(m, "256") || m[0] == 0)
|
||||
_props.AesKeyMode = 3;
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
_props.IsAesMode = true;
|
||||
m_ForceAesMode = true;
|
||||
}
|
||||
else if (m == L"zipcrypto")
|
||||
else if (StringsAreEqualNoCase_Ascii(m, "ZipCrypto"))
|
||||
{
|
||||
_props.IsAesMode = false;
|
||||
m_ForceAesMode = true;
|
||||
@@ -397,13 +433,6 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
else if (name.IsPrefixedBy(L"mt"))
|
||||
{
|
||||
#ifndef _7ZIP_ST
|
||||
RINOK(ParseMtProp(name.Ptr(2), prop, numProcessors, _props.NumThreads));
|
||||
_props.NumThreadsWasChanged = true;
|
||||
#endif
|
||||
}
|
||||
else if (name.IsEqualTo("tc"))
|
||||
{
|
||||
RINOK(PROPVARIANT_to_bool(prop, m_WriteNtfsTimeExtra));
|
||||
@@ -433,9 +462,39 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop));
|
||||
if (name.IsEqualTo_Ascii_NoCase("m") && prop.vt == VT_UI4)
|
||||
{
|
||||
UInt32 id = prop.ulVal;
|
||||
if (id > 0xFF)
|
||||
return E_INVALIDARG;
|
||||
m_MainMethod = id;
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(_props.SetProperty(name, prop));
|
||||
}
|
||||
// RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop));
|
||||
}
|
||||
}
|
||||
|
||||
_props._methods.DeleteFrontal(_props.GetNumEmptyMethods());
|
||||
if (_props._methods.Size() > 1)
|
||||
return E_INVALIDARG;
|
||||
if (_props._methods.Size() == 1)
|
||||
{
|
||||
const AString &methodName = _props._methods[0].MethodName;
|
||||
|
||||
if (!methodName.IsEmpty())
|
||||
{
|
||||
const char *end;
|
||||
UInt32 id = ConvertStringToUInt32(methodName, &end);
|
||||
if (*end == 0 && id <= 0xFF)
|
||||
m_MainMethod = id;
|
||||
else if (methodName.IsEqualTo_Ascii_NoCase("Copy")) // it's alias for "Store"
|
||||
m_MainMethod = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ namespace NSignature
|
||||
}
|
||||
|
||||
const unsigned kLocalHeaderSize = 4 + 26; // including signature
|
||||
const unsigned kDataDescriptorSize = 4 + 12; // including signature
|
||||
const unsigned kDataDescriptorSize32 = 4 + 4 + 4 * 2; // including signature
|
||||
const unsigned kDataDescriptorSize64 = 4 + 4 + 8 * 2; // including signature
|
||||
const unsigned kCentralHeaderSize = 4 + 42; // including signature
|
||||
|
||||
const unsigned kEcdSize = 22; // including signature
|
||||
@@ -37,28 +38,30 @@ namespace NFileHeader
|
||||
{
|
||||
enum EType
|
||||
{
|
||||
kStored = 0,
|
||||
kShrunk = 1,
|
||||
kReduced1 = 2,
|
||||
kReduced2 = 3,
|
||||
kReduced3 = 4,
|
||||
kReduced4 = 5,
|
||||
kImploded = 6,
|
||||
kReservedTokenizing = 7, // reserved for tokenizing
|
||||
kDeflated = 8,
|
||||
kDeflated64 = 9,
|
||||
kStore = 0,
|
||||
kShrink = 1,
|
||||
kReduce1 = 2,
|
||||
kReduce2 = 3,
|
||||
kReduce3 = 4,
|
||||
kReduce4 = 5,
|
||||
kImplode = 6,
|
||||
kTokenize = 7,
|
||||
kDeflate = 8,
|
||||
kDeflate64 = 9,
|
||||
kPKImploding = 10,
|
||||
|
||||
kBZip2 = 12,
|
||||
|
||||
kLZMA = 14,
|
||||
|
||||
kTerse = 18,
|
||||
kLz77 = 19,
|
||||
|
||||
kXz = 0x5F,
|
||||
kJpeg = 0x60,
|
||||
kWavPack = 0x61,
|
||||
kPPMd = 0x62,
|
||||
kWzAES = 0x63
|
||||
kXz = 95,
|
||||
kJpeg = 96,
|
||||
kWavPack = 97,
|
||||
kPPMd = 98,
|
||||
kWzAES = 99
|
||||
};
|
||||
|
||||
const Byte kMadeByProgramVersion = 63;
|
||||
@@ -73,6 +76,7 @@ namespace NFileHeader
|
||||
const Byte kExtractVersion_Aes = 51;
|
||||
const Byte kExtractVersion_LZMA = 63;
|
||||
const Byte kExtractVersion_PPMd = 63;
|
||||
const Byte kExtractVersion_Xz = 20; // test it
|
||||
}
|
||||
|
||||
namespace NExtraID
|
||||
@@ -83,6 +87,7 @@ namespace NFileHeader
|
||||
kNTFS = 0x0A,
|
||||
kStrongEncrypt = 0x17,
|
||||
kUnixTime = 0x5455,
|
||||
kUnixExtra = 0x5855,
|
||||
kIzUnicodeComment = 0x6375,
|
||||
kIzUnicodeName = 0x7075,
|
||||
kWzAES = 0x9901
|
||||
@@ -110,6 +115,15 @@ namespace NFileHeader
|
||||
};
|
||||
}
|
||||
|
||||
namespace NUnixExtra
|
||||
{
|
||||
enum
|
||||
{
|
||||
kATime = 0,
|
||||
kMTime
|
||||
};
|
||||
}
|
||||
|
||||
namespace NFlags
|
||||
{
|
||||
const unsigned kEncrypted = 1 << 0;
|
||||
@@ -121,10 +135,12 @@ namespace NFileHeader
|
||||
const unsigned kImplodeDictionarySizeMask = 1 << 1;
|
||||
const unsigned kImplodeLiteralsOnMask = 1 << 2;
|
||||
|
||||
/*
|
||||
const unsigned kDeflateTypeBitStart = 1;
|
||||
const unsigned kNumDeflateTypeBits = 2;
|
||||
const unsigned kNumDeflateTypes = (1 << kNumDeflateTypeBits);
|
||||
const unsigned kDeflateTypeMask = (1 << kNumDeflateTypeBits) - 1;
|
||||
*/
|
||||
}
|
||||
|
||||
namespace NHostOS
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,12 +3,11 @@
|
||||
#ifndef __ZIP_IN_H
|
||||
#define __ZIP_IN_H
|
||||
|
||||
#include "../../../Common/MyBuffer2.h"
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "../../Common/InBuffer.h"
|
||||
|
||||
#include "ZipHeader.h"
|
||||
#include "ZipItem.h"
|
||||
|
||||
@@ -22,8 +21,12 @@ class CItemEx: public CItem
|
||||
public:
|
||||
UInt32 LocalFullHeaderSize; // including Name and Extra
|
||||
|
||||
bool DescriptorWasRead;
|
||||
|
||||
CItemEx(): DescriptorWasRead(false) {}
|
||||
|
||||
UInt64 GetLocalFullSize() const
|
||||
{ return LocalFullHeaderSize + PackSize + (HasDescriptor() ? kDataDescriptorSize : 0); }
|
||||
{ return LocalFullHeaderSize + GetPackSizeWithDescriptor(); }
|
||||
UInt64 GetDataPosition() const
|
||||
{ return LocalHeaderPos + LocalFullHeaderSize; }
|
||||
};
|
||||
@@ -52,6 +55,10 @@ struct CInArchiveInfo
|
||||
UInt64 FirstItemRelatOffset; /* Relative offset of first local (read from cd) (relative to Base).
|
||||
= 0 in most archives
|
||||
= size of stub for some SFXs */
|
||||
|
||||
|
||||
int MarkerVolIndex;
|
||||
|
||||
bool CdWasRead;
|
||||
bool IsSpanMode;
|
||||
bool ThereIsTail;
|
||||
@@ -68,6 +75,7 @@ struct CInArchiveInfo
|
||||
FinishPos(0),
|
||||
FileEndPos(0),
|
||||
FirstItemRelatOffset(0),
|
||||
MarkerVolIndex(-1),
|
||||
CdWasRead(false),
|
||||
IsSpanMode(false),
|
||||
ThereIsTail(false)
|
||||
@@ -82,6 +90,7 @@ struct CInArchiveInfo
|
||||
MarkerPos2 = 0;
|
||||
FinishPos = 0;
|
||||
FileEndPos = 0;
|
||||
MarkerVolIndex = -1;
|
||||
ThereIsTail = false;
|
||||
|
||||
FirstItemRelatOffset = 0;
|
||||
@@ -96,6 +105,10 @@ struct CInArchiveInfo
|
||||
|
||||
struct CCdInfo
|
||||
{
|
||||
bool IsFromEcd64;
|
||||
|
||||
UInt16 CommentSize;
|
||||
|
||||
// 64
|
||||
UInt16 VersionMade;
|
||||
UInt16 VersionNeedExtract;
|
||||
@@ -108,39 +121,55 @@ struct CCdInfo
|
||||
UInt64 Size;
|
||||
UInt64 Offset;
|
||||
|
||||
UInt16 CommentSize;
|
||||
|
||||
CCdInfo() { memset(this, 0, sizeof(*this)); }
|
||||
CCdInfo() { memset(this, 0, sizeof(*this)); IsFromEcd64 = false; }
|
||||
|
||||
void ParseEcd32(const Byte *p); // (p) includes signature
|
||||
void ParseEcd64e(const Byte *p); // (p) exclude signature
|
||||
|
||||
bool IsEmptyArc() const
|
||||
{
|
||||
return ThisDisk == 0
|
||||
&& CdDisk == 0
|
||||
&& NumEntries_in_ThisDisk == 0
|
||||
&& NumEntries == 0
|
||||
&& Size == 0
|
||||
&& Offset == 0 // test it
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CVols
|
||||
struct CVols
|
||||
{
|
||||
public:
|
||||
|
||||
struct CSubStreamInfo
|
||||
{
|
||||
CMyComPtr<IInStream> Stream;
|
||||
UInt64 Size;
|
||||
|
||||
HRESULT SeekToStart() const { return Stream->Seek(0, STREAM_SEEK_SET, NULL); }
|
||||
|
||||
CSubStreamInfo(): Size(0) {}
|
||||
};
|
||||
|
||||
CObjectVector<CSubStreamInfo> Streams;
|
||||
int StreamIndex;
|
||||
|
||||
int StreamIndex; // -1 for StartStream
|
||||
// -2 for ZipStream at multivol detection code
|
||||
// >=0 volume index in multivol
|
||||
|
||||
bool NeedSeek;
|
||||
|
||||
CMyComPtr<IInStream> ZipStream;
|
||||
|
||||
bool StartIsExe; // is .exe
|
||||
bool StartIsZ; // is .zip or .zNN
|
||||
bool StartIsZip; // is .zip
|
||||
bool IsUpperCase;
|
||||
bool MissingZip;
|
||||
Int32 StartVolIndex; // = (NN - 1), if StartStream is .zNN
|
||||
|
||||
bool ecd_wasRead;
|
||||
|
||||
Int32 StartVolIndex; // -1, if unknown vol index
|
||||
// = (NN - 1), if StartStream is .zNN
|
||||
// = 0, if start vol is exe
|
||||
|
||||
Int32 StartParsingVol; // if we need local parsing, we must use that stream
|
||||
unsigned NumVols;
|
||||
@@ -148,19 +177,27 @@ public:
|
||||
int EndVolIndex; // index of last volume (ecd volume),
|
||||
// -1, if is not multivol
|
||||
|
||||
UString BaseName; // including '.'
|
||||
|
||||
UString BaseName; // name of archive including '.'
|
||||
UString MissingName;
|
||||
|
||||
CMyComPtr<IInStream> ZipStream;
|
||||
|
||||
CCdInfo ecd;
|
||||
bool ecd_wasRead;
|
||||
|
||||
UInt64 TotalBytesSize; // for MultiVol only
|
||||
|
||||
void ClearRefs()
|
||||
{
|
||||
Streams.Clear();
|
||||
ZipStream.Release();
|
||||
TotalBytesSize = 0;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
StreamIndex = -1;
|
||||
NeedSeek = false;
|
||||
|
||||
|
||||
StartIsExe = false;
|
||||
StartIsZ = false;
|
||||
StartIsZip = false;
|
||||
@@ -177,21 +214,12 @@ public:
|
||||
MissingZip = false;
|
||||
ecd_wasRead = false;
|
||||
|
||||
Streams.Clear();
|
||||
ZipStream.Release();
|
||||
ClearRefs();
|
||||
}
|
||||
|
||||
HRESULT ParseArcName(IArchiveOpenVolumeCallback *volCallback);
|
||||
|
||||
HRESULT Read(void *data, UInt32 size, UInt32 *processedSize);
|
||||
|
||||
UInt64 GetTotalSize() const
|
||||
{
|
||||
UInt64 total = 0;
|
||||
FOR_VECTOR (i, Streams)
|
||||
total += Streams[i].Size;
|
||||
return total;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -210,44 +238,69 @@ public:
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
CInBuffer _inBuffer;
|
||||
bool _inBufMode;
|
||||
UInt32 m_Signature;
|
||||
UInt64 m_Position;
|
||||
CMidBuffer Buffer;
|
||||
size_t _bufPos;
|
||||
size_t _bufCached;
|
||||
|
||||
UInt64 _processedCnt;
|
||||
|
||||
UInt64 _streamPos;
|
||||
UInt64 _cnt;
|
||||
|
||||
size_t GetAvail() const { return _bufCached - _bufPos; }
|
||||
|
||||
void InitBuf() { _bufPos = 0; _bufCached = 0; }
|
||||
void DisableBufMode() { InitBuf(); _inBufMode = false; }
|
||||
|
||||
void SkipLookahed(size_t skip)
|
||||
{
|
||||
_bufPos += skip;
|
||||
_cnt += skip;
|
||||
}
|
||||
|
||||
UInt64 GetVirtStreamPos() { return _streamPos - _bufCached + _bufPos; }
|
||||
|
||||
bool _inBufMode;
|
||||
|
||||
bool IsArcOpen;
|
||||
bool CanStartNewVol;
|
||||
|
||||
UInt32 _signature;
|
||||
|
||||
CMyComPtr<IInStream> StreamRef;
|
||||
IInStream *Stream;
|
||||
IInStream *StartStream;
|
||||
IArchiveOpenCallback *Callback;
|
||||
|
||||
bool IsArcOpen;
|
||||
HRESULT Seek_SavePos(UInt64 offset);
|
||||
HRESULT SeekToVol(int volIndex, UInt64 offset);
|
||||
|
||||
HRESULT ReadFromCache(Byte *data, unsigned size, unsigned &processed);
|
||||
|
||||
HRESULT ReadVols2(IArchiveOpenVolumeCallback *volCallback,
|
||||
unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsigned &numMissingVols);
|
||||
HRESULT ReadVols();
|
||||
|
||||
HRESULT Seek(UInt64 offset);
|
||||
HRESULT FindMarker(IInStream *stream, const UInt64 *searchLimit);
|
||||
HRESULT IncreaseRealPosition(Int64 addValue, bool &isFinished);
|
||||
HRESULT FindMarker(const UInt64 *searchLimit);
|
||||
HRESULT IncreaseRealPosition(UInt64 addValue, bool &isFinished);
|
||||
|
||||
HRESULT ReadBytes(void *data, UInt32 size, UInt32 *processedSize);
|
||||
void SafeReadBytes(void *data, unsigned size);
|
||||
HRESULT LookAhead(size_t minRequiredInBuffer);
|
||||
void SafeRead(Byte *data, unsigned size);
|
||||
void ReadBuffer(CByteBuffer &buffer, unsigned size);
|
||||
Byte ReadByte();
|
||||
UInt16 ReadUInt16();
|
||||
// Byte ReadByte();
|
||||
// UInt16 ReadUInt16();
|
||||
UInt32 ReadUInt32();
|
||||
UInt64 ReadUInt64();
|
||||
void Skip(unsigned num);
|
||||
void Skip64(UInt64 num);
|
||||
void ReadFileName(unsigned nameSize, AString &dest);
|
||||
|
||||
bool ReadExtra(unsigned extraSize, CExtraBlock &extraBlock,
|
||||
UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber);
|
||||
void ReadSignature();
|
||||
|
||||
void Skip(size_t num);
|
||||
HRESULT Skip64(UInt64 num, unsigned numFiles);
|
||||
|
||||
bool ReadFileName(unsigned nameSize, AString &dest);
|
||||
|
||||
bool ReadExtra(unsigned extraSize, CExtraBlock &extra,
|
||||
UInt64 &unpackSize, UInt64 &packSize, UInt64 &localOffset, UInt32 &disk);
|
||||
bool ReadLocalItem(CItemEx &item);
|
||||
HRESULT ReadLocalItemDescriptor(CItemEx &item);
|
||||
HRESULT FindDescriptor(CItemEx &item, unsigned numFiles);
|
||||
HRESULT ReadCdItem(CItemEx &item);
|
||||
HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo);
|
||||
HRESULT FindCd(bool checkOffsetMode);
|
||||
@@ -255,21 +308,28 @@ class CInArchive
|
||||
HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize);
|
||||
HRESULT ReadLocals(CObjectVector<CItemEx> &localItems);
|
||||
|
||||
HRESULT ReadHeaders2(CObjectVector<CItemEx> &items);
|
||||
HRESULT ReadHeaders(CObjectVector<CItemEx> &items);
|
||||
|
||||
HRESULT GetVolStream(unsigned vol, UInt64 pos, CMyComPtr<ISequentialInStream> &stream);
|
||||
|
||||
public:
|
||||
CInArchiveInfo ArcInfo;
|
||||
|
||||
bool IsArc;
|
||||
bool IsZip64;
|
||||
|
||||
bool HeadersError;
|
||||
bool HeadersWarning;
|
||||
bool ExtraMinorError;
|
||||
bool UnexpectedEnd;
|
||||
bool LocalsWereRead;
|
||||
bool LocalsCenterMerged;
|
||||
bool NoCentralDir;
|
||||
bool Overflow32bit; // = true, if zip without Zip64 extension support and it has some fields values truncated to 32-bits.
|
||||
bool Cd_NumEntries_Overflow_16bit; // = true, if no Zip64 and 16-bit ecd:NumEntries was overflowed.
|
||||
|
||||
bool MarkerIsFound;
|
||||
bool MarkerIsSafe;
|
||||
|
||||
bool IsMultiVol;
|
||||
bool UseDisk_in_SingleVol;
|
||||
@@ -277,9 +337,7 @@ public:
|
||||
|
||||
CVols Vols;
|
||||
|
||||
IArchiveOpenCallback *Callback;
|
||||
|
||||
CInArchive(): Stream(NULL), Callback(NULL), IsArcOpen(false) {}
|
||||
CInArchive(): Stream(NULL), StartStream(NULL), Callback(NULL), IsArcOpen(false) {}
|
||||
|
||||
UInt64 GetPhySize() const
|
||||
{
|
||||
@@ -301,7 +359,6 @@ public:
|
||||
void ClearRefs();
|
||||
void Close();
|
||||
HRESULT Open(IInStream *stream, const UInt64 *searchLimit, IArchiveOpenCallback *callback, CObjectVector<CItemEx> &items);
|
||||
HRESULT ReadHeaders(CObjectVector<CItemEx> &items);
|
||||
|
||||
bool IsOpen() const { return IsArcOpen; }
|
||||
|
||||
@@ -329,7 +386,8 @@ public:
|
||||
}
|
||||
|
||||
|
||||
HRESULT ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail);
|
||||
HRESULT CheckDescriptor(const CItemEx &item);
|
||||
HRESULT ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail, bool &headersError);
|
||||
HRESULT ReadLocalItemAfterCdItemFull(CItemEx &item);
|
||||
|
||||
HRESULT GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr<ISequentialInStream> &stream);
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
#include "../../../../C/CpuArch.h"
|
||||
#include "../../../../C/7zCrc.h"
|
||||
|
||||
#include "../../../Common/IntToString.h"
|
||||
#include "../../../Common/MyLinux.h"
|
||||
#include "../../../Common/StringConvert.h"
|
||||
|
||||
#include "../../../Windows/PropVariantUtils.h"
|
||||
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
|
||||
#include "ZipItem.h"
|
||||
@@ -17,6 +20,62 @@ namespace NZip {
|
||||
|
||||
using namespace NFileHeader;
|
||||
|
||||
static const CUInt32PCharPair g_ExtraTypes[] =
|
||||
{
|
||||
{ NExtraID::kZip64, "Zip64" },
|
||||
{ NExtraID::kNTFS, "NTFS" },
|
||||
{ NExtraID::kStrongEncrypt, "StrongCrypto" },
|
||||
{ NExtraID::kUnixTime, "UT" },
|
||||
{ NExtraID::kUnixExtra, "UX" },
|
||||
{ NExtraID::kIzUnicodeComment, "uc" },
|
||||
{ NExtraID::kIzUnicodeName, "up" },
|
||||
{ NExtraID::kWzAES, "WzAES" }
|
||||
};
|
||||
|
||||
void CExtraSubBlock::PrintInfo(AString &s) const
|
||||
{
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(g_ExtraTypes); i++)
|
||||
{
|
||||
const CUInt32PCharPair &pair = g_ExtraTypes[i];
|
||||
if (pair.Value == ID)
|
||||
{
|
||||
s += pair.Name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
{
|
||||
char sz[32];
|
||||
sz[0] = '0';
|
||||
sz[1] = 'x';
|
||||
ConvertUInt32ToHex(ID, sz + 2);
|
||||
s += sz;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CExtraBlock::PrintInfo(AString &s) const
|
||||
{
|
||||
if (Error)
|
||||
s.Add_OptSpaced("Extra_ERROR");
|
||||
|
||||
if (MinorError)
|
||||
s.Add_OptSpaced("Minor_Extra_ERROR");
|
||||
|
||||
if (IsZip64 || IsZip64_Error)
|
||||
{
|
||||
s.Add_OptSpaced("Zip64");
|
||||
if (IsZip64_Error)
|
||||
s += "_ERROR";
|
||||
}
|
||||
|
||||
FOR_VECTOR (i, SubBlocks)
|
||||
{
|
||||
s.Add_Space_if_NotEmpty();
|
||||
SubBlocks[i].PrintInfo(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const
|
||||
{
|
||||
ft.dwHighDateTime = ft.dwLowDateTime = 0;
|
||||
@@ -83,6 +142,19 @@ bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res
|
||||
}
|
||||
|
||||
|
||||
bool CExtraSubBlock::ExtractUnixExtraTime(unsigned index, UInt32 &res) const
|
||||
{
|
||||
res = 0;
|
||||
const size_t size = Data.Size();
|
||||
unsigned offset = index * 4;
|
||||
if (ID != NExtraID::kUnixExtra || size < offset + 4)
|
||||
return false;
|
||||
const Byte *p = (const Byte *)Data + offset;
|
||||
res = GetUi32(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const
|
||||
{
|
||||
FOR_VECTOR (i, SubBlocks)
|
||||
@@ -96,11 +168,29 @@ bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const
|
||||
|
||||
bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const
|
||||
{
|
||||
FOR_VECTOR (i, SubBlocks)
|
||||
{
|
||||
const CExtraSubBlock &sb = SubBlocks[i];
|
||||
if (sb.ID == NFileHeader::NExtraID::kUnixTime)
|
||||
return sb.ExtractUnixTime(isCentral, index, res);
|
||||
FOR_VECTOR (i, SubBlocks)
|
||||
{
|
||||
const CExtraSubBlock &sb = SubBlocks[i];
|
||||
if (sb.ID == NFileHeader::NExtraID::kUnixTime)
|
||||
return sb.ExtractUnixTime(isCentral, index, res);
|
||||
}
|
||||
}
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case NUnixTime::kMTime: index = NUnixExtra::kMTime; break;
|
||||
case NUnixTime::kATime: index = NUnixExtra::kATime; break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
{
|
||||
FOR_VECTOR (i, SubBlocks)
|
||||
{
|
||||
const CExtraSubBlock &sb = SubBlocks[i];
|
||||
if (sb.ID == NFileHeader::NExtraID::kUnixExtra)
|
||||
return sb.ExtractUnixExtraTime(index, res);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -22,11 +22,12 @@ struct CVersion
|
||||
|
||||
struct CExtraSubBlock
|
||||
{
|
||||
UInt16 ID;
|
||||
UInt32 ID;
|
||||
CByteBuffer Data;
|
||||
|
||||
bool ExtractNtfsTime(unsigned index, FILETIME &ft) const;
|
||||
bool ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const;
|
||||
bool ExtractUnixExtraTime(unsigned index, UInt32 &res) const;
|
||||
|
||||
bool ExtractIzUnicode(UInt32 crc, AString &name) const
|
||||
{
|
||||
@@ -44,6 +45,8 @@ struct CExtraSubBlock
|
||||
return false;
|
||||
return CheckUTF8(name, false);
|
||||
}
|
||||
|
||||
void PrintInfo(AString &s) const;
|
||||
};
|
||||
|
||||
const unsigned k_WzAesExtra_Size = 7;
|
||||
@@ -129,11 +132,22 @@ struct CStrongCryptoExtra
|
||||
bool CertificateIsUsed() const { return (Flags > 0x0001); }
|
||||
};
|
||||
|
||||
|
||||
struct CExtraBlock
|
||||
{
|
||||
CObjectVector<CExtraSubBlock> SubBlocks;
|
||||
bool Error;
|
||||
bool MinorError;
|
||||
bool IsZip64;
|
||||
bool IsZip64_Error;
|
||||
|
||||
void Clear() { SubBlocks.Clear(); }
|
||||
CExtraBlock(): Error(false), MinorError(false), IsZip64(false), IsZip64_Error(false) {}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
SubBlocks.Clear();
|
||||
IsZip64 = false;
|
||||
}
|
||||
|
||||
size_t GetSize() const
|
||||
{
|
||||
@@ -176,6 +190,8 @@ struct CExtraBlock
|
||||
bool GetNtfsTime(unsigned index, FILETIME &ft) const;
|
||||
bool GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const;
|
||||
|
||||
void PrintInfo(AString &s) const;
|
||||
|
||||
void RemoveUnknownSubBlocks()
|
||||
{
|
||||
for (unsigned i = SubBlocks.Size(); i != 0;)
|
||||
@@ -206,12 +222,19 @@ public:
|
||||
|
||||
CExtraBlock LocalExtra;
|
||||
|
||||
unsigned GetDescriptorSize() const { return LocalExtra.IsZip64 ? kDataDescriptorSize64 : kDataDescriptorSize32; }
|
||||
|
||||
UInt64 GetPackSizeWithDescriptor() const
|
||||
{ return PackSize + (HasDescriptor() ? GetDescriptorSize() : 0); }
|
||||
|
||||
bool IsUtf8() const { return (Flags & NFileHeader::NFlags::kUtf8) != 0; }
|
||||
bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kEncrypted) != 0; }
|
||||
bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; }
|
||||
bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || Method == NFileHeader::NCompressionMethod::kWzAES); }
|
||||
bool IsLzmaEOS() const { return (Flags & NFileHeader::NFlags::kLzmaEOS) != 0; }
|
||||
bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; }
|
||||
|
||||
unsigned GetDeflateLevel() const { return (Flags >> 1) & 3; }
|
||||
|
||||
bool IsDir() const;
|
||||
|
||||
|
||||
@@ -21,48 +21,20 @@ HRESULT COutArchive::Create(IOutStream *outStream)
|
||||
return m_Stream->Seek(0, STREAM_SEEK_CUR, &m_Base);
|
||||
}
|
||||
|
||||
void COutArchive::MoveCurPos(UInt64 distanceToMove)
|
||||
void COutArchive::SeekToCurPos()
|
||||
{
|
||||
m_CurPos += distanceToMove; // test overflow
|
||||
}
|
||||
|
||||
void COutArchive::SeekToRelatPos(UInt64 offset)
|
||||
{
|
||||
HRESULT res = m_Stream->Seek(m_Base + offset, STREAM_SEEK_SET, NULL);
|
||||
HRESULT res = m_Stream->Seek(m_Base + m_CurPos, STREAM_SEEK_SET, NULL);
|
||||
if (res != S_OK)
|
||||
throw CSystemException(res);
|
||||
}
|
||||
|
||||
void COutArchive::PrepareWriteCompressedDataZip64(unsigned fileNameLen, bool isZip64, bool aesEncryption)
|
||||
{
|
||||
m_IsZip64 = isZip64;
|
||||
m_ExtraSize = isZip64 ? (4 + 8 + 8) : 0;
|
||||
if (aesEncryption)
|
||||
m_ExtraSize += 4 + k_WzAesExtra_Size;
|
||||
m_LocalFileHeaderSize = kLocalHeaderSize + fileNameLen + m_ExtraSize;
|
||||
}
|
||||
|
||||
void COutArchive::PrepareWriteCompressedData(unsigned fileNameLen, UInt64 unPackSize, bool aesEncryption)
|
||||
{
|
||||
// We use Zip64, if unPackSize size is larger than 0xF8000000 to support
|
||||
// cases when compressed size can be about 3% larger than uncompressed size
|
||||
|
||||
PrepareWriteCompressedDataZip64(fileNameLen, unPackSize >= (UInt32)0xF8000000, aesEncryption);
|
||||
}
|
||||
|
||||
#define DOES_NEED_ZIP64(v) (v >= (UInt32)0xFFFFFFFF)
|
||||
// #define DOES_NEED_ZIP64(v) (v >= 0)
|
||||
|
||||
void COutArchive::PrepareWriteCompressedData2(unsigned fileNameLen, UInt64 unPackSize, UInt64 packSize, bool aesEncryption)
|
||||
{
|
||||
bool isZip64 =
|
||||
DOES_NEED_ZIP64(unPackSize) ||
|
||||
DOES_NEED_ZIP64(packSize);
|
||||
PrepareWriteCompressedDataZip64(fileNameLen, isZip64, aesEncryption);
|
||||
}
|
||||
|
||||
void COutArchive::WriteBytes(const void *buffer, UInt32 size)
|
||||
void COutArchive::WriteBytes(const void *data, size_t size)
|
||||
{
|
||||
m_OutBuffer.WriteBytes(buffer, size);
|
||||
m_OutBuffer.WriteBytes(data, size);
|
||||
m_CurPos += size;
|
||||
}
|
||||
|
||||
@@ -74,11 +46,8 @@ void COutArchive::Write8(Byte b)
|
||||
|
||||
void COutArchive::Write16(UInt16 val)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Write8((Byte)val);
|
||||
val >>= 8;
|
||||
}
|
||||
Write8((Byte)val);
|
||||
Write8((Byte)(val >> 8));
|
||||
}
|
||||
|
||||
void COutArchive::Write32(UInt32 val)
|
||||
@@ -101,15 +70,12 @@ void COutArchive::Write64(UInt64 val)
|
||||
|
||||
void COutArchive::WriteExtra(const CExtraBlock &extra)
|
||||
{
|
||||
if (extra.SubBlocks.Size() != 0)
|
||||
FOR_VECTOR (i, extra.SubBlocks)
|
||||
{
|
||||
FOR_VECTOR (i, extra.SubBlocks)
|
||||
{
|
||||
const CExtraSubBlock &subBlock = extra.SubBlocks[i];
|
||||
Write16(subBlock.ID);
|
||||
Write16((UInt16)subBlock.Data.Size());
|
||||
WriteBytes(subBlock.Data, (UInt32)subBlock.Data.Size());
|
||||
}
|
||||
const CExtraSubBlock &subBlock = extra.SubBlocks[i];
|
||||
Write16((UInt16)subBlock.ID);
|
||||
Write16((UInt16)subBlock.Data.Size());
|
||||
WriteBytes(subBlock.Data, (UInt16)subBlock.Data.Size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,40 +91,65 @@ void COutArchive::WriteCommonItemInfo(const CLocalItem &item, bool isZip64)
|
||||
Write16(item.Flags);
|
||||
Write16(item.Method);
|
||||
Write32(item.Time);
|
||||
Write32(item.Crc);
|
||||
}
|
||||
|
||||
|
||||
#define WRITE_32_VAL_SPEC(__v, __isZip64) Write32((__isZip64) ? 0xFFFFFFFF : (UInt32)(__v));
|
||||
|
||||
void COutArchive::WriteLocalHeader(const CLocalItem &item)
|
||||
|
||||
void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
|
||||
{
|
||||
SeekToCurPos();
|
||||
m_LocalHeaderPos = m_CurPos;
|
||||
item.LocalHeaderPos = m_CurPos;
|
||||
|
||||
bool isZip64 = m_IsZip64 ||
|
||||
bool isZip64 =
|
||||
DOES_NEED_ZIP64(item.PackSize) ||
|
||||
DOES_NEED_ZIP64(item.Size);
|
||||
|
||||
Write32(NSignature::kLocalFileHeader);
|
||||
WriteCommonItemInfo(item, isZip64);
|
||||
|
||||
WRITE_32_VAL_SPEC(item.PackSize, isZip64);
|
||||
WRITE_32_VAL_SPEC(item.Size, isZip64);
|
||||
if (needCheck && m_IsZip64)
|
||||
isZip64 = true;
|
||||
|
||||
const UInt32 localExtraSize = (UInt32)((isZip64 ? (4 + 8 + 8): 0) + item.LocalExtra.GetSize());
|
||||
if ((UInt16)localExtraSize != localExtraSize)
|
||||
throw CSystemException(E_FAIL);
|
||||
if (needCheck && m_ExtraSize != localExtraSize)
|
||||
throw CSystemException(E_FAIL);
|
||||
|
||||
m_IsZip64 = isZip64;
|
||||
m_ExtraSize = localExtraSize;
|
||||
|
||||
item.LocalExtra.IsZip64 = isZip64;
|
||||
|
||||
Write32(NSignature::kLocalFileHeader);
|
||||
|
||||
WriteCommonItemInfo(item, isZip64);
|
||||
|
||||
Write32(item.HasDescriptor() ? 0 : item.Crc);
|
||||
|
||||
UInt64 packSize = item.PackSize;
|
||||
UInt64 size = item.Size;
|
||||
|
||||
if (item.HasDescriptor())
|
||||
{
|
||||
packSize = 0;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
WRITE_32_VAL_SPEC(packSize, isZip64);
|
||||
WRITE_32_VAL_SPEC(size, isZip64);
|
||||
|
||||
Write16((UInt16)item.Name.Len());
|
||||
{
|
||||
UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 8 + 8): 0) + item.LocalExtra.GetSize());
|
||||
if (localExtraSize != m_ExtraSize)
|
||||
throw CSystemException(E_FAIL);
|
||||
}
|
||||
Write16((UInt16)m_ExtraSize);
|
||||
WriteBytes((const char *)item.Name, item.Name.Len());
|
||||
|
||||
Write16((UInt16)localExtraSize);
|
||||
|
||||
WriteBytes((const char *)item.Name, (UInt16)item.Name.Len());
|
||||
|
||||
if (isZip64)
|
||||
{
|
||||
Write16(NFileHeader::NExtraID::kZip64);
|
||||
Write16(8 + 8);
|
||||
Write64(item.Size);
|
||||
Write64(item.PackSize);
|
||||
Write64(size);
|
||||
Write64(packSize);
|
||||
}
|
||||
|
||||
WriteExtra(item.LocalExtra);
|
||||
@@ -166,10 +157,57 @@ void COutArchive::WriteLocalHeader(const CLocalItem &item)
|
||||
// Why don't we write NTFS timestamps to local header?
|
||||
// Probably we want to reduce size of archive?
|
||||
|
||||
const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos);
|
||||
if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize)
|
||||
throw CSystemException(E_FAIL);
|
||||
m_LocalFileHeaderSize = localFileHeaderSize;
|
||||
|
||||
m_OutBuffer.FlushWithCheck();
|
||||
MoveCurPos(item.PackSize);
|
||||
}
|
||||
|
||||
|
||||
void COutArchive::WriteLocalHeader_Replace(CItemOut &item)
|
||||
{
|
||||
m_CurPos = m_LocalHeaderPos + m_LocalFileHeaderSize + item.PackSize;
|
||||
|
||||
if (item.HasDescriptor())
|
||||
{
|
||||
WriteDescriptor(item);
|
||||
m_OutBuffer.FlushWithCheck();
|
||||
}
|
||||
|
||||
const UInt64 nextPos = m_CurPos;
|
||||
m_CurPos = m_LocalHeaderPos;
|
||||
SeekToCurPos();
|
||||
WriteLocalHeader(item, true);
|
||||
m_CurPos = nextPos;
|
||||
SeekToCurPos();
|
||||
}
|
||||
|
||||
|
||||
void COutArchive::WriteDescriptor(const CItemOut &item)
|
||||
{
|
||||
Byte buf[kDataDescriptorSize64];
|
||||
SetUi32(buf, NSignature::kDataDescriptor);
|
||||
SetUi32(buf + 4, item.Crc);
|
||||
unsigned descriptorSize;
|
||||
if (m_IsZip64)
|
||||
{
|
||||
SetUi64(buf + 8, item.PackSize);
|
||||
SetUi64(buf + 16, item.Size);
|
||||
descriptorSize = kDataDescriptorSize64;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetUi32(buf + 8, (UInt32)item.PackSize);
|
||||
SetUi32(buf + 12, (UInt32)item.Size);
|
||||
descriptorSize = kDataDescriptorSize32;
|
||||
}
|
||||
WriteBytes(buf, descriptorSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void COutArchive::WriteCentralHeader(const CItemOut &item)
|
||||
{
|
||||
bool isUnPack64 = DOES_NEED_ZIP64(item.Size);
|
||||
@@ -182,6 +220,7 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
|
||||
Write8(item.MadeByVersion.HostOS);
|
||||
|
||||
WriteCommonItemInfo(item, isZip64);
|
||||
Write32(item.Crc);
|
||||
|
||||
WRITE_32_VAL_SPEC(item.PackSize, isPack64);
|
||||
WRITE_32_VAL_SPEC(item.Size, isUnPack64);
|
||||
@@ -196,7 +235,10 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
|
||||
item.CentralExtra.GetSize());
|
||||
|
||||
Write16(centralExtraSize); // test it;
|
||||
Write16((UInt16)item.Comment.Size());
|
||||
|
||||
const UInt16 commentSize = (UInt16)item.Comment.Size();
|
||||
|
||||
Write16(commentSize);
|
||||
Write16(0); // DiskNumberStart;
|
||||
Write16(item.InternalAttrib);
|
||||
Write32(item.ExternalAttrib);
|
||||
@@ -228,14 +270,12 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
|
||||
}
|
||||
|
||||
WriteExtra(item.CentralExtra);
|
||||
if (item.Comment.Size() > 0)
|
||||
WriteBytes(item.Comment, (UInt32)item.Comment.Size());
|
||||
if (commentSize != 0)
|
||||
WriteBytes(item.Comment, commentSize);
|
||||
}
|
||||
|
||||
void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment)
|
||||
{
|
||||
SeekToCurPos();
|
||||
|
||||
UInt64 cdOffset = GetCurPos();
|
||||
FOR_VECTOR (i, items)
|
||||
WriteCentralHeader(items[i]);
|
||||
@@ -252,6 +292,11 @@ void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CB
|
||||
{
|
||||
Write32(NSignature::kEcd64);
|
||||
Write64(kEcd64_MainSize);
|
||||
|
||||
// to test extra block:
|
||||
// const UInt32 extraSize = 1 << 26;
|
||||
// Write64(kEcd64_MainSize + extraSize);
|
||||
|
||||
Write16(45); // made by version
|
||||
Write16(45); // extract version
|
||||
Write32(0); // ThisDiskNumber = 0;
|
||||
@@ -261,6 +306,8 @@ void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CB
|
||||
Write64((UInt64)cdSize);
|
||||
Write64((UInt64)cdOffset);
|
||||
|
||||
// for (UInt32 iii = 0; iii < extraSize; iii++) Write8(1);
|
||||
|
||||
Write32(NSignature::kEcd64Locator);
|
||||
Write32(0); // number of the disk with the start of the zip64 end of central directory
|
||||
Write64(cd64EndOffset);
|
||||
@@ -276,37 +323,23 @@ void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CB
|
||||
WRITE_32_VAL_SPEC(cdSize, cdSize64);
|
||||
WRITE_32_VAL_SPEC(cdOffset, cdOffset64);
|
||||
|
||||
UInt32 commentSize = (UInt32)(comment ? comment->Size() : 0);
|
||||
const UInt16 commentSize = (UInt16)(comment ? comment->Size() : 0);
|
||||
Write16((UInt16)commentSize);
|
||||
if (commentSize > 0)
|
||||
if (commentSize != 0)
|
||||
WriteBytes((const Byte *)*comment, commentSize);
|
||||
m_OutBuffer.FlushWithCheck();
|
||||
}
|
||||
|
||||
void COutArchive::CreateStreamForCompressing(IOutStream **outStream)
|
||||
void COutArchive::CreateStreamForCompressing(CMyComPtr<IOutStream> &outStream)
|
||||
{
|
||||
COffsetOutStream *streamSpec = new COffsetOutStream;
|
||||
CMyComPtr<IOutStream> tempStream(streamSpec);
|
||||
streamSpec->Init(m_Stream, m_Base + m_CurPos + m_LocalFileHeaderSize);
|
||||
*outStream = tempStream.Detach();
|
||||
outStream = streamSpec;
|
||||
streamSpec->Init(m_Stream, m_Base + m_CurPos);
|
||||
}
|
||||
|
||||
/*
|
||||
void COutArchive::SeekToPackedDataPosition()
|
||||
void COutArchive::CreateStreamForCopying(CMyComPtr<ISequentialOutStream> &outStream)
|
||||
{
|
||||
SeekTo(m_BasePosition + m_LocalFileHeaderSize);
|
||||
}
|
||||
*/
|
||||
|
||||
void COutArchive::SeekToCurPos()
|
||||
{
|
||||
SeekToRelatPos(m_CurPos);
|
||||
}
|
||||
|
||||
void COutArchive::CreateStreamForCopying(ISequentialOutStream **outStream)
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> tempStream(m_Stream);
|
||||
*outStream = tempStream.Detach();
|
||||
outStream = m_Stream;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
#include "../../Common/OutBuffer.h"
|
||||
|
||||
#include "ZipItem.h"
|
||||
@@ -13,8 +12,6 @@
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
// can throw CSystemException and COutBufferException
|
||||
|
||||
class CItemOut: public CItem
|
||||
{
|
||||
public:
|
||||
@@ -28,21 +25,23 @@ public:
|
||||
CItemOut(): NtfsTimeIsDefined(false) {}
|
||||
};
|
||||
|
||||
|
||||
// COutArchive can throw CSystemException and COutBufferException
|
||||
|
||||
class COutArchive
|
||||
{
|
||||
CMyComPtr<IOutStream> m_Stream;
|
||||
COutBuffer m_OutBuffer;
|
||||
CMyComPtr<IOutStream> m_Stream;
|
||||
|
||||
UInt64 m_Base; // Base of arc (offset in output Stream)
|
||||
UInt64 m_Base; // Base of archive (offset in output Stream)
|
||||
UInt64 m_CurPos; // Curent position in archive (relative from m_Base)
|
||||
UInt64 m_LocalHeaderPos; // LocalHeaderPos (relative from m_Base) for last WriteLocalHeader() call
|
||||
|
||||
UInt32 m_LocalFileHeaderSize;
|
||||
UInt32 m_ExtraSize;
|
||||
bool m_IsZip64;
|
||||
|
||||
void SeekToRelatPos(UInt64 offset);
|
||||
|
||||
void WriteBytes(const void *buffer, UInt32 size);
|
||||
void WriteBytes(const void *data, size_t size);
|
||||
void Write8(Byte b);
|
||||
void Write16(UInt16 val);
|
||||
void Write32(UInt32 val);
|
||||
@@ -57,30 +56,26 @@ class COutArchive
|
||||
void WriteCommonItemInfo(const CLocalItem &item, bool isZip64);
|
||||
void WriteCentralHeader(const CItemOut &item);
|
||||
|
||||
void PrepareWriteCompressedDataZip64(unsigned fileNameLen, bool isZip64, bool aesEncryption);
|
||||
|
||||
void SeekToCurPos();
|
||||
public:
|
||||
HRESULT Create(IOutStream *outStream);
|
||||
|
||||
void MoveCurPos(UInt64 distanceToMove);
|
||||
UInt64 GetCurPos() const { return m_CurPos; }
|
||||
|
||||
void SeekToCurPos();
|
||||
|
||||
void PrepareWriteCompressedData(unsigned fileNameLen, UInt64 unPackSize, bool aesEncryption);
|
||||
void PrepareWriteCompressedData2(unsigned fileNameLen, UInt64 unPackSize, UInt64 packSize, bool aesEncryption);
|
||||
void WriteLocalHeader(const CLocalItem &item);
|
||||
|
||||
void WriteLocalHeader_And_SeekToNextFile(const CLocalItem &item)
|
||||
void MoveCurPos(UInt64 distanceToMove)
|
||||
{
|
||||
WriteLocalHeader(item);
|
||||
SeekToCurPos();
|
||||
m_CurPos += distanceToMove;
|
||||
}
|
||||
|
||||
void WriteLocalHeader(CItemOut &item, bool needCheck = false);
|
||||
void WriteLocalHeader_Replace(CItemOut &item);
|
||||
|
||||
void WriteDescriptor(const CItemOut &item);
|
||||
|
||||
void WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment);
|
||||
|
||||
void CreateStreamForCompressing(IOutStream **outStream);
|
||||
void CreateStreamForCopying(ISequentialOutStream **outStream);
|
||||
void CreateStreamForCompressing(CMyComPtr<IOutStream> &outStream);
|
||||
void CreateStreamForCopying(CMyComPtr<ISequentialOutStream> &outStream);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -10,13 +10,14 @@ namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
static const Byte k_Signature[] = {
|
||||
4, 0x50, 0x4B, 0x03, 0x04,
|
||||
4, 0x50, 0x4B, 0x05, 0x06,
|
||||
6, 0x50, 0x4B, 0x07, 0x08, 0x50, 0x4B,
|
||||
6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B };
|
||||
4, 0x50, 0x4B, 0x03, 0x04, // Local
|
||||
4, 0x50, 0x4B, 0x05, 0x06, // Ecd
|
||||
4, 0x50, 0x4B, 0x06, 0x06, // Ecd64
|
||||
6, 0x50, 0x4B, 0x07, 0x08, 0x50, 0x4B, // Span / Descriptor
|
||||
6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B }; // NoSpan
|
||||
|
||||
REGISTER_ARC_IO(
|
||||
"zip", "zip z01 zipx jar xpi odt ods docx xlsx epub", 0, 1,
|
||||
"zip", "zip z01 zipx jar xpi odt ods docx xlsx epub ipa apk appx", 0, 1,
|
||||
k_Signature,
|
||||
0,
|
||||
NArcInfoFlags::kFindSignature |
|
||||
|
||||
@@ -42,32 +42,38 @@ static const Byte kHostOS =
|
||||
static const Byte kMadeByHostOS = kHostOS;
|
||||
static const Byte kExtractHostOS = kHostOS;
|
||||
|
||||
static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStored;
|
||||
static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStore;
|
||||
|
||||
static HRESULT CopyBlockToArchive(ISequentialInStream *inStream, UInt64 size,
|
||||
COutArchive &outArchive, ICompressProgressInfo *progress)
|
||||
|
||||
static void AddAesExtra(CItem &item, Byte aesKeyMode, UInt16 method)
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
outArchive.CreateStreamForCopying(&outStream);
|
||||
return NCompress::CopyStream_ExactSize(inStream, outStream, size, progress);
|
||||
CWzAesExtra wzAesField;
|
||||
wzAesField.Strength = aesKeyMode;
|
||||
wzAesField.Method = method;
|
||||
item.Method = NFileHeader::NCompressionMethod::kWzAES;
|
||||
item.Crc = 0;
|
||||
CExtraSubBlock sb;
|
||||
wzAesField.SetSubBlock(sb);
|
||||
item.LocalExtra.SubBlocks.Add(sb);
|
||||
item.CentralExtra.SubBlocks.Add(sb);
|
||||
}
|
||||
|
||||
|
||||
static void SetFileHeader(
|
||||
COutArchive &archive,
|
||||
const CCompressionMethodMode &options,
|
||||
const CUpdateItem &ui,
|
||||
// bool isSeqMode,
|
||||
CItemOut &item)
|
||||
{
|
||||
item.Size = ui.Size;
|
||||
bool isDir;
|
||||
bool isDir = ui.IsDir;
|
||||
|
||||
item.ClearFlags();
|
||||
|
||||
if (ui.NewProps)
|
||||
{
|
||||
isDir = ui.IsDir;
|
||||
item.Name = ui.Name;
|
||||
item.Comment = ui.Comment;
|
||||
item.SetUtf8(ui.IsUtf8);
|
||||
item.ExternalAttrib = ui.Attrib;
|
||||
item.Time = ui.Time;
|
||||
@@ -76,10 +82,11 @@ static void SetFileHeader(
|
||||
item.Ntfs_CTime = ui.Ntfs_CTime;
|
||||
item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
|
||||
}
|
||||
/*
|
||||
else
|
||||
isDir = item.IsDir();
|
||||
*/
|
||||
|
||||
item.LocalHeaderPos = archive.GetCurPos();
|
||||
item.MadeByVersion.HostOS = kMadeByHostOS;
|
||||
item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion;
|
||||
|
||||
@@ -97,14 +104,32 @@ static void SetFileHeader(
|
||||
item.Size = 0;
|
||||
item.Crc = 0;
|
||||
}
|
||||
|
||||
item.LocalExtra.Clear();
|
||||
item.CentralExtra.Clear();
|
||||
|
||||
if (isDir)
|
||||
{
|
||||
item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir;
|
||||
item.Method = kMethodForDirectory;
|
||||
item.PackSize = 0;
|
||||
item.Size = 0;
|
||||
item.Crc = 0;
|
||||
}
|
||||
else if (options.IsRealAesMode())
|
||||
AddAesExtra(item, options.AesKeyMode, (Byte)(options.MethodSequence.IsEmpty() ? 8 : options.MethodSequence[0]));
|
||||
}
|
||||
|
||||
|
||||
// we call SetItemInfoFromCompressingResult() after SetFileHeader()
|
||||
|
||||
static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult,
|
||||
bool isAesMode, Byte aesKeyMode, CItem &item)
|
||||
{
|
||||
item.ExtractVersion.Version = compressingResult.ExtractVersion;
|
||||
item.Method = compressingResult.Method;
|
||||
if (compressingResult.Method == NFileHeader::NCompressionMethod::kLZMA && compressingResult.LzmaEos)
|
||||
item.Flags |= NFileHeader::NFlags::kLzmaEOS;
|
||||
item.Crc = compressingResult.CRC;
|
||||
item.Size = compressingResult.UnpackSize;
|
||||
item.PackSize = compressingResult.PackSize;
|
||||
@@ -113,17 +138,7 @@ static void SetItemInfoFromCompressingResult(const CCompressingResult &compressi
|
||||
item.CentralExtra.Clear();
|
||||
|
||||
if (isAesMode)
|
||||
{
|
||||
CWzAesExtra wzAesField;
|
||||
wzAesField.Strength = aesKeyMode;
|
||||
wzAesField.Method = compressingResult.Method;
|
||||
item.Method = NFileHeader::NCompressionMethod::kWzAES;
|
||||
item.Crc = 0;
|
||||
CExtraSubBlock sb;
|
||||
wzAesField.SetSubBlock(sb);
|
||||
item.LocalExtra.SubBlocks.Add(sb);
|
||||
item.CentralExtra.SubBlocks.Add(sb);
|
||||
}
|
||||
AddAesExtra(item, aesKeyMode, compressingResult.Method);
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +166,7 @@ struct CThreadInfo
|
||||
HRESULT Result;
|
||||
CCompressingResult CompressingResult;
|
||||
|
||||
bool SeqMode;
|
||||
bool IsFree;
|
||||
UInt32 UpdateIndex;
|
||||
UInt32 FileTime;
|
||||
@@ -160,6 +176,7 @@ struct CThreadInfo
|
||||
ProgressSpec(0),
|
||||
OutStreamSpec(0),
|
||||
Coder(options),
|
||||
SeqMode(false),
|
||||
FileTime(0)
|
||||
{}
|
||||
|
||||
@@ -193,7 +210,7 @@ void CThreadInfo::WaitAndCode()
|
||||
|
||||
Result = Coder.Compress(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
InStream, OutStream, FileTime, Progress, CompressingResult);
|
||||
InStream, OutStream, SeqMode, FileTime, Progress, CompressingResult);
|
||||
|
||||
if (Result == S_OK && Progress)
|
||||
Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize);
|
||||
@@ -342,6 +359,8 @@ static HRESULT UpdateItemOldData(
|
||||
NUpdateNotifyOp::kReplicate))
|
||||
}
|
||||
|
||||
UInt64 rangeSize;
|
||||
|
||||
if (ui.NewProps)
|
||||
{
|
||||
if (item.HasDescriptor())
|
||||
@@ -349,14 +368,11 @@ static HRESULT UpdateItemOldData(
|
||||
|
||||
// use old name size.
|
||||
|
||||
CMyComPtr<ISequentialInStream> packStream;
|
||||
RINOK(inArchive->GetItemStream(itemEx, true, packStream));
|
||||
if (!packStream)
|
||||
return E_NOTIMPL;
|
||||
|
||||
// we keep ExternalAttrib and some another properties from old archive
|
||||
// item.ExternalAttrib = ui.Attrib;
|
||||
|
||||
// if we don't change Comment, we keep Comment from OldProperties
|
||||
item.Comment = ui.Comment;
|
||||
item.Name = ui.Name;
|
||||
item.SetUtf8(ui.IsUtf8);
|
||||
item.Time = ui.Time;
|
||||
@@ -367,46 +383,37 @@ static HRESULT UpdateItemOldData(
|
||||
|
||||
item.CentralExtra.RemoveUnknownSubBlocks();
|
||||
item.LocalExtra.RemoveUnknownSubBlocks();
|
||||
item.LocalHeaderPos = archive.GetCurPos();
|
||||
|
||||
archive.PrepareWriteCompressedData2(item.Name.Len(), item.Size, item.PackSize, item.LocalExtra.HasWzAes());
|
||||
archive.WriteLocalHeader(item);
|
||||
|
||||
RINOK(CopyBlockToArchive(packStream, itemEx.PackSize, archive, progress));
|
||||
|
||||
complexity += itemEx.PackSize;
|
||||
rangeSize = item.GetPackSizeWithDescriptor();
|
||||
}
|
||||
else
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> packStream;
|
||||
RINOK(inArchive->GetItemStream(itemEx, false, packStream));
|
||||
if (!packStream)
|
||||
return E_NOTIMPL;
|
||||
|
||||
// set new header position
|
||||
item.LocalHeaderPos = archive.GetCurPos();
|
||||
|
||||
const UInt64 rangeSize = itemEx.GetLocalFullSize();
|
||||
|
||||
RINOK(CopyBlockToArchive(packStream, rangeSize, archive, progress));
|
||||
|
||||
complexity += rangeSize;
|
||||
archive.MoveCurPos(rangeSize);
|
||||
rangeSize = itemEx.GetLocalFullSize();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
CMyComPtr<ISequentialInStream> packStream;
|
||||
|
||||
RINOK(inArchive->GetItemStream(itemEx, ui.NewProps, packStream));
|
||||
if (!packStream)
|
||||
return E_NOTIMPL;
|
||||
|
||||
complexity += rangeSize;
|
||||
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
archive.CreateStreamForCopying(outStream);
|
||||
HRESULT res = NCompress::CopyStream_ExactSize(packStream, outStream, rangeSize, progress);
|
||||
archive.MoveCurPos(rangeSize);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options,
|
||||
const CUpdateItem &ui, CItemOut &item)
|
||||
{
|
||||
SetFileHeader(archive, *options, ui, item);
|
||||
archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size,
|
||||
// options->IsRealAesMode()
|
||||
false // fixed 9.31
|
||||
);
|
||||
archive.WriteLocalHeader_And_SeekToNextFile(item);
|
||||
SetFileHeader(*options, ui, item);
|
||||
archive.WriteLocalHeader(item);
|
||||
}
|
||||
|
||||
|
||||
@@ -490,6 +497,8 @@ static HRESULT Update2St(
|
||||
|
||||
if (!ui.NewProps || !ui.NewData)
|
||||
{
|
||||
// Note: for (ui.NewProps && !ui.NewData) it copies Props from old archive,
|
||||
// But we will rewrite all important properties later. But we can keep some properties like Comment
|
||||
itemEx = inputItems[ui.IndexInArc];
|
||||
if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK)
|
||||
return E_NOTIMPL;
|
||||
@@ -498,7 +507,8 @@ static HRESULT Update2St(
|
||||
|
||||
if (ui.NewData)
|
||||
{
|
||||
bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir());
|
||||
// bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir());
|
||||
bool isDir = ui.IsDir;
|
||||
if (isDir)
|
||||
{
|
||||
WriteDirHeader(archive, options, ui, item);
|
||||
@@ -517,28 +527,39 @@ static HRESULT Update2St(
|
||||
if (!fileInStream)
|
||||
return E_INVALIDARG;
|
||||
|
||||
// bool isSeqMode = false;
|
||||
/*
|
||||
bool seqMode;
|
||||
{
|
||||
CMyComPtr<IInStream> inStream2;
|
||||
fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2);
|
||||
isSeqMode = (inStream2 == NULL);
|
||||
seqMode = (inStream2 == NULL);
|
||||
}
|
||||
*/
|
||||
// seqMode = true; // to test seqMode
|
||||
|
||||
UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity);
|
||||
SetFileHeader(archive, *options, ui, item);
|
||||
SetFileHeader(*options, ui, item);
|
||||
|
||||
item.SetDescriptorMode(seqMode);
|
||||
|
||||
// file Size can be 64-bit !!!
|
||||
archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode());
|
||||
|
||||
CCompressingResult compressingResult;
|
||||
|
||||
RINOK(compressor.Set_Pre_CompressionResult(
|
||||
seqMode,
|
||||
ui.Size,
|
||||
compressingResult));
|
||||
|
||||
SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
|
||||
|
||||
archive.WriteLocalHeader(item);
|
||||
|
||||
CMyComPtr<IOutStream> outStream;
|
||||
archive.CreateStreamForCompressing(&outStream);
|
||||
archive.CreateStreamForCompressing(outStream);
|
||||
|
||||
RINOK(compressor.Compress(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
fileInStream, outStream,
|
||||
ui.Time,
|
||||
seqMode, ui.Time,
|
||||
progress, compressingResult));
|
||||
|
||||
if (compressingResult.FileTimeWasUsed)
|
||||
@@ -551,7 +572,9 @@ static HRESULT Update2St(
|
||||
}
|
||||
|
||||
SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
|
||||
archive.WriteLocalHeader_And_SeekToNextFile(item);
|
||||
|
||||
archive.WriteLocalHeader_Replace(item);
|
||||
|
||||
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
|
||||
unpackSizeTotal += item.Size;
|
||||
packSizeTotal += item.PackSize;
|
||||
@@ -561,7 +584,9 @@ static HRESULT Update2St(
|
||||
{
|
||||
UInt64 complexity = 0;
|
||||
lps->SendRatio = false;
|
||||
|
||||
RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity));
|
||||
|
||||
lps->SendRatio = true;
|
||||
lps->ProgressOffset += complexity;
|
||||
}
|
||||
@@ -591,6 +616,7 @@ static HRESULT Update2(
|
||||
CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
|
||||
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
|
||||
|
||||
bool unknownComplexity = false;
|
||||
UInt64 complexity = 0;
|
||||
UInt64 numFilesToCompress = 0;
|
||||
UInt64 numBytesToCompress = 0;
|
||||
@@ -602,7 +628,10 @@ static HRESULT Update2(
|
||||
const CUpdateItem &ui = updateItems[i];
|
||||
if (ui.NewData)
|
||||
{
|
||||
complexity += ui.Size;
|
||||
if (ui.Size == (UInt64)(Int64)-1)
|
||||
unknownComplexity = true;
|
||||
else
|
||||
complexity += ui.Size;
|
||||
numBytesToCompress += ui.Size;
|
||||
numFilesToCompress++;
|
||||
/*
|
||||
@@ -625,19 +654,49 @@ static HRESULT Update2(
|
||||
if (comment)
|
||||
complexity += comment->Size();
|
||||
complexity++; // end of central
|
||||
updateCallback->SetTotal(complexity);
|
||||
|
||||
if (!unknownComplexity)
|
||||
updateCallback->SetTotal(complexity);
|
||||
|
||||
UInt64 totalComplexity = complexity;
|
||||
|
||||
CAddCommon compressor(options);
|
||||
CCompressionMethodMode options2 = options;
|
||||
|
||||
if (options2._methods.IsEmpty())
|
||||
{
|
||||
// we need method item, if default method was used
|
||||
options2._methods.AddNew();
|
||||
}
|
||||
|
||||
CAddCommon compressor(options2);
|
||||
|
||||
complexity = 0;
|
||||
|
||||
CCompressionMethodMode options2 = options;
|
||||
const Byte method = options.MethodSequence.Front();
|
||||
|
||||
COneMethodInfo *oneMethodMain = NULL;
|
||||
if (!options2._methods.IsEmpty())
|
||||
oneMethodMain = &options2._methods[0];
|
||||
|
||||
{
|
||||
FOR_VECTOR (mi, options2._methods)
|
||||
{
|
||||
options2.SetGlobalLevelTo(options2._methods[mi]);
|
||||
}
|
||||
}
|
||||
|
||||
if (oneMethodMain)
|
||||
{
|
||||
// appnote recommends to use EOS marker for LZMA.
|
||||
if (method == NFileHeader::NCompressionMethod::kLZMA)
|
||||
oneMethodMain->AddProp_EndMarker_if_NotFound(true);
|
||||
}
|
||||
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
|
||||
UInt32 numThreads = options.NumThreads;
|
||||
UInt32 numThreads = options._numThreads;
|
||||
|
||||
const UInt32 kNumMaxThreads = 64;
|
||||
if (numThreads > kNumMaxThreads)
|
||||
numThreads = kNumMaxThreads;
|
||||
@@ -646,7 +705,6 @@ static HRESULT Update2(
|
||||
if (numThreads < 1)
|
||||
numThreads = 1;
|
||||
|
||||
|
||||
const size_t kMemPerThread = (1 << 25);
|
||||
const size_t kBlockSize = 1 << 16;
|
||||
|
||||
@@ -655,44 +713,69 @@ static HRESULT Update2(
|
||||
if (numFilesToCompress <= 1)
|
||||
mtMode = false;
|
||||
|
||||
Byte method = options.MethodSequence.Front();
|
||||
|
||||
if (!mtMode)
|
||||
{
|
||||
if (options2.MethodInfo.FindProp(NCoderPropID::kNumThreads) < 0)
|
||||
FOR_VECTOR (mi, options2._methods)
|
||||
{
|
||||
// fixed for 9.31. bzip2 default is just one thread.
|
||||
if (options2.NumThreadsWasChanged || method == NFileHeader::NCompressionMethod::kBZip2)
|
||||
options2.MethodInfo.AddProp_NumThreads(numThreads);
|
||||
COneMethodInfo &onem = options2._methods[mi];
|
||||
|
||||
if (onem.FindProp(NCoderPropID::kNumThreads) < 0)
|
||||
{
|
||||
// fixed for 9.31. bzip2 default is just one thread.
|
||||
onem.AddProp_NumThreads(numThreads);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (method == NFileHeader::NCompressionMethod::kStored && !options.PasswordIsDefined)
|
||||
if (method == NFileHeader::NCompressionMethod::kStore && !options.PasswordIsDefined)
|
||||
numThreads = 1;
|
||||
|
||||
if (oneMethodMain)
|
||||
{
|
||||
|
||||
if (method == NFileHeader::NCompressionMethod::kBZip2)
|
||||
{
|
||||
bool fixedNumber;
|
||||
UInt32 numBZip2Threads = options2.MethodInfo.Get_BZip2_NumThreads(fixedNumber);
|
||||
UInt32 numBZip2Threads = oneMethodMain->Get_BZip2_NumThreads(fixedNumber);
|
||||
if (!fixedNumber)
|
||||
{
|
||||
UInt64 averageSize = numBytesToCompress / numFilesToCompress;
|
||||
UInt32 blockSize = options2.MethodInfo.Get_BZip2_BlockSize();
|
||||
UInt64 averageNumberOfBlocks = averageSize / blockSize + 1;
|
||||
const UInt64 averageSize = numBytesToCompress / numFilesToCompress;
|
||||
const UInt32 blockSize = oneMethodMain->Get_BZip2_BlockSize();
|
||||
const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1;
|
||||
numBZip2Threads = 32;
|
||||
if (averageNumberOfBlocks < numBZip2Threads)
|
||||
if (numBZip2Threads > averageNumberOfBlocks)
|
||||
numBZip2Threads = (UInt32)averageNumberOfBlocks;
|
||||
options2.MethodInfo.AddProp_NumThreads(numBZip2Threads);
|
||||
oneMethodMain->AddProp_NumThreads(numBZip2Threads);
|
||||
}
|
||||
numThreads /= numBZip2Threads;
|
||||
}
|
||||
if (method == NFileHeader::NCompressionMethod::kLZMA)
|
||||
|
||||
if (method == NFileHeader::NCompressionMethod::kXz)
|
||||
{
|
||||
bool fixedNumber;
|
||||
UInt32 numLzma2Threads = oneMethodMain->Get_Lzma2_NumThreads(fixedNumber);
|
||||
if (!fixedNumber)
|
||||
{
|
||||
const UInt64 averageSize = numBytesToCompress / numFilesToCompress;
|
||||
const UInt64 blockSize = oneMethodMain->Get_Lzma2_BlockSize();
|
||||
const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1;
|
||||
numLzma2Threads = 2;
|
||||
if (numLzma2Threads > averageNumberOfBlocks)
|
||||
numLzma2Threads = (UInt32)averageNumberOfBlocks;
|
||||
oneMethodMain->AddProp_NumThreads(numLzma2Threads);
|
||||
}
|
||||
numThreads /= numLzma2Threads;
|
||||
}
|
||||
|
||||
if (method == NFileHeader::NCompressionMethod::kLZMA)
|
||||
{
|
||||
// we suppose that default LZMA is 2 thread. So we don't change it
|
||||
UInt32 numLZMAThreads = options2.MethodInfo.Get_Lzma_NumThreads(fixedNumber);
|
||||
UInt32 numLZMAThreads = oneMethodMain->Get_Lzma_NumThreads();
|
||||
numThreads /= numLZMAThreads;
|
||||
}
|
||||
}
|
||||
|
||||
if (numThreads > numFilesToCompress)
|
||||
numThreads = (UInt32)numFilesToCompress;
|
||||
if (numThreads <= 1)
|
||||
@@ -747,6 +830,7 @@ static HRESULT Update2(
|
||||
threadInfo.ProgressSpec = new CMtCompressProgress();
|
||||
threadInfo.Progress = threadInfo.ProgressSpec;
|
||||
threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i);
|
||||
threadInfo.SeqMode = false; // fix it !
|
||||
threadInfo.FileTime = 0; // fix it !
|
||||
RINOK(threadInfo.CreateThread());
|
||||
}
|
||||
@@ -777,7 +861,9 @@ static HRESULT Update2(
|
||||
if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK)
|
||||
return E_NOTIMPL;
|
||||
(CItem &)item = itemEx;
|
||||
if (item.IsDir())
|
||||
if (item.IsDir() != ui.IsDir)
|
||||
return E_NOTIMPL;
|
||||
if (ui.IsDir)
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -849,7 +935,8 @@ static HRESULT Update2(
|
||||
|
||||
if (ui.NewData)
|
||||
{
|
||||
bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir());
|
||||
// bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir());
|
||||
bool isDir = ui.IsDir;
|
||||
|
||||
if (isDir)
|
||||
{
|
||||
@@ -857,39 +944,51 @@ static HRESULT Update2(
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lastRealStreamItemIndex < (int)itemIndex)
|
||||
{
|
||||
lastRealStreamItemIndex = itemIndex;
|
||||
SetFileHeader(archive, options, ui, item);
|
||||
// file Size can be 64-bit !!!
|
||||
archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options.IsRealAesMode());
|
||||
}
|
||||
|
||||
CMemBlocks2 &memRef = refs.Refs[itemIndex];
|
||||
|
||||
if (memRef.Defined)
|
||||
{
|
||||
CMyComPtr<IOutStream> outStream;
|
||||
archive.CreateStreamForCompressing(&outStream);
|
||||
memRef.WriteToStream(memManager.GetBlockSize(), outStream);
|
||||
SetFileHeader(archive, options, ui, item);
|
||||
if (lastRealStreamItemIndex < (int)itemIndex)
|
||||
lastRealStreamItemIndex = itemIndex;
|
||||
|
||||
SetFileHeader(options, ui, item);
|
||||
// the BUG was fixed in 9.26:
|
||||
// SetItemInfoFromCompressingResult must be after SetFileHeader
|
||||
// to write correct Size.
|
||||
SetItemInfoFromCompressingResult(memRef.CompressingResult,
|
||||
options.IsRealAesMode(), options.AesKeyMode, item);
|
||||
archive.WriteLocalHeader_And_SeekToNextFile(item);
|
||||
archive.WriteLocalHeader(item);
|
||||
// RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
archive.CreateStreamForCopying(outStream);
|
||||
memRef.WriteToStream(memManager.GetBlockSize(), outStream);
|
||||
archive.MoveCurPos(item.PackSize);
|
||||
memRef.FreeOpt(&memManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lastRealStreamItemIndex < (int)itemIndex)
|
||||
{
|
||||
lastRealStreamItemIndex = itemIndex;
|
||||
SetFileHeader(options, ui, item);
|
||||
|
||||
CCompressingResult compressingResult;
|
||||
RINOK(compressor.Set_Pre_CompressionResult(
|
||||
false, // seqMode
|
||||
ui.Size,
|
||||
compressingResult));
|
||||
SetItemInfoFromCompressingResult(compressingResult, options.IsRealAesMode(), options.AesKeyMode, item);
|
||||
|
||||
// file Size can be 64-bit !!!
|
||||
archive.WriteLocalHeader(item);
|
||||
}
|
||||
|
||||
{
|
||||
CThreadInfo &thread = threads.Threads[threadIndices.Front()];
|
||||
if (!thread.OutStreamSpec->WasUnlockEventSent())
|
||||
{
|
||||
CMyComPtr<IOutStream> outStream;
|
||||
archive.CreateStreamForCompressing(&outStream);
|
||||
archive.CreateStreamForCompressing(outStream);
|
||||
thread.OutStreamSpec->SetOutStream(outStream);
|
||||
thread.OutStreamSpec->SetRealStreamMode();
|
||||
}
|
||||
@@ -918,10 +1017,10 @@ static HRESULT Update2(
|
||||
{
|
||||
RINOK(threadInfo.OutStreamSpec->WriteToRealStream());
|
||||
threadInfo.OutStreamSpec->ReleaseOutStream();
|
||||
SetFileHeader(archive, options, ui, item);
|
||||
SetFileHeader(options, ui, item);
|
||||
SetItemInfoFromCompressingResult(threadInfo.CompressingResult,
|
||||
options.IsRealAesMode(), options.AesKeyMode, item);
|
||||
archive.WriteLocalHeader_And_SeekToNextFile(item);
|
||||
archive.WriteLocalHeader_Replace(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
/*
|
||||
struct CUpdateRange
|
||||
{
|
||||
UInt64 Position;
|
||||
@@ -22,6 +23,7 @@ struct CUpdateRange
|
||||
// CUpdateRange() {};
|
||||
CUpdateRange(UInt64 position, UInt64 size): Position(position), Size(size) {};
|
||||
};
|
||||
*/
|
||||
|
||||
struct CUpdateItem
|
||||
{
|
||||
@@ -36,12 +38,23 @@ struct CUpdateItem
|
||||
UInt32 Time;
|
||||
UInt64 Size;
|
||||
AString Name;
|
||||
CByteBuffer Comment;
|
||||
// bool Commented;
|
||||
// CUpdateRange CommentRange;
|
||||
FILETIME Ntfs_MTime;
|
||||
FILETIME Ntfs_ATime;
|
||||
FILETIME Ntfs_CTime;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
IsDir = false;
|
||||
NtfsTimeIsDefined = false;
|
||||
IsUtf8 = false;
|
||||
Size = 0;
|
||||
Name.Empty();
|
||||
Comment.Free();
|
||||
}
|
||||
|
||||
CUpdateItem(): NtfsTimeIsDefined(false), IsUtf8(false), Size(0) {}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user