This commit is contained in:
Igor Pavlov
2017-04-30 00:00:00 +00:00
committed by Kornel
parent 603abd5528
commit 2efa10565a
442 changed files with 15479 additions and 8525 deletions

View File

@@ -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)
{

View File

@@ -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);
};
}}

View File

@@ -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;
}

View File

@@ -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))
}

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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

View File

File diff suppressed because it is too large Load Diff

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}
}}

View File

@@ -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);
};
}}

View File

@@ -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 |

View File

@@ -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
{

View File

@@ -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) {}
};