chore: initial commit (extracted from Launchers monorepo)
Plugin: ns7zip v2.0.0 Architectures: x86-ansi, x86-unicode, amd64-unicode License: LGPL-2.1-or-later
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef ZIP7_INC_STDAFX_H
|
||||
#define ZIP7_INC_STDAFX_H
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1800
|
||||
#pragma warning(disable : 4464) // relative include path contains '..'
|
||||
#endif
|
||||
#include "../../../Common/Common.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,484 @@
|
||||
// ZipAddCommon.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
#include "../../../../C/Alloc.h"
|
||||
|
||||
#include "../../../Windows/PropVariant.h"
|
||||
|
||||
#include "../../ICoder.h"
|
||||
#include "../../IPassword.h"
|
||||
#include "../../MyVersion.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
#include "../../Common/StreamObjects.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "../../Compress/LzmaEncoder.h"
|
||||
#include "../../Compress/PpmdZip.h"
|
||||
#include "../../Compress/XzEncoder.h"
|
||||
|
||||
#include "../Common/InStreamWithCRC.h"
|
||||
|
||||
#include "ZipAddCommon.h"
|
||||
#include "ZipHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
using namespace NFileHeader;
|
||||
|
||||
|
||||
static const unsigned kLzmaPropsSize = 5;
|
||||
static const unsigned kLzmaHeaderSize = 4 + kLzmaPropsSize;
|
||||
|
||||
Z7_CLASS_IMP_NOQIB_3(
|
||||
CLzmaEncoder
|
||||
, ICompressCoder
|
||||
, ICompressSetCoderProperties
|
||||
, ICompressSetCoderPropertiesOpt
|
||||
)
|
||||
public:
|
||||
CMyComPtr2<ICompressCoder, NCompress::NLzma::CEncoder> Encoder;
|
||||
Byte Header[kLzmaHeaderSize];
|
||||
};
|
||||
|
||||
Z7_COM7F_IMF(CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
|
||||
{
|
||||
Encoder.Create_if_Empty();
|
||||
CMyComPtr2_Create<ISequentialOutStream, CBufPtrSeqOutStream> outStream;
|
||||
outStream->Init(Header + 4, kLzmaPropsSize);
|
||||
RINOK(Encoder->SetCoderProperties(propIDs, props, numProps))
|
||||
RINOK(Encoder->WriteCoderProperties(outStream))
|
||||
if (outStream->GetPos() != kLzmaPropsSize)
|
||||
return E_FAIL;
|
||||
Header[0] = MY_VER_MAJOR;
|
||||
Header[1] = MY_VER_MINOR;
|
||||
Header[2] = kLzmaPropsSize;
|
||||
Header[3] = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Z7_COM7F_IMF(CLzmaEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
|
||||
{
|
||||
return Encoder->SetCoderPropertiesOpt(propIDs, props, numProps);
|
||||
}
|
||||
|
||||
Z7_COM7F_IMF(CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
|
||||
{
|
||||
RINOK(WriteStream(outStream, Header, kLzmaHeaderSize))
|
||||
return Encoder.Interface()->Code(inStream, outStream, inSize, outSize, progress);
|
||||
}
|
||||
|
||||
|
||||
CAddCommon::CAddCommon():
|
||||
_isLzmaEos(false),
|
||||
_buf(NULL)
|
||||
{}
|
||||
|
||||
void CAddCommon::SetOptions(const CCompressionMethodMode &options)
|
||||
{
|
||||
_options = options;
|
||||
}
|
||||
|
||||
CAddCommon::~CAddCommon()
|
||||
{
|
||||
MidFree(_buf);
|
||||
}
|
||||
|
||||
static const UInt32 kBufSize = ((UInt32)1 << 16);
|
||||
|
||||
HRESULT CAddCommon::CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC)
|
||||
{
|
||||
if (!_buf)
|
||||
{
|
||||
_buf = (Byte *)MidAlloc(kBufSize);
|
||||
if (!_buf)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
UInt32 crc = CRC_INIT_VAL;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 processed;
|
||||
RINOK(inStream->Read(_buf, kBufSize, &processed))
|
||||
if (processed == 0)
|
||||
{
|
||||
resultCRC = CRC_GET_DIGEST(crc);
|
||||
return S_OK;
|
||||
}
|
||||
crc = CrcUpdate(crc, _buf, (size_t)processed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT CAddCommon::Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, 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;
|
||||
|
||||
const Byte method = _options.MethodSequence[0];
|
||||
|
||||
if (method == NCompressionMethod::kStore && !_options.Password_Defined)
|
||||
opRes.PackSize = unpackSize;
|
||||
|
||||
opRes.CRC = 0;
|
||||
|
||||
opRes.LzmaEos = false;
|
||||
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
|
||||
opRes.DescriptorMode = outSeqMode;
|
||||
|
||||
if (_options.Password_Defined)
|
||||
{
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_ZipCrypto;
|
||||
if (_options.IsAesMode)
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes;
|
||||
else
|
||||
{
|
||||
if (inSeqMode)
|
||||
opRes.DescriptorMode = 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;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
if (opRes.ExtractVersion < ver)
|
||||
opRes.ExtractVersion = ver;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CAddCommon::Compress(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
ISequentialInStream *inStream, IOutStream *outStream,
|
||||
bool inSeqMode, bool outSeqMode,
|
||||
UInt32 fileTime,
|
||||
UInt64 expectedDataSize, bool expectedDataSize_IsConfirmed,
|
||||
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;
|
||||
}
|
||||
|
||||
CMyComPtr2_Create<ISequentialInStream, CSequentialInStreamWithCRC> inCrcStream;
|
||||
|
||||
CMyComPtr<IInStream> inStream2;
|
||||
if (!inSeqMode)
|
||||
{
|
||||
inStream->QueryInterface(IID_IInStream, (void **)&inStream2);
|
||||
if (!inStream2)
|
||||
{
|
||||
// inSeqMode = true;
|
||||
// inSeqMode must be correct before
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
inCrcStream->SetStream(inStream);
|
||||
inCrcStream->SetFullSize(expectedDataSize_IsConfirmed ? expectedDataSize : (UInt64)(Int64)-1);
|
||||
// inCrcStream->Init();
|
||||
|
||||
unsigned numTestMethods = _options.MethodSequence.Size();
|
||||
// numTestMethods != 0
|
||||
|
||||
bool descriptorMode = outSeqMode;
|
||||
|
||||
// ZipCrypto without descriptor requires additional reading pass for
|
||||
// inStream to calculate CRC for password check field.
|
||||
// The descriptor allows to use ZipCrypto check field without CRC (InfoZip's modification).
|
||||
|
||||
if (!outSeqMode)
|
||||
if (inSeqMode && _options.Password_Defined && !_options.IsAesMode)
|
||||
descriptorMode = true;
|
||||
opRes.DescriptorMode = descriptorMode;
|
||||
|
||||
if (numTestMethods > 1)
|
||||
if (inSeqMode || outSeqMode || !inStream2)
|
||||
numTestMethods = 1;
|
||||
|
||||
UInt32 crc = 0;
|
||||
bool crc_IsCalculated = false;
|
||||
|
||||
CFilterCoder::C_OutStream_Releaser outStreamReleaser;
|
||||
// opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
|
||||
|
||||
for (unsigned i = 0; i < numTestMethods; i++)
|
||||
{
|
||||
inCrcStream->Init();
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
// if (inStream2)
|
||||
{
|
||||
RINOK(InStream_SeekToBegin(inStream2))
|
||||
}
|
||||
RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL))
|
||||
RINOK(outStream->SetSize(0))
|
||||
}
|
||||
|
||||
opRes.LzmaEos = false;
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
|
||||
|
||||
const Byte method = _options.MethodSequence[i];
|
||||
if (method == NCompressionMethod::kStore && descriptorMode)
|
||||
{
|
||||
// we still can create descriptor_mode archives with "Store" method, but they are not good for 100%
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
bool needCode = true;
|
||||
|
||||
if (_options.Password_Defined)
|
||||
{
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_ZipCrypto;
|
||||
|
||||
if (!_cryptoStream.IsDefined())
|
||||
_cryptoStream.SetFromCls(new CFilterCoder(true));
|
||||
|
||||
if (_options.IsAesMode)
|
||||
{
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes;
|
||||
if (!_cryptoStream->Filter)
|
||||
{
|
||||
_cryptoStream->Filter = _filterAesSpec = new NCrypto::NWzAes::CEncoder;
|
||||
_filterAesSpec->SetKeyMode(_options.AesKeyMode);
|
||||
RINOK(_filterAesSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len()))
|
||||
}
|
||||
RINOK(_filterAesSpec->WriteHeader(outStream))
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_cryptoStream->Filter)
|
||||
{
|
||||
_cryptoStream->Filter = _filterSpec = new NCrypto::NZip::CEncoder;
|
||||
_filterSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len());
|
||||
}
|
||||
|
||||
UInt32 check;
|
||||
|
||||
if (descriptorMode)
|
||||
{
|
||||
// it's Info-ZIP modification for stream_mode descriptor_mode (bit 3 of the general purpose bit flag is set)
|
||||
check = (fileTime & 0xFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!crc_IsCalculated)
|
||||
{
|
||||
RINOK(CalcStreamCRC(inStream, crc))
|
||||
crc_IsCalculated = true;
|
||||
RINOK(InStream_SeekToBegin(inStream2))
|
||||
inCrcStream->Init();
|
||||
}
|
||||
check = (crc >> 16);
|
||||
}
|
||||
|
||||
RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check))
|
||||
}
|
||||
|
||||
if (method == NCompressionMethod::kStore)
|
||||
{
|
||||
needCode = false;
|
||||
RINOK(_cryptoStream->Code(inCrcStream, outStream, NULL, NULL, progress))
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(_cryptoStream->SetOutStream(outStream))
|
||||
RINOK(_cryptoStream->InitEncoder())
|
||||
outStreamReleaser.FilterCoder = _cryptoStream.ClsPtr();
|
||||
}
|
||||
}
|
||||
|
||||
if (needCode)
|
||||
{
|
||||
switch (method)
|
||||
{
|
||||
case NCompressionMethod::kStore:
|
||||
{
|
||||
_copyCoder.Create_if_Empty();
|
||||
CMyComPtr<ISequentialOutStream> outStreamNew;
|
||||
if (_options.Password_Defined)
|
||||
outStreamNew = _cryptoStream;
|
||||
else
|
||||
outStreamNew = outStream;
|
||||
RINOK(_copyCoder.Interface()->Code(inCrcStream, outStreamNew, NULL, NULL, progress))
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if (!_compressEncoder)
|
||||
{
|
||||
CLzmaEncoder *_lzmaEncoder = NULL;
|
||||
if (method == NCompressionMethod::kLZMA)
|
||||
{
|
||||
_compressExtractVersion = NCompressionMethod::kExtractVersion_LZMA;
|
||||
_lzmaEncoder = new CLzmaEncoder();
|
||||
_compressEncoder = _lzmaEncoder;
|
||||
}
|
||||
else if (method == NCompressionMethod::kXz)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
else
|
||||
{
|
||||
CMethodId methodId;
|
||||
switch (method)
|
||||
{
|
||||
case NCompressionMethod::kBZip2:
|
||||
methodId = kMethodId_BZip2;
|
||||
_compressExtractVersion = NCompressionMethod::kExtractVersion_BZip2;
|
||||
break;
|
||||
default:
|
||||
_compressExtractVersion = ((method == NCompressionMethod::kDeflate64) ?
|
||||
NCompressionMethod::kExtractVersion_Deflate64 :
|
||||
NCompressionMethod::kExtractVersion_Deflate);
|
||||
methodId = kMethodId_ZipBase + method;
|
||||
break;
|
||||
}
|
||||
RINOK(CreateCoder_Id(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
methodId, true, _compressEncoder))
|
||||
if (!_compressEncoder)
|
||||
return E_NOTIMPL;
|
||||
|
||||
if (method == NCompressionMethod::kDeflate ||
|
||||
method == NCompressionMethod::kDeflate64)
|
||||
{
|
||||
}
|
||||
else if (method == NCompressionMethod::kBZip2)
|
||||
{
|
||||
}
|
||||
}
|
||||
{
|
||||
CMyComPtr<ICompressSetCoderProperties> setCoderProps;
|
||||
_compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProps);
|
||||
if (setCoderProps)
|
||||
{
|
||||
if (!_options._methods.IsEmpty())
|
||||
{
|
||||
COneMethodInfo *oneMethodMain = &_options._methods[0];
|
||||
|
||||
RINOK(oneMethodMain->SetCoderProps(setCoderProps,
|
||||
_options.DataSizeReduce_Defined ? &_options.DataSizeReduce : NULL))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (method == NCompressionMethod::kLZMA)
|
||||
_isLzmaEos = _lzmaEncoder->Encoder->IsWriteEndMark();
|
||||
}
|
||||
|
||||
if (method == NCompressionMethod::kLZMA)
|
||||
opRes.LzmaEos = _isLzmaEos;
|
||||
|
||||
CMyComPtr<ISequentialOutStream> outStreamNew;
|
||||
if (_options.Password_Defined)
|
||||
outStreamNew = _cryptoStream;
|
||||
else
|
||||
outStreamNew = outStream;
|
||||
if (_compressExtractVersion > opRes.ExtractVersion)
|
||||
opRes.ExtractVersion = _compressExtractVersion;
|
||||
|
||||
{
|
||||
CMyComPtr<ICompressSetCoderPropertiesOpt> optProps;
|
||||
_compressEncoder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps);
|
||||
if (optProps)
|
||||
{
|
||||
const PROPID propID = NCoderPropID::kExpectedDataSize;
|
||||
NWindows::NCOM::CPropVariant prop = (UInt64)expectedDataSize;
|
||||
RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1))
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress))
|
||||
} catch (...) { return E_FAIL; }
|
||||
break;
|
||||
}
|
||||
} // switch end
|
||||
|
||||
if (_options.Password_Defined)
|
||||
{
|
||||
RINOK(_cryptoStream->OutStreamFinish())
|
||||
}
|
||||
}
|
||||
|
||||
if (_options.Password_Defined)
|
||||
{
|
||||
if (_options.IsAesMode)
|
||||
{
|
||||
RINOK(_filterAesSpec->WriteFooter(outStream))
|
||||
}
|
||||
}
|
||||
|
||||
RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize))
|
||||
|
||||
{
|
||||
opRes.CRC = inCrcStream->GetCRC();
|
||||
opRes.UnpackSize = inCrcStream->GetSize();
|
||||
opRes.Method = method;
|
||||
}
|
||||
|
||||
if (!inCrcStream->WasFinished())
|
||||
return E_FAIL;
|
||||
|
||||
if (_options.Password_Defined)
|
||||
{
|
||||
if (opRes.PackSize < opRes.UnpackSize +
|
||||
(_options.IsAesMode ? _filterAesSpec->GetAddPackSize() : NCrypto::NZip::kHeaderSize))
|
||||
break;
|
||||
}
|
||||
else if (opRes.PackSize < opRes.UnpackSize)
|
||||
break;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,76 @@
|
||||
// ZipAddCommon.h
|
||||
|
||||
#ifndef ZIP7_INC_ZIP_ADD_COMMON_H
|
||||
#define ZIP7_INC_ZIP_ADD_COMMON_H
|
||||
|
||||
#include "../../ICoder.h"
|
||||
#include "../../IProgress.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
#include "../../Common/FilterCoder.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
|
||||
#include "../../Crypto/ZipCrypto.h"
|
||||
#include "../../Crypto/WzAes.h"
|
||||
|
||||
#include "ZipCompressionMode.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
struct CCompressingResult
|
||||
{
|
||||
UInt64 UnpackSize;
|
||||
UInt64 PackSize;
|
||||
UInt32 CRC;
|
||||
UInt16 Method;
|
||||
Byte ExtractVersion;
|
||||
bool DescriptorMode;
|
||||
bool LzmaEos;
|
||||
|
||||
CCompressingResult()
|
||||
{
|
||||
// for GCC:
|
||||
UnpackSize = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class CAddCommon MY_UNCOPYABLE
|
||||
{
|
||||
CCompressionMethodMode _options;
|
||||
CMyComPtr2<ICompressCoder, NCompress::CCopyCoder> _copyCoder;
|
||||
|
||||
CMyComPtr<ICompressCoder> _compressEncoder;
|
||||
Byte _compressExtractVersion;
|
||||
bool _isLzmaEos;
|
||||
|
||||
CMyComPtr2<ISequentialOutStream, CFilterCoder> _cryptoStream;
|
||||
|
||||
NCrypto::NZip::CEncoder *_filterSpec;
|
||||
NCrypto::NWzAes::CEncoder *_filterAesSpec;
|
||||
|
||||
Byte *_buf;
|
||||
|
||||
HRESULT CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC);
|
||||
public:
|
||||
// CAddCommon(const CCompressionMethodMode &options);
|
||||
CAddCommon();
|
||||
void SetOptions(const CCompressionMethodMode &options);
|
||||
~CAddCommon();
|
||||
|
||||
HRESULT Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, UInt64 unpackSize,
|
||||
CCompressingResult &opRes) const;
|
||||
|
||||
HRESULT Compress(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
ISequentialInStream *inStream, IOutStream *outStream,
|
||||
bool inSeqMode, bool outSeqMode,
|
||||
UInt32 fileTime,
|
||||
UInt64 expectedDataSize, bool expectedDataSize_IsConfirmed,
|
||||
ICompressProgressInfo *progress, CCompressingResult &opRes);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
// CompressionMode.h
|
||||
|
||||
#ifndef ZIP7_INC_ZIP_COMPRESSION_MODE_H
|
||||
#define ZIP7_INC_ZIP_COMPRESSION_MODE_H
|
||||
|
||||
#include "../../../Common/MyString.h"
|
||||
|
||||
#ifndef Z7_ST
|
||||
#include "../../../Windows/System.h"
|
||||
#endif
|
||||
|
||||
#include "../Common/HandlerOut.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
const CMethodId kMethodId_ZipBase = 0x040100;
|
||||
const CMethodId kMethodId_BZip2 = 0x040202;
|
||||
|
||||
struct CBaseProps: public CMultiMethodProps
|
||||
{
|
||||
bool IsAesMode;
|
||||
Byte AesKeyMode;
|
||||
|
||||
void Init()
|
||||
{
|
||||
CMultiMethodProps::Init();
|
||||
|
||||
IsAesMode = false;
|
||||
AesKeyMode = 3;
|
||||
}
|
||||
};
|
||||
|
||||
struct CCompressionMethodMode: public CBaseProps
|
||||
{
|
||||
CRecordVector<Byte> MethodSequence;
|
||||
AString Password; // _Wipe
|
||||
bool Password_Defined;
|
||||
bool Force_SeqOutMode;
|
||||
bool DataSizeReduce_Defined;
|
||||
UInt64 DataSizeReduce;
|
||||
|
||||
bool IsRealAesMode() const { return Password_Defined && IsAesMode; }
|
||||
|
||||
CCompressionMethodMode()
|
||||
{
|
||||
Password_Defined = false;
|
||||
Force_SeqOutMode = false;
|
||||
DataSizeReduce_Defined = false;
|
||||
DataSizeReduce = 0;
|
||||
}
|
||||
|
||||
#ifdef Z7_CPP_IS_SUPPORTED_default
|
||||
CCompressionMethodMode(const CCompressionMethodMode &) = default;
|
||||
CCompressionMethodMode& operator =(const CCompressionMethodMode &) = default;
|
||||
#endif
|
||||
~CCompressionMethodMode() { Password.Wipe_and_Empty(); }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,94 @@
|
||||
// Zip/Handler.h
|
||||
|
||||
#ifndef ZIP7_INC_ZIP_HANDLER_H
|
||||
#define ZIP7_INC_ZIP_HANDLER_H
|
||||
|
||||
#include "../../../Common/DynamicBuffer.h"
|
||||
#include "../../ICoder.h"
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
|
||||
#include "ZipCompressionMode.h"
|
||||
#include "ZipIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
const unsigned kNumMethodNames1 = NFileHeader::NCompressionMethod::kZstdPk + 1;
|
||||
const unsigned kMethodNames2Start = NFileHeader::NCompressionMethod::kZstdWz;
|
||||
const unsigned kNumMethodNames2 = NFileHeader::NCompressionMethod::kWzAES + 1 - kMethodNames2Start;
|
||||
|
||||
extern const char * const kMethodNames1[kNumMethodNames1];
|
||||
extern const char * const kMethodNames2[kNumMethodNames2];
|
||||
|
||||
|
||||
class CHandler Z7_final:
|
||||
public IInArchive,
|
||||
// public IArchiveGetRawProps,
|
||||
public IOutArchive,
|
||||
public ISetProperties,
|
||||
Z7_PUBLIC_ISetCompressCodecsInfo_IFEC
|
||||
public CMyUnknownImp
|
||||
{
|
||||
Z7_COM_QI_BEGIN2(IInArchive)
|
||||
// Z7_COM_QI_ENTRY(IArchiveGetRawProps)
|
||||
Z7_COM_QI_ENTRY(IOutArchive)
|
||||
Z7_COM_QI_ENTRY(ISetProperties)
|
||||
Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC
|
||||
Z7_COM_QI_END
|
||||
Z7_COM_ADDREF_RELEASE
|
||||
|
||||
Z7_IFACE_COM7_IMP(IInArchive)
|
||||
// Z7_IFACE_COM7_IMP(IArchiveGetRawProps)
|
||||
Z7_IFACE_COM7_IMP(IOutArchive)
|
||||
Z7_IFACE_COM7_IMP(ISetProperties)
|
||||
DECL_ISetCompressCodecsInfo
|
||||
|
||||
private:
|
||||
CObjectVector<CItemEx> m_Items;
|
||||
CInArchive m_Archive;
|
||||
|
||||
CBaseProps _props;
|
||||
CHandlerTimeOptions TimeOptions;
|
||||
|
||||
int m_MainMethod;
|
||||
bool m_ForceAesMode;
|
||||
|
||||
bool _removeSfxBlock;
|
||||
bool m_ForceLocal;
|
||||
bool m_ForceUtf8;
|
||||
bool _force_SeqOutMode; // for creation
|
||||
bool _force_OpenSeq;
|
||||
bool _forceCodePage;
|
||||
UInt32 _specifiedCodePage;
|
||||
|
||||
DECL_EXTERNAL_CODECS_VARS
|
||||
|
||||
void InitMethodProps()
|
||||
{
|
||||
_props.Init();
|
||||
TimeOptions.Init();
|
||||
TimeOptions.Prec = k_PropVar_TimePrec_0;
|
||||
m_MainMethod = -1;
|
||||
m_ForceAesMode = false;
|
||||
_removeSfxBlock = false;
|
||||
m_ForceLocal = false;
|
||||
m_ForceUtf8 = false;
|
||||
_force_SeqOutMode = false;
|
||||
_force_OpenSeq = false;
|
||||
_forceCodePage = false;
|
||||
_specifiedCodePage = CP_OEMCP;
|
||||
}
|
||||
|
||||
// void MarkAltStreams(CObjectVector<CItemEx> &items);
|
||||
|
||||
HRESULT GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value);
|
||||
|
||||
public:
|
||||
CHandler();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,626 @@
|
||||
// ZipHandlerOut.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../Common/ComTry.h"
|
||||
#include "../../../Common/StringConvert.h"
|
||||
#include "../../../Common/StringToInt.h"
|
||||
|
||||
#include "../../../Windows/PropVariant.h"
|
||||
#include "../../../Windows/TimeUtils.h"
|
||||
|
||||
#include "../../IPassword.h"
|
||||
|
||||
#include "../../Common/OutBuffer.h"
|
||||
|
||||
#include "../../Crypto/WzAes.h"
|
||||
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
#include "../Common/ParseProperties.h"
|
||||
|
||||
#include "ZipHandler.h"
|
||||
#include "ZipUpdate.h"
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NCOM;
|
||||
using namespace NTime;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType))
|
||||
{
|
||||
*timeType = TimeOptions.Prec;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static bool IsSimpleAsciiString(const wchar_t *s)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
wchar_t c = *s++;
|
||||
if (c == 0)
|
||||
return true;
|
||||
if (c < 0x20 || c > 0x7F)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 (int)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 (int)kMethodNames2Start + k;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#define COM_TRY_BEGIN2 try {
|
||||
#define COM_TRY_END2 } \
|
||||
catch(const CSystemException &e) { return e.ErrorCode; } \
|
||||
catch(...) { return E_OUTOFMEMORY; }
|
||||
|
||||
static HRESULT GetTime(IArchiveUpdateCallback *callback, unsigned index, PROPID propID, FILETIME &filetime)
|
||||
{
|
||||
filetime.dwHighDateTime = filetime.dwLowDateTime = 0;
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(callback->GetProperty(index, propID, &prop))
|
||||
if (prop.vt == VT_FILETIME)
|
||||
filetime = prop.filetime;
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
||||
IArchiveUpdateCallback *callback))
|
||||
{
|
||||
COM_TRY_BEGIN2
|
||||
|
||||
if (m_Archive.IsOpen())
|
||||
{
|
||||
if (!m_Archive.CanUpdate())
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
CObjectVector<CUpdateItem> updateItems;
|
||||
updateItems.ClearAndReserve(numItems);
|
||||
|
||||
bool thereAreAesUpdates = false;
|
||||
UInt64 largestSize = 0;
|
||||
bool largestSizeDefined = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
const UINT oemCP = GetOEMCP();
|
||||
#endif
|
||||
|
||||
UString name;
|
||||
CUpdateItem ui;
|
||||
|
||||
for (UInt32 i = 0; i < numItems; i++)
|
||||
{
|
||||
Int32 newData;
|
||||
Int32 newProps;
|
||||
UInt32 indexInArc;
|
||||
|
||||
if (!callback)
|
||||
return E_FAIL;
|
||||
|
||||
RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc))
|
||||
|
||||
name.Empty();
|
||||
ui.Clear();
|
||||
|
||||
ui.NewProps = IntToBool(newProps);
|
||||
ui.NewData = IntToBool(newData);
|
||||
ui.IndexInArc = (int)indexInArc;
|
||||
ui.IndexInClient = i;
|
||||
|
||||
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();
|
||||
// ui.IsAltStream = inputItem.IsAltStream();
|
||||
}
|
||||
|
||||
if (IntToBool(newProps))
|
||||
{
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(callback->GetProperty(i, kpidAttrib, &prop))
|
||||
if (prop.vt == VT_EMPTY)
|
||||
ui.Attrib = 0;
|
||||
else if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
else
|
||||
ui.Attrib = prop.ulVal;
|
||||
}
|
||||
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(callback->GetProperty(i, kpidPath, &prop))
|
||||
if (prop.vt == VT_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))
|
||||
if (prop.vt == VT_EMPTY)
|
||||
ui.IsDir = false;
|
||||
else if (prop.vt != VT_BOOL)
|
||||
return E_INVALIDARG;
|
||||
else
|
||||
ui.IsDir = (prop.boolVal != VARIANT_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
bool isAltStream = false;
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(callback->GetProperty(i, kpidIsAltStream, &prop));
|
||||
if (prop.vt == VT_BOOL)
|
||||
isAltStream = (prop.boolVal != VARIANT_FALSE);
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (isAltStream)
|
||||
{
|
||||
if (ui.IsDir)
|
||||
return E_INVALIDARG;
|
||||
int delim = name.ReverseFind(L':');
|
||||
if (delim >= 0)
|
||||
{
|
||||
name.Delete(delim, 1);
|
||||
name.Insert(delim, UString(k_SpecName_NTFS_STREAM));
|
||||
ui.IsAltStream = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// 22.00 : kpidTimeType is useless here : the code was disabled
|
||||
/*
|
||||
{
|
||||
CPropVariant prop;
|
||||
RINOK(callback->GetProperty(i, kpidTimeType, &prop));
|
||||
if (prop.vt == VT_UI4)
|
||||
ui.NtfsTime_IsDefined = (prop.ulVal == NFileTimeType::kWindows);
|
||||
else
|
||||
ui.NtfsTime_IsDefined = _Write_NtfsTime;
|
||||
}
|
||||
*/
|
||||
|
||||
if (TimeOptions.Write_MTime.Val) RINOK (GetTime (callback, i, kpidMTime, ui.Ntfs_MTime))
|
||||
if (TimeOptions.Write_ATime.Val) RINOK (GetTime (callback, i, kpidATime, ui.Ntfs_ATime))
|
||||
if (TimeOptions.Write_CTime.Val) RINOK (GetTime (callback, i, kpidCTime, ui.Ntfs_CTime))
|
||||
|
||||
if (TimeOptions.Prec != k_PropVar_TimePrec_DOS)
|
||||
{
|
||||
if (TimeOptions.Prec == k_PropVar_TimePrec_Unix ||
|
||||
TimeOptions.Prec == k_PropVar_TimePrec_Base)
|
||||
ui.Write_UnixTime = ! FILETIME_IsZero (ui.Ntfs_MTime);
|
||||
else
|
||||
{
|
||||
/*
|
||||
// if we want to store zero timestamps as zero timestamp, use the following:
|
||||
ui.Write_NtfsTime =
|
||||
_Write_MTime ||
|
||||
_Write_ATime ||
|
||||
_Write_CTime;
|
||||
*/
|
||||
|
||||
// We treat zero timestamp as no timestamp
|
||||
ui.Write_NtfsTime =
|
||||
! FILETIME_IsZero (ui.Ntfs_MTime) ||
|
||||
! FILETIME_IsZero (ui.Ntfs_ATime) ||
|
||||
! FILETIME_IsZero (ui.Ntfs_CTime);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
how 0 in dos time works:
|
||||
win10 explorer extract : some random date 1601-04-25.
|
||||
winrar 6.10 : write time.
|
||||
7zip : MTime of archive is used
|
||||
how 0 in tar works:
|
||||
winrar 6.10 : 1970
|
||||
0 in dos field can show that there is no timestamp.
|
||||
we write correct 1970-01-01 in dos field, to support correct extraction in Win10.
|
||||
*/
|
||||
|
||||
UtcFileTime_To_LocalDosTime(ui.Ntfs_MTime, ui.Time);
|
||||
|
||||
NItemName::ReplaceSlashes_OsToUnix(name);
|
||||
|
||||
bool needSlash = ui.IsDir;
|
||||
const wchar_t kSlash = L'/';
|
||||
if (!name.IsEmpty())
|
||||
{
|
||||
if (name.Back() == kSlash)
|
||||
{
|
||||
if (!ui.IsDir)
|
||||
return E_INVALIDARG;
|
||||
needSlash = false;
|
||||
}
|
||||
}
|
||||
if (needSlash)
|
||||
name += kSlash;
|
||||
|
||||
const UINT codePage = _forceCodePage ? _specifiedCodePage : CP_OEMCP;
|
||||
bool tryUtf8 = true;
|
||||
|
||||
/*
|
||||
Windows 10 allows users to set UTF-8 in Region Settings via option:
|
||||
"Beta: Use Unicode UTF-8 for worldwide language support"
|
||||
In that case Windows uses CP_UTF8 when we use CP_OEMCP.
|
||||
21.02 fixed:
|
||||
we set UTF-8 mark for non-latin files for such UTF-8 mode in Windows.
|
||||
we write additional Info-Zip Utf-8 FileName Extra for non-latin names/
|
||||
*/
|
||||
|
||||
if ((codePage != CP_UTF8) &&
|
||||
#ifdef _WIN32
|
||||
(m_ForceLocal || !m_ForceUtf8) && (oemCP != CP_UTF8)
|
||||
#else
|
||||
(m_ForceLocal && !m_ForceUtf8)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
bool defaultCharWasUsed;
|
||||
ui.Name = UnicodeStringToMultiByte(name, codePage, '_', defaultCharWasUsed);
|
||||
tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed ||
|
||||
MultiByteToUnicodeString(ui.Name, codePage) != name));
|
||||
}
|
||||
|
||||
const bool isNonLatin = !name.IsAscii();
|
||||
|
||||
if (tryUtf8)
|
||||
{
|
||||
ui.IsUtf8 = isNonLatin;
|
||||
ConvertUnicodeToUTF8(name, ui.Name);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (ui.IsUtf8 && !CheckUTF8_AString(ui.Name))
|
||||
{
|
||||
// if it's non-Windows and there are non-UTF8 characters we clear UTF8-flag
|
||||
ui.IsUtf8 = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (isNonLatin)
|
||||
Convert_Unicode_To_UTF8_Buf(name, ui.Name_Utf);
|
||||
|
||||
if (ui.Name.Len() >= (1 << 16)
|
||||
|| ui.Name_Utf.Size() >= (1 << 16) - 128)
|
||||
return E_INVALIDARG;
|
||||
|
||||
{
|
||||
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[indexInArc];
|
||||
// ui.Commented = itemInfo.IsCommented();
|
||||
ui.Commented = false;
|
||||
if (ui.Commented)
|
||||
{
|
||||
ui.CommentRange.Position = itemInfo.GetCommentPosition();
|
||||
ui.CommentRange.Size = itemInfo.CommentSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
ui.Commented = false;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
if (IntToBool(newData))
|
||||
{
|
||||
UInt64 size = 0;
|
||||
if (!ui.IsDir)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(callback->GetProperty(i, kpidSize, &prop))
|
||||
if (prop.vt != VT_UI8)
|
||||
return E_INVALIDARG;
|
||||
size = prop.uhVal.QuadPart;
|
||||
if (largestSize < size)
|
||||
largestSize = size;
|
||||
largestSizeDefined = true;
|
||||
}
|
||||
ui.Size = size;
|
||||
}
|
||||
|
||||
updateItems.Add(ui);
|
||||
}
|
||||
|
||||
|
||||
CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
|
||||
{
|
||||
CMyComPtr<IArchiveUpdateCallback> udateCallBack2(callback);
|
||||
udateCallBack2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword);
|
||||
}
|
||||
CCompressionMethodMode options;
|
||||
(CBaseProps &)options = _props;
|
||||
options.DataSizeReduce = largestSize;
|
||||
options.DataSizeReduce_Defined = largestSizeDefined;
|
||||
|
||||
options.Password_Defined = false;
|
||||
options.Password.Wipe_and_Empty();
|
||||
if (getTextPassword)
|
||||
{
|
||||
CMyComBSTR_Wipe password;
|
||||
Int32 passwordIsDefined;
|
||||
RINOK(getTextPassword->CryptoGetTextPassword2(&passwordIsDefined, &password))
|
||||
options.Password_Defined = IntToBool(passwordIsDefined);
|
||||
if (options.Password_Defined)
|
||||
{
|
||||
if (!m_ForceAesMode)
|
||||
options.IsAesMode = thereAreAesUpdates;
|
||||
|
||||
if (!IsSimpleAsciiString(password))
|
||||
return E_INVALIDARG;
|
||||
if (password)
|
||||
UnicodeStringToMultiByte2(options.Password, (LPCOLESTR)password, CP_OEMCP);
|
||||
if (options.IsAesMode)
|
||||
{
|
||||
if (options.Password.Len() > NCrypto::NWzAes::kPasswordSizeMax)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
bool isFilter;
|
||||
if (FindMethod_Index(EXTERNAL_CODECS_VARS methodName, true,
|
||||
methodId, numStreams, isFilter) < 0)
|
||||
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)mainMethod;
|
||||
|
||||
options.MethodSequence.Add((Byte)mainMethod);
|
||||
|
||||
if (mainMethod != NFileHeader::NCompressionMethod::kStore)
|
||||
options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStore);
|
||||
|
||||
options.Force_SeqOutMode = _force_SeqOutMode;
|
||||
|
||||
CUpdateOptions uo;
|
||||
uo.Write_MTime = TimeOptions.Write_MTime.Val;
|
||||
uo.Write_ATime = TimeOptions.Write_ATime.Val;
|
||||
uo.Write_CTime = TimeOptions.Write_CTime.Val;
|
||||
/*
|
||||
uo.Write_NtfsTime = _Write_NtfsTime &&
|
||||
(_Write_MTime || _Write_ATime || _Write_CTime);
|
||||
uo.Write_UnixTime = _Write_UnixTime;
|
||||
*/
|
||||
|
||||
return Update(
|
||||
EXTERNAL_CODECS_VARS
|
||||
m_Items, updateItems, outStream,
|
||||
m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock,
|
||||
uo, options, callback);
|
||||
|
||||
COM_TRY_END2
|
||||
}
|
||||
|
||||
|
||||
|
||||
Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
|
||||
{
|
||||
InitMethodProps();
|
||||
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
UString name = names[i];
|
||||
name.MakeLower_Ascii();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
|
||||
const PROPVARIANT &prop = values[i];
|
||||
|
||||
if (name.IsEqualTo_Ascii_NoCase("em"))
|
||||
{
|
||||
if (prop.vt != VT_BSTR)
|
||||
return E_INVALIDARG;
|
||||
{
|
||||
const wchar_t *m = prop.bstrVal;
|
||||
if (IsString1PrefixedByString2_NoCase_Ascii(m, "AES"))
|
||||
{
|
||||
m += 3;
|
||||
UInt32 v = 3;
|
||||
if (*m != 0)
|
||||
{
|
||||
if (*m == '-')
|
||||
m++;
|
||||
const wchar_t *end;
|
||||
v = ConvertStringToUInt32(m, &end);
|
||||
if (*end != 0 || v % 64 != 0)
|
||||
return E_INVALIDARG;
|
||||
v /= 64;
|
||||
v -= 2;
|
||||
if (v >= 3)
|
||||
return E_INVALIDARG;
|
||||
v++;
|
||||
}
|
||||
_props.AesKeyMode = (Byte)v;
|
||||
_props.IsAesMode = true;
|
||||
m_ForceAesMode = true;
|
||||
}
|
||||
else if (StringsAreEqualNoCase_Ascii(m, "ZipCrypto"))
|
||||
{
|
||||
_props.IsAesMode = false;
|
||||
m_ForceAesMode = true;
|
||||
}
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
else if (name.IsEqualTo("cl"))
|
||||
{
|
||||
RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal))
|
||||
if (m_ForceLocal)
|
||||
m_ForceUtf8 = false;
|
||||
}
|
||||
else if (name.IsEqualTo("cu"))
|
||||
{
|
||||
RINOK(PROPVARIANT_to_bool(prop, m_ForceUtf8))
|
||||
if (m_ForceUtf8)
|
||||
m_ForceLocal = false;
|
||||
}
|
||||
else if (name.IsEqualTo("cp"))
|
||||
{
|
||||
UInt32 cp = CP_OEMCP;
|
||||
RINOK(ParsePropToUInt32(L"", prop, cp))
|
||||
_forceCodePage = true;
|
||||
_specifiedCodePage = cp;
|
||||
}
|
||||
else if (name.IsEqualTo("rsfx"))
|
||||
{
|
||||
RINOK(PROPVARIANT_to_bool(prop, _removeSfxBlock))
|
||||
}
|
||||
else if (name.IsEqualTo("rws"))
|
||||
{
|
||||
RINOK(PROPVARIANT_to_bool(prop, _force_SeqOutMode))
|
||||
}
|
||||
else if (name.IsEqualTo("ros"))
|
||||
{
|
||||
RINOK(PROPVARIANT_to_bool(prop, _force_OpenSeq))
|
||||
}
|
||||
else
|
||||
{
|
||||
if (name.IsEqualTo_Ascii_NoCase("m") && prop.vt == VT_UI4)
|
||||
{
|
||||
UInt32 id = prop.ulVal;
|
||||
if (id > 0xFF)
|
||||
return E_INVALIDARG;
|
||||
m_MainMethod = (int)id;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool processed = false;
|
||||
RINOK(TimeOptions.Parse(name, prop, processed))
|
||||
if (!processed)
|
||||
{
|
||||
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 = (int)id;
|
||||
else if (methodName.IsEqualTo_Ascii_NoCase("Copy")) // it's alias for "Store"
|
||||
m_MainMethod = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,201 @@
|
||||
// ZipHeader.h
|
||||
|
||||
#ifndef ZIP7_INC_ARCHIVE_ZIP_HEADER_H
|
||||
#define ZIP7_INC_ARCHIVE_ZIP_HEADER_H
|
||||
|
||||
#include "../../../Common/MyTypes.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
const unsigned kMarkerSize = 4;
|
||||
|
||||
namespace NSignature
|
||||
{
|
||||
const UInt32 kLocalFileHeader = 0x04034B50;
|
||||
const UInt32 kDataDescriptor = 0x08074B50;
|
||||
const UInt32 kCentralFileHeader = 0x02014B50;
|
||||
const UInt32 kEcd = 0x06054B50;
|
||||
const UInt32 kEcd64 = 0x06064B50;
|
||||
const UInt32 kEcd64Locator = 0x07064B50;
|
||||
const UInt32 kSpan = 0x08074B50;
|
||||
const UInt32 kNoSpan = 0x30304B50; // PK00, replaces kSpan, if there is only 1 segment
|
||||
}
|
||||
|
||||
const unsigned kLocalHeaderSize = 4 + 26; // 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
|
||||
const unsigned kEcd64_MainSize = 44;
|
||||
const unsigned kEcd64_FullSize = 12 + kEcd64_MainSize;
|
||||
const unsigned kEcd64Locator_Size = 20;
|
||||
|
||||
namespace NFileHeader
|
||||
{
|
||||
namespace NCompressionMethod
|
||||
{
|
||||
enum EType
|
||||
{
|
||||
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,
|
||||
kZstdPk = 20,
|
||||
|
||||
kZstdWz = 93,
|
||||
kMP3 = 94,
|
||||
kXz = 95,
|
||||
kJpeg = 96,
|
||||
kWavPack = 97,
|
||||
kPPMd = 98,
|
||||
kWzAES = 99
|
||||
};
|
||||
|
||||
const Byte kMadeByProgramVersion = 63;
|
||||
|
||||
const Byte kExtractVersion_Default = 10;
|
||||
const Byte kExtractVersion_Dir = 20;
|
||||
const Byte kExtractVersion_ZipCrypto = 20;
|
||||
const Byte kExtractVersion_Deflate = 20;
|
||||
const Byte kExtractVersion_Deflate64 = 21;
|
||||
const Byte kExtractVersion_Zip64 = 45;
|
||||
const Byte kExtractVersion_BZip2 = 46;
|
||||
const Byte kExtractVersion_Aes = 51;
|
||||
const Byte kExtractVersion_LZMA = 63;
|
||||
const Byte kExtractVersion_PPMd = 63;
|
||||
const Byte kExtractVersion_Xz = 20; // test it
|
||||
}
|
||||
|
||||
namespace NExtraID
|
||||
{
|
||||
enum
|
||||
{
|
||||
kZip64 = 0x01,
|
||||
kNTFS = 0x0A,
|
||||
kUnix0 = 0x0D, // Info-ZIP : (UNIX) PK
|
||||
kStrongEncrypt = 0x17,
|
||||
kIzNtSecurityDescriptor = 0x4453,
|
||||
kUnixTime = 0x5455, // "UT" (time) Info-ZIP
|
||||
kUnix1 = 0x5855, // Info-ZIP
|
||||
kIzUnicodeComment = 0x6375,
|
||||
kIzUnicodeName = 0x7075,
|
||||
kUnix2 = 0x7855, // Info-ZIP
|
||||
kUnixN = 0x7875, // Info-ZIP
|
||||
kWzAES = 0x9901,
|
||||
kApkAlign = 0xD935
|
||||
};
|
||||
}
|
||||
|
||||
namespace NNtfsExtra
|
||||
{
|
||||
const UInt16 kTagTime = 1;
|
||||
enum
|
||||
{
|
||||
kMTime = 0,
|
||||
kATime,
|
||||
kCTime
|
||||
};
|
||||
}
|
||||
|
||||
namespace NUnixTime
|
||||
{
|
||||
enum
|
||||
{
|
||||
kMTime = 0,
|
||||
kATime,
|
||||
kCTime
|
||||
};
|
||||
}
|
||||
|
||||
namespace NUnixExtra
|
||||
{
|
||||
enum
|
||||
{
|
||||
kATime = 0,
|
||||
kMTime
|
||||
};
|
||||
}
|
||||
|
||||
namespace NFlags
|
||||
{
|
||||
const unsigned kEncrypted = 1 << 0;
|
||||
const unsigned kLzmaEOS = 1 << 1;
|
||||
const unsigned kDescriptorUsedMask = 1 << 3;
|
||||
const unsigned kStrongEncrypted = 1 << 6;
|
||||
const unsigned kUtf8 = 1 << 11;
|
||||
const unsigned kAltStream = 1 << 14;
|
||||
|
||||
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
|
||||
{
|
||||
enum EEnum
|
||||
{
|
||||
kFAT = 0,
|
||||
kAMIGA = 1,
|
||||
kVMS = 2, // VAX/VMS
|
||||
kUnix = 3,
|
||||
kVM_CMS = 4,
|
||||
kAtari = 5, // what if it's a minix filesystem? [cjh]
|
||||
kHPFS = 6, // filesystem used by OS/2 (and NT 3.x)
|
||||
kMac = 7,
|
||||
kZ_System = 8,
|
||||
kCPM = 9,
|
||||
kTOPS20 = 10, // pkzip 2.50 NTFS
|
||||
kNTFS = 11, // filesystem used by Windows NT
|
||||
kQDOS = 12, // SMS/QDOS
|
||||
kAcorn = 13, // Archimedes Acorn RISC OS
|
||||
kVFAT = 14, // filesystem used by Windows 95, NT
|
||||
kMVS = 15,
|
||||
kBeOS = 16, // hybrid POSIX/database filesystem
|
||||
kTandem = 17,
|
||||
kOS400 = 18,
|
||||
kOSX = 19
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
namespace NAmigaAttrib
|
||||
{
|
||||
const UInt32 kIFMT = 06000; // Amiga file type mask
|
||||
const UInt32 kIFDIR = 04000; // Amiga directory
|
||||
const UInt32 kIFREG = 02000; // Amiga regular file
|
||||
const UInt32 kIHIDDEN = 00200; // to be supported in AmigaDOS 3.x
|
||||
const UInt32 kISCRIPT = 00100; // executable script (text command file)
|
||||
const UInt32 kIPURE = 00040; // allow loading into resident memory
|
||||
const UInt32 kIARCHIVE = 00020; // not modified since bit was last set
|
||||
const UInt32 kIREAD = 00010; // can be opened for reading
|
||||
const UInt32 kIWRITE = 00004; // can be opened for writing
|
||||
const UInt32 kIEXECUTE = 00002; // executable image, a loadable runfile
|
||||
const UInt32 kIDELETE = 00001; // can be deleted
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,449 @@
|
||||
// Archive/ZipIn.h
|
||||
|
||||
#ifndef ZIP7_INC_ZIP_IN_H
|
||||
#define ZIP7_INC_ZIP_IN_H
|
||||
|
||||
#include "../../../Common/MyBuffer2.h"
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "ZipHeader.h"
|
||||
#include "ZipItem.h"
|
||||
|
||||
API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size);
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
class CItemEx: public CItem
|
||||
{
|
||||
public:
|
||||
UInt32 LocalFullHeaderSize; // including Name and Extra
|
||||
// int ParentOfAltStream; // -1, if not AltStream
|
||||
|
||||
bool DescriptorWasRead;
|
||||
|
||||
CItemEx():
|
||||
// ParentOfAltStream(-1),
|
||||
DescriptorWasRead(false) {}
|
||||
|
||||
UInt64 GetLocalFullSize() const
|
||||
{ return LocalFullHeaderSize + GetPackSizeWithDescriptor(); }
|
||||
UInt64 GetDataPosition() const
|
||||
{ return LocalHeaderPos + LocalFullHeaderSize; }
|
||||
|
||||
bool IsBadDescriptor() const
|
||||
{
|
||||
return !FromCentral && FromLocal && HasDescriptor() && !DescriptorWasRead;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CInArchiveInfo
|
||||
{
|
||||
Int64 Base; /* Base offset of start of archive in stream.
|
||||
Offsets in headers must be calculated from that Base.
|
||||
Base is equal to MarkerPos for normal ZIPs.
|
||||
Base can point to PE stub for some ZIP SFXs.
|
||||
if CentralDir was read,
|
||||
Base can be negative, if start of data is not available,
|
||||
if CentralDirs was not read,
|
||||
Base = ArcInfo.MarkerPos; */
|
||||
|
||||
/* The following *Pos variables contain absolute offsets in Stream */
|
||||
|
||||
UInt64 MarkerPos; /* Pos of first signature, it can point to kSpan/kNoSpan signature
|
||||
= MarkerPos2 in most archives
|
||||
= MarkerPos2 - 4 if there is kSpan/kNoSpan signature */
|
||||
UInt64 MarkerPos2; // Pos of first local item signature in stream
|
||||
UInt64 FinishPos; // Finish pos of archive data in starting volume
|
||||
UInt64 FileEndPos; // Finish pos of stream
|
||||
|
||||
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;
|
||||
|
||||
// UInt32 BaseVolIndex;
|
||||
|
||||
CByteBuffer Comment;
|
||||
|
||||
|
||||
CInArchiveInfo():
|
||||
Base(0),
|
||||
MarkerPos(0),
|
||||
MarkerPos2(0),
|
||||
FinishPos(0),
|
||||
FileEndPos(0),
|
||||
FirstItemRelatOffset(0),
|
||||
MarkerVolIndex(-1),
|
||||
CdWasRead(false),
|
||||
IsSpanMode(false),
|
||||
ThereIsTail(false)
|
||||
// BaseVolIndex(0)
|
||||
{}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
// BaseVolIndex = 0;
|
||||
Base = 0;
|
||||
MarkerPos = 0;
|
||||
MarkerPos2 = 0;
|
||||
FinishPos = 0;
|
||||
FileEndPos = 0;
|
||||
MarkerVolIndex = -1;
|
||||
ThereIsTail = false;
|
||||
|
||||
FirstItemRelatOffset = 0;
|
||||
|
||||
CdWasRead = false;
|
||||
IsSpanMode = false;
|
||||
|
||||
Comment.Free();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CCdInfo
|
||||
{
|
||||
bool IsFromEcd64;
|
||||
|
||||
UInt16 CommentSize;
|
||||
|
||||
// 64
|
||||
UInt16 VersionMade;
|
||||
UInt16 VersionNeedExtract;
|
||||
|
||||
// old zip
|
||||
UInt32 ThisDisk;
|
||||
UInt32 CdDisk;
|
||||
UInt64 NumEntries_in_ThisDisk;
|
||||
UInt64 NumEntries;
|
||||
UInt64 Size;
|
||||
UInt64 Offset;
|
||||
|
||||
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
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CVols
|
||||
{
|
||||
struct CSubStreamInfo
|
||||
{
|
||||
CMyComPtr<IInStream> Stream;
|
||||
UInt64 Size;
|
||||
|
||||
HRESULT SeekToStart() const { return InStream_SeekToBegin(Stream); }
|
||||
|
||||
CSubStreamInfo(): Size(0) {}
|
||||
};
|
||||
|
||||
CObjectVector<CSubStreamInfo> Streams;
|
||||
|
||||
int StreamIndex; // -1 for StartStream
|
||||
// -2 for ZipStream at multivol detection code
|
||||
// >=0 volume index in multivol
|
||||
|
||||
bool NeedSeek;
|
||||
|
||||
bool DisableVolsSearch;
|
||||
bool StartIsExe; // is .exe
|
||||
bool StartIsZ; // is .zip or .zNN
|
||||
bool StartIsZip; // is .zip
|
||||
bool IsUpperCase;
|
||||
bool MissingZip;
|
||||
|
||||
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;
|
||||
|
||||
int EndVolIndex; // index of last volume (ecd volume),
|
||||
// -1, if is not multivol
|
||||
|
||||
UString BaseName; // name of archive including '.'
|
||||
UString MissingName;
|
||||
|
||||
CMyComPtr<IInStream> ZipStream;
|
||||
|
||||
CCdInfo ecd;
|
||||
|
||||
UInt64 TotalBytesSize; // for MultiVol only
|
||||
|
||||
void ClearRefs()
|
||||
{
|
||||
Streams.Clear();
|
||||
ZipStream.Release();
|
||||
TotalBytesSize = 0;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
StreamIndex = -1;
|
||||
NeedSeek = false;
|
||||
|
||||
DisableVolsSearch = false;
|
||||
StartIsExe = false;
|
||||
StartIsZ = false;
|
||||
StartIsZip = false;
|
||||
IsUpperCase = false;
|
||||
|
||||
StartVolIndex = -1;
|
||||
StartParsingVol = 0;
|
||||
NumVols = 0;
|
||||
EndVolIndex = -1;
|
||||
|
||||
BaseName.Empty();
|
||||
MissingName.Empty();
|
||||
|
||||
MissingZip = false;
|
||||
ecd_wasRead = false;
|
||||
|
||||
ClearRefs();
|
||||
}
|
||||
|
||||
HRESULT ParseArcName(IArchiveOpenVolumeCallback *volCallback);
|
||||
|
||||
HRESULT Read(void *data, UInt32 size, UInt32 *processedSize);
|
||||
};
|
||||
|
||||
|
||||
Z7_CLASS_IMP_COM_1(
|
||||
CVolStream
|
||||
, ISequentialInStream
|
||||
)
|
||||
public:
|
||||
CVols *Vols;
|
||||
};
|
||||
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
CMidBuffer Buffer;
|
||||
size_t _bufPos;
|
||||
size_t _bufCached;
|
||||
|
||||
UInt64 _streamPos;
|
||||
UInt64 _cnt;
|
||||
|
||||
// UInt32 _startLocalFromCd_Disk;
|
||||
// UInt64 _startLocalFromCd_Offset;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
HRESULT AllocateBuffer(size_t size);
|
||||
|
||||
UInt64 GetVirtStreamPos() { return _streamPos - _bufCached + _bufPos; }
|
||||
|
||||
bool _inBufMode;
|
||||
|
||||
bool IsArcOpen;
|
||||
bool CanStartNewVol;
|
||||
|
||||
UInt32 _signature;
|
||||
|
||||
CMyComPtr<IInStream> StreamRef;
|
||||
IInStream *Stream;
|
||||
IInStream *StartStream;
|
||||
IArchiveOpenCallback *Callback;
|
||||
|
||||
HRESULT Seek_SavePos(UInt64 offset);
|
||||
HRESULT SeekToVol(int volIndex, UInt64 offset);
|
||||
|
||||
HRESULT ReadFromCache(Byte *data, unsigned size, unsigned &processed);
|
||||
HRESULT ReadFromCache_FALSE(Byte *data, unsigned size);
|
||||
|
||||
HRESULT ReadVols2(IArchiveOpenVolumeCallback *volCallback,
|
||||
unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsigned &numMissingVols);
|
||||
HRESULT ReadVols();
|
||||
|
||||
HRESULT FindMarker(const UInt64 *searchLimit);
|
||||
HRESULT IncreaseRealPosition(UInt64 addValue, bool &isFinished);
|
||||
|
||||
HRESULT LookAhead(size_t minRequiredInBuffer);
|
||||
void SafeRead(Byte *data, unsigned size);
|
||||
void ReadBuffer(CByteBuffer &buffer, unsigned size);
|
||||
// Byte ReadByte();
|
||||
// UInt16 ReadUInt16();
|
||||
UInt32 ReadUInt32();
|
||||
UInt64 ReadUInt64();
|
||||
|
||||
void ReadSignature();
|
||||
|
||||
void Skip(size_t num);
|
||||
HRESULT Skip64(UInt64 num, unsigned numFiles);
|
||||
|
||||
bool ReadFileName(unsigned nameSize, AString &dest);
|
||||
|
||||
bool ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlock &extra,
|
||||
UInt64 &unpackSize, UInt64 &packSize, CItem *cdItem);
|
||||
bool ReadLocalItem(CItemEx &item);
|
||||
HRESULT FindDescriptor(CItemEx &item, unsigned numFiles);
|
||||
HRESULT ReadCdItem(CItemEx &item);
|
||||
HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo);
|
||||
HRESULT FindCd(bool checkOffsetMode);
|
||||
HRESULT TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize);
|
||||
HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize);
|
||||
HRESULT ReadLocals(CObjectVector<CItemEx> &localItems);
|
||||
|
||||
HRESULT ReadHeaders(CObjectVector<CItemEx> &items);
|
||||
|
||||
HRESULT GetVolStream(unsigned vol, UInt64 pos, CMyComPtr<ISequentialInStream> &stream);
|
||||
|
||||
public:
|
||||
CInArchiveInfo ArcInfo;
|
||||
|
||||
bool IsArc;
|
||||
bool IsZip64;
|
||||
|
||||
bool IsApk;
|
||||
bool IsCdUnsorted;
|
||||
|
||||
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;
|
||||
UInt32 EcdVolIndex;
|
||||
|
||||
CVols Vols;
|
||||
|
||||
bool Force_ReadLocals_Mode;
|
||||
bool Disable_VolsRead;
|
||||
bool Disable_FindMarker;
|
||||
|
||||
CInArchive():
|
||||
IsArcOpen(false),
|
||||
Stream(NULL),
|
||||
StartStream(NULL),
|
||||
Callback(NULL),
|
||||
Force_ReadLocals_Mode(false),
|
||||
Disable_VolsRead(false),
|
||||
Disable_FindMarker(false)
|
||||
{}
|
||||
|
||||
UInt64 GetPhySize() const
|
||||
{
|
||||
if (IsMultiVol)
|
||||
return ArcInfo.FinishPos;
|
||||
else
|
||||
return (UInt64)((Int64)ArcInfo.FinishPos - ArcInfo.Base);
|
||||
}
|
||||
|
||||
UInt64 GetOffset() const
|
||||
{
|
||||
if (IsMultiVol)
|
||||
return 0;
|
||||
else
|
||||
return (UInt64)ArcInfo.Base;
|
||||
}
|
||||
|
||||
|
||||
void ClearRefs();
|
||||
void Close();
|
||||
HRESULT Open(IInStream *stream, const UInt64 *searchLimit, IArchiveOpenCallback *callback, CObjectVector<CItemEx> &items);
|
||||
|
||||
bool IsOpen() const { return IsArcOpen; }
|
||||
|
||||
bool AreThereErrors() const
|
||||
{
|
||||
return HeadersError
|
||||
|| UnexpectedEnd
|
||||
|| !Vols.MissingName.IsEmpty();
|
||||
}
|
||||
|
||||
bool IsLocalOffsetOK(const CItemEx &item) const
|
||||
{
|
||||
if (item.FromLocal)
|
||||
return true;
|
||||
return (Int64)GetOffset() + (Int64)item.LocalHeaderPos >= 0;
|
||||
}
|
||||
|
||||
UInt64 GetEmbeddedStubSize() const
|
||||
{
|
||||
// it's possible that first item in CD doesn refers to first local item
|
||||
// so FirstItemRelatOffset is not first local item
|
||||
|
||||
if (ArcInfo.CdWasRead)
|
||||
return ArcInfo.FirstItemRelatOffset;
|
||||
if (IsMultiVol)
|
||||
return 0;
|
||||
return (UInt64)((Int64)ArcInfo.MarkerPos2 - ArcInfo.Base);
|
||||
}
|
||||
|
||||
|
||||
HRESULT CheckDescriptor(const CItemEx &item);
|
||||
HRESULT Read_LocalItem_After_CdItem(CItemEx &item, bool &isAvail, bool &headersError);
|
||||
HRESULT Read_LocalItem_After_CdItem_Full(CItemEx &item);
|
||||
|
||||
HRESULT GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr<ISequentialInStream> &stream);
|
||||
|
||||
IInStream *GetBaseStream() { return StreamRef; }
|
||||
|
||||
bool CanUpdate() const
|
||||
{
|
||||
if (AreThereErrors()
|
||||
|| IsMultiVol
|
||||
|| ArcInfo.Base < 0
|
||||
|| (Int64)ArcInfo.MarkerPos2 < ArcInfo.Base
|
||||
|| ArcInfo.ThereIsTail
|
||||
|| GetEmbeddedStubSize() != 0
|
||||
|| IsApk
|
||||
|| IsCdUnsorted)
|
||||
return false;
|
||||
|
||||
// 7-zip probably can update archives with embedded stubs.
|
||||
// we just disable that feature for more safety.
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,464 @@
|
||||
// Archive/ZipItem.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#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"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
using namespace NFileHeader;
|
||||
|
||||
|
||||
/*
|
||||
const char *k_SpecName_NTFS_STREAM = "@@NTFS@STREAM@";
|
||||
const char *k_SpecName_MAC_RESOURCE_FORK = "@@MAC@RESOURCE-FORK@";
|
||||
*/
|
||||
|
||||
static const CUInt32PCharPair g_ExtraTypes[] =
|
||||
{
|
||||
{ NExtraID::kZip64, "Zip64" },
|
||||
{ NExtraID::kNTFS, "NTFS" },
|
||||
{ NExtraID::kUnix0, "UNIX" },
|
||||
{ NExtraID::kStrongEncrypt, "StrongCrypto" },
|
||||
{ NExtraID::kUnixTime, "UT" },
|
||||
{ NExtraID::kUnix1, "UX" },
|
||||
{ NExtraID::kUnix2, "Ux" },
|
||||
{ NExtraID::kUnixN, "ux" },
|
||||
{ NExtraID::kIzUnicodeComment, "uc" },
|
||||
{ NExtraID::kIzUnicodeName, "up" },
|
||||
{ NExtraID::kIzNtSecurityDescriptor, "SD" },
|
||||
{ NExtraID::kWzAES, "WzAES" },
|
||||
{ NExtraID::kApkAlign, "ApkAlign" }
|
||||
};
|
||||
|
||||
void CExtraSubBlock::PrintInfo(AString &s) const
|
||||
{
|
||||
for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExtraTypes); i++)
|
||||
{
|
||||
const CUInt32PCharPair &pair = g_ExtraTypes[i];
|
||||
if (pair.Value == ID)
|
||||
{
|
||||
s += pair.Name;
|
||||
if (ID == NExtraID::kUnixTime)
|
||||
{
|
||||
if (Data.Size() >= 1)
|
||||
{
|
||||
s.Add_Colon();
|
||||
const Byte flags = Data[0];
|
||||
if (flags & 1) s.Add_Char('M');
|
||||
if (flags & 2) s.Add_Char('A');
|
||||
if (flags & 4) s.Add_Char('C');
|
||||
const UInt32 size = (UInt32)(Data.Size()) - 1;
|
||||
if (size % 4 == 0)
|
||||
{
|
||||
s.Add_Colon();
|
||||
s.Add_UInt32(size / 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (ID == NExtraID::kApkAlign && Data.Size() >= 2)
|
||||
{
|
||||
char sz[32];
|
||||
sz[0] = ':';
|
||||
ConvertUInt32ToHex(GetUi16(Data), sz + 1);
|
||||
s += sz;
|
||||
for (unsigned j = 2; j < Data.Size(); j++)
|
||||
{
|
||||
char sz[32];
|
||||
sz[0] = '-';
|
||||
ConvertUInt32ToHex(Data[j], sz + 1);
|
||||
s += sz;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
{
|
||||
char sz[16];
|
||||
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;
|
||||
UInt32 size = (UInt32)Data.Size();
|
||||
if (ID != NExtraID::kNTFS || size < 32)
|
||||
return false;
|
||||
const Byte *p = (const Byte *)Data;
|
||||
p += 4; // for reserved
|
||||
size -= 4;
|
||||
while (size > 4)
|
||||
{
|
||||
UInt16 tag = GetUi16(p);
|
||||
unsigned attrSize = GetUi16(p + 2);
|
||||
p += 4;
|
||||
size -= 4;
|
||||
if (attrSize > size)
|
||||
attrSize = size;
|
||||
|
||||
if (tag == NNtfsExtra::kTagTime && attrSize >= 24)
|
||||
{
|
||||
p += 8 * index;
|
||||
ft.dwLowDateTime = GetUi32(p);
|
||||
ft.dwHighDateTime = GetUi32(p + 4);
|
||||
return true;
|
||||
}
|
||||
p += attrSize;
|
||||
size -= attrSize;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CExtraSubBlock::Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const
|
||||
{
|
||||
/* Info-Zip :
|
||||
The central-header extra field contains the modification
|
||||
time only, or no timestamp at all.
|
||||
Size of Data is used to flag its presence or absence
|
||||
If "Flags" indicates that Modtime is present in the local header
|
||||
field, it MUST be present in the central header field, too
|
||||
*/
|
||||
|
||||
res = 0;
|
||||
UInt32 size = (UInt32)Data.Size();
|
||||
if (ID != NExtraID::kUnixTime || size < 5)
|
||||
return false;
|
||||
const Byte *p = (const Byte *)Data;
|
||||
const Byte flags = *p++;
|
||||
size--;
|
||||
if (isCentral)
|
||||
{
|
||||
if (index != NUnixTime::kMTime ||
|
||||
(flags & (1 << NUnixTime::kMTime)) == 0 ||
|
||||
size < 4)
|
||||
return false;
|
||||
res = GetUi32(p);
|
||||
return true;
|
||||
}
|
||||
for (unsigned i = 0; i < 3; i++)
|
||||
if ((flags & (1 << i)) != 0)
|
||||
{
|
||||
if (size < 4)
|
||||
return false;
|
||||
if (index == i)
|
||||
{
|
||||
res = GetUi32(p);
|
||||
return true;
|
||||
}
|
||||
p += 4;
|
||||
size -= 4;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Info-ZIP's abandoned "Unix1 timestamps & owner ID info"
|
||||
|
||||
bool CExtraSubBlock::Extract_Unix01_Time(unsigned index, UInt32 &res) const
|
||||
{
|
||||
res = 0;
|
||||
const unsigned offset = index * 4;
|
||||
if (Data.Size() < offset + 4)
|
||||
return false;
|
||||
if (ID != NExtraID::kUnix0 &&
|
||||
ID != NExtraID::kUnix1)
|
||||
return false;
|
||||
const Byte *p = (const Byte *)Data + offset;
|
||||
res = GetUi32(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
// PKWARE's Unix "extra" is similar to Info-ZIP's abandoned "Unix1 timestamps"
|
||||
bool CExtraSubBlock::Extract_Unix_Time(unsigned index, UInt32 &res) const
|
||||
{
|
||||
res = 0;
|
||||
const unsigned offset = index * 4;
|
||||
if (ID != NExtraID::kUnix0 || Data.Size() < offset)
|
||||
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)
|
||||
{
|
||||
const CExtraSubBlock &sb = SubBlocks[i];
|
||||
if (sb.ID == NFileHeader::NExtraID::kNTFS)
|
||||
return sb.ExtractNtfsTime(index, ft);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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.Extract_UnixTime(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::kUnix0 ||
|
||||
sb.ID == NFileHeader::NExtraID::kUnix1)
|
||||
return sb.Extract_Unix01_Time(index, res);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CLocalItem::IsDir() const
|
||||
{
|
||||
return NItemName::HasTailSlash(Name, GetCodePage());
|
||||
}
|
||||
|
||||
bool CItem::IsDir() const
|
||||
{
|
||||
// FIXME: we can check InfoZip UTF-8 name at first.
|
||||
if (NItemName::HasTailSlash(Name, GetCodePage()))
|
||||
return true;
|
||||
|
||||
Byte hostOS = GetHostOS();
|
||||
|
||||
if (Size == 0 && PackSize == 0 && !Name.IsEmpty() && Name.Back() == '\\')
|
||||
{
|
||||
// do we need to use CharPrevExA?
|
||||
// .NET Framework 4.5 : System.IO.Compression::CreateFromDirectory() probably writes backslashes to headers?
|
||||
// so we support that case
|
||||
switch (hostOS)
|
||||
{
|
||||
case NHostOS::kFAT:
|
||||
case NHostOS::kNTFS:
|
||||
case NHostOS::kHPFS:
|
||||
case NHostOS::kVFAT:
|
||||
return true;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!FromCentral)
|
||||
return false;
|
||||
|
||||
UInt16 highAttrib = (UInt16)((ExternalAttrib >> 16 ) & 0xFFFF);
|
||||
|
||||
switch (hostOS)
|
||||
{
|
||||
case NHostOS::kAMIGA:
|
||||
switch (highAttrib & NAmigaAttrib::kIFMT)
|
||||
{
|
||||
case NAmigaAttrib::kIFDIR: return true;
|
||||
case NAmigaAttrib::kIFREG: return false;
|
||||
default: return false; // change it throw kUnknownAttributes;
|
||||
}
|
||||
case NHostOS::kFAT:
|
||||
case NHostOS::kNTFS:
|
||||
case NHostOS::kHPFS:
|
||||
case NHostOS::kVFAT:
|
||||
return ((ExternalAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0);
|
||||
case NHostOS::kAtari:
|
||||
case NHostOS::kMac:
|
||||
case NHostOS::kVMS:
|
||||
case NHostOS::kVM_CMS:
|
||||
case NHostOS::kAcorn:
|
||||
case NHostOS::kMVS:
|
||||
return false; // change it throw kUnknownAttributes;
|
||||
case NHostOS::kUnix:
|
||||
return MY_LIN_S_ISDIR(highAttrib);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 CItem::GetWinAttrib() const
|
||||
{
|
||||
UInt32 winAttrib = 0;
|
||||
switch (GetHostOS())
|
||||
{
|
||||
case NHostOS::kFAT:
|
||||
case NHostOS::kNTFS:
|
||||
if (FromCentral)
|
||||
winAttrib = ExternalAttrib;
|
||||
break;
|
||||
case NHostOS::kUnix:
|
||||
// do we need to clear 16 low bits in this case?
|
||||
if (FromCentral)
|
||||
{
|
||||
/*
|
||||
Some programs write posix attributes in high 16 bits of ExternalAttrib
|
||||
Also some programs can write additional marker flag:
|
||||
0x8000 - p7zip
|
||||
0x4000 - Zip in MacOS
|
||||
no marker - Info-Zip
|
||||
|
||||
Client code has two options to detect posix field:
|
||||
1) check 0x8000 marker. In that case we must add 0x8000 marker here.
|
||||
2) check that high 4 bits (file type bits in posix field) of attributes are not zero.
|
||||
*/
|
||||
|
||||
winAttrib = ExternalAttrib & 0xFFFF0000;
|
||||
|
||||
// #ifndef _WIN32
|
||||
winAttrib |= 0x8000; // add posix mode marker
|
||||
// #endif
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
if (IsDir()) // test it;
|
||||
winAttrib |= FILE_ATTRIBUTE_DIRECTORY;
|
||||
return winAttrib;
|
||||
}
|
||||
|
||||
bool CItem::GetPosixAttrib(UInt32 &attrib) const
|
||||
{
|
||||
// some archivers can store PosixAttrib in high 16 bits even with HostOS=FAT.
|
||||
if (FromCentral && GetHostOS() == NHostOS::kUnix)
|
||||
{
|
||||
attrib = ExternalAttrib >> 16;
|
||||
return (attrib != 0);
|
||||
}
|
||||
attrib = 0;
|
||||
if (IsDir())
|
||||
attrib = MY_LIN_S_IFDIR;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CExtraSubBlock::CheckIzUnicode(const AString &s) const
|
||||
{
|
||||
size_t size = Data.Size();
|
||||
if (size < 1 + 4)
|
||||
return false;
|
||||
const Byte *p = (const Byte *)Data;
|
||||
if (p[0] > 1)
|
||||
return false;
|
||||
if (CrcCalc(s, s.Len()) != GetUi32(p + 1))
|
||||
return false;
|
||||
size -= 5;
|
||||
p += 5;
|
||||
for (size_t i = 0; i < size; i++)
|
||||
if (p[i] == 0)
|
||||
return false;
|
||||
return Check_UTF8_Buf((const char *)(const void *)p, size, false);
|
||||
}
|
||||
|
||||
|
||||
void CItem::GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const
|
||||
{
|
||||
bool isUtf8 = IsUtf8();
|
||||
// bool ignore_Utf8_Errors = true;
|
||||
|
||||
if (!isUtf8)
|
||||
{
|
||||
{
|
||||
const unsigned id = isComment ?
|
||||
NFileHeader::NExtraID::kIzUnicodeComment:
|
||||
NFileHeader::NExtraID::kIzUnicodeName;
|
||||
const CObjectVector<CExtraSubBlock> &subBlocks = GetMainExtra().SubBlocks;
|
||||
|
||||
FOR_VECTOR (i, subBlocks)
|
||||
{
|
||||
const CExtraSubBlock &sb = subBlocks[i];
|
||||
if (sb.ID == id)
|
||||
{
|
||||
if (sb.CheckIzUnicode(s))
|
||||
{
|
||||
// const unsigned kIzUnicodeHeaderSize = 5;
|
||||
if (Convert_UTF8_Buf_To_Unicode(
|
||||
(const char *)(const void *)(const Byte *)sb.Data + 5,
|
||||
sb.Data.Size() - 5, res))
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useSpecifiedCodePage)
|
||||
isUtf8 = (codePage == CP_UTF8);
|
||||
#ifdef _WIN32
|
||||
else if (GetHostOS() == NFileHeader::NHostOS::kUnix)
|
||||
{
|
||||
/* Some ZIP archives in Unix use UTF-8 encoding without Utf8 flag in header.
|
||||
We try to get name as UTF-8.
|
||||
Do we need to do it in POSIX version also? */
|
||||
isUtf8 = true;
|
||||
|
||||
/* 21.02: we want to ignore UTF-8 errors to support file paths that are mixed
|
||||
of UTF-8 and non-UTF-8 characters. */
|
||||
// ignore_Utf8_Errors = false;
|
||||
// ignore_Utf8_Errors = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
if (isUtf8)
|
||||
{
|
||||
ConvertUTF8ToUnicode(s, res);
|
||||
return;
|
||||
}
|
||||
|
||||
MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage());
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,356 @@
|
||||
// Archive/ZipItem.h
|
||||
|
||||
#ifndef ZIP7_INC_ARCHIVE_ZIP_ITEM_H
|
||||
#define ZIP7_INC_ARCHIVE_ZIP_ITEM_H
|
||||
|
||||
#include "../../../../C/CpuArch.h"
|
||||
|
||||
#include "../../../Common/MyBuffer.h"
|
||||
#include "../../../Common/MyString.h"
|
||||
#include "../../../Common/UTFConvert.h"
|
||||
|
||||
#include "ZipHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
/*
|
||||
extern const char *k_SpecName_NTFS_STREAM;
|
||||
extern const char *k_SpecName_MAC_RESOURCE_FORK;
|
||||
*/
|
||||
|
||||
struct CVersion
|
||||
{
|
||||
Byte Version;
|
||||
Byte HostOS;
|
||||
};
|
||||
|
||||
struct CExtraSubBlock
|
||||
{
|
||||
UInt32 ID;
|
||||
CByteBuffer Data;
|
||||
|
||||
bool ExtractNtfsTime(unsigned index, FILETIME &ft) const;
|
||||
bool Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const;
|
||||
bool Extract_Unix01_Time(unsigned index, UInt32 &res) const;
|
||||
// bool Extract_Unix_Time(unsigned index, UInt32 &res) const;
|
||||
|
||||
bool CheckIzUnicode(const AString &s) const;
|
||||
|
||||
void PrintInfo(AString &s) const;
|
||||
};
|
||||
|
||||
const unsigned k_WzAesExtra_Size = 7;
|
||||
|
||||
struct CWzAesExtra
|
||||
{
|
||||
UInt16 VendorVersion; // 1: AE-1, 2: AE-2,
|
||||
// UInt16 VendorId; // 'A' 'E'
|
||||
Byte Strength; // 1: 128-bit, 2: 192-bit, 3: 256-bit
|
||||
UInt16 Method;
|
||||
|
||||
CWzAesExtra(): VendorVersion(2), Strength(3), Method(0) {}
|
||||
|
||||
bool NeedCrc() const { return (VendorVersion == 1); }
|
||||
|
||||
bool ParseFromSubBlock(const CExtraSubBlock &sb)
|
||||
{
|
||||
if (sb.ID != NFileHeader::NExtraID::kWzAES)
|
||||
return false;
|
||||
if (sb.Data.Size() < k_WzAesExtra_Size)
|
||||
return false;
|
||||
const Byte *p = (const Byte *)sb.Data;
|
||||
VendorVersion = GetUi16(p);
|
||||
if (p[2] != 'A' || p[3] != 'E')
|
||||
return false;
|
||||
Strength = p[4];
|
||||
// 9.31: The BUG was fixed:
|
||||
Method = GetUi16(p + 5);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetSubBlock(CExtraSubBlock &sb) const
|
||||
{
|
||||
sb.Data.Alloc(k_WzAesExtra_Size);
|
||||
sb.ID = NFileHeader::NExtraID::kWzAES;
|
||||
Byte *p = (Byte *)sb.Data;
|
||||
p[0] = (Byte)VendorVersion;
|
||||
p[1] = (Byte)(VendorVersion >> 8);
|
||||
p[2] = 'A';
|
||||
p[3] = 'E';
|
||||
p[4] = Strength;
|
||||
p[5] = (Byte)Method;
|
||||
p[6] = (Byte)(Method >> 8);
|
||||
}
|
||||
};
|
||||
|
||||
namespace NStrongCrypto_AlgId
|
||||
{
|
||||
const UInt16 kDES = 0x6601;
|
||||
const UInt16 kRC2old = 0x6602;
|
||||
const UInt16 k3DES168 = 0x6603;
|
||||
const UInt16 k3DES112 = 0x6609;
|
||||
const UInt16 kAES128 = 0x660E;
|
||||
const UInt16 kAES192 = 0x660F;
|
||||
const UInt16 kAES256 = 0x6610;
|
||||
const UInt16 kRC2 = 0x6702;
|
||||
const UInt16 kBlowfish = 0x6720;
|
||||
const UInt16 kTwofish = 0x6721;
|
||||
const UInt16 kRC4 = 0x6801;
|
||||
}
|
||||
|
||||
struct CStrongCryptoExtra
|
||||
{
|
||||
UInt16 Format;
|
||||
UInt16 AlgId;
|
||||
UInt16 BitLen;
|
||||
UInt16 Flags;
|
||||
|
||||
bool ParseFromSubBlock(const CExtraSubBlock &sb)
|
||||
{
|
||||
if (sb.ID != NFileHeader::NExtraID::kStrongEncrypt)
|
||||
return false;
|
||||
const Byte *p = (const Byte *)sb.Data;
|
||||
if (sb.Data.Size() < 8)
|
||||
return false;
|
||||
Format = GetUi16(p + 0);
|
||||
AlgId = GetUi16(p + 2);
|
||||
BitLen = GetUi16(p + 4);
|
||||
Flags = GetUi16(p + 6);
|
||||
return (Format == 2);
|
||||
}
|
||||
|
||||
bool CertificateIsUsed() const { return (Flags > 0x0001); }
|
||||
};
|
||||
|
||||
|
||||
struct CExtraBlock
|
||||
{
|
||||
CObjectVector<CExtraSubBlock> SubBlocks;
|
||||
bool Error;
|
||||
bool MinorError;
|
||||
bool IsZip64;
|
||||
bool IsZip64_Error;
|
||||
|
||||
CExtraBlock(): Error(false), MinorError(false), IsZip64(false), IsZip64_Error(false) {}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
SubBlocks.Clear();
|
||||
IsZip64 = false;
|
||||
}
|
||||
|
||||
size_t GetSize() const
|
||||
{
|
||||
size_t res = 0;
|
||||
FOR_VECTOR (i, SubBlocks)
|
||||
res += SubBlocks[i].Data.Size() + 2 + 2;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool GetWzAes(CWzAesExtra &e) const
|
||||
{
|
||||
FOR_VECTOR (i, SubBlocks)
|
||||
if (e.ParseFromSubBlock(SubBlocks[i]))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasWzAes() const
|
||||
{
|
||||
CWzAesExtra e;
|
||||
return GetWzAes(e);
|
||||
}
|
||||
|
||||
bool GetStrongCrypto(CStrongCryptoExtra &e) const
|
||||
{
|
||||
FOR_VECTOR (i, SubBlocks)
|
||||
if (e.ParseFromSubBlock(SubBlocks[i]))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
bool HasStrongCrypto() const
|
||||
{
|
||||
CStrongCryptoExtra e;
|
||||
return GetStrongCrypto(e);
|
||||
}
|
||||
*/
|
||||
|
||||
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;)
|
||||
{
|
||||
i--;
|
||||
switch (SubBlocks[i].ID)
|
||||
{
|
||||
case NFileHeader::NExtraID::kStrongEncrypt:
|
||||
case NFileHeader::NExtraID::kWzAES:
|
||||
break;
|
||||
default:
|
||||
SubBlocks.Delete(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CLocalItem
|
||||
{
|
||||
public:
|
||||
UInt16 Flags;
|
||||
UInt16 Method;
|
||||
|
||||
/*
|
||||
Zip specification doesn't mention that ExtractVersion field uses HostOS subfield.
|
||||
18.06: 7-Zip now doesn't use ExtractVersion::HostOS to detect codePage
|
||||
*/
|
||||
|
||||
CVersion ExtractVersion;
|
||||
|
||||
UInt64 Size;
|
||||
UInt64 PackSize;
|
||||
UInt32 Time;
|
||||
UInt32 Crc;
|
||||
|
||||
UInt32 Disk;
|
||||
|
||||
AString Name;
|
||||
|
||||
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; }
|
||||
// bool IsAltStream() const { return (Flags & NFileHeader::NFlags::kAltStream) != 0; }
|
||||
|
||||
unsigned GetDeflateLevel() const { return (Flags >> 1) & 3; }
|
||||
|
||||
bool IsDir() const;
|
||||
|
||||
/*
|
||||
void GetUnicodeString(const AString &s, UString &res) const
|
||||
{
|
||||
bool isUtf8 = IsUtf8();
|
||||
if (isUtf8)
|
||||
if (ConvertUTF8ToUnicode(s, res))
|
||||
return;
|
||||
MultiByteToUnicodeString2(res, s, GetCodePage());
|
||||
}
|
||||
*/
|
||||
|
||||
private:
|
||||
|
||||
void SetFlag(unsigned bitMask, bool enable)
|
||||
{
|
||||
if (enable)
|
||||
Flags = (UInt16)(Flags | bitMask);
|
||||
else
|
||||
Flags = (UInt16)(Flags & ~bitMask);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void ClearFlags() { Flags = 0; }
|
||||
void SetEncrypted(bool encrypted) { SetFlag(NFileHeader::NFlags::kEncrypted, encrypted); }
|
||||
void SetUtf8(bool isUtf8) { SetFlag(NFileHeader::NFlags::kUtf8, isUtf8); }
|
||||
// void SetFlag_AltStream(bool isAltStream) { SetFlag(NFileHeader::NFlags::kAltStream, isAltStream); }
|
||||
void SetDescriptorMode(bool useDescriptor) { SetFlag(NFileHeader::NFlags::kDescriptorUsedMask, useDescriptor); }
|
||||
|
||||
UINT GetCodePage() const
|
||||
{
|
||||
if (IsUtf8())
|
||||
return CP_UTF8;
|
||||
return CP_OEMCP;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CItem: public CLocalItem
|
||||
{
|
||||
public:
|
||||
CVersion MadeByVersion;
|
||||
UInt16 InternalAttrib;
|
||||
UInt32 ExternalAttrib;
|
||||
|
||||
UInt64 LocalHeaderPos;
|
||||
|
||||
CExtraBlock CentralExtra;
|
||||
CByteBuffer Comment;
|
||||
|
||||
bool FromLocal;
|
||||
bool FromCentral;
|
||||
|
||||
// CItem can be used as CLocalItem. So we must clear unused fields
|
||||
CItem():
|
||||
InternalAttrib(0),
|
||||
ExternalAttrib(0),
|
||||
FromLocal(false),
|
||||
FromCentral(false)
|
||||
{
|
||||
MadeByVersion.Version = 0;
|
||||
MadeByVersion.HostOS = 0;
|
||||
}
|
||||
|
||||
const CExtraBlock &GetMainExtra() const { return *(FromCentral ? &CentralExtra : &LocalExtra); }
|
||||
|
||||
bool IsDir() const;
|
||||
UInt32 GetWinAttrib() const;
|
||||
bool GetPosixAttrib(UInt32 &attrib) const;
|
||||
|
||||
// 18.06: 0 instead of ExtractVersion.HostOS for local item
|
||||
Byte GetHostOS() const { return FromCentral ? MadeByVersion.HostOS : (Byte)0; }
|
||||
|
||||
void GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const;
|
||||
|
||||
bool IsThereCrc() const
|
||||
{
|
||||
if (Method == NFileHeader::NCompressionMethod::kWzAES)
|
||||
{
|
||||
CWzAesExtra aesField;
|
||||
if (GetMainExtra().GetWzAes(aesField))
|
||||
return aesField.NeedCrc();
|
||||
}
|
||||
return (Crc != 0 || !IsDir());
|
||||
}
|
||||
|
||||
bool Is_MadeBy_Unix() const
|
||||
{
|
||||
if (!FromCentral)
|
||||
return false;
|
||||
return (MadeByVersion.HostOS == NFileHeader::NHostOS::kUnix);
|
||||
}
|
||||
|
||||
UINT GetCodePage() const
|
||||
{
|
||||
// 18.06: now we use HostOS only from Central::MadeByVersion
|
||||
if (IsUtf8())
|
||||
return CP_UTF8;
|
||||
if (!FromCentral)
|
||||
return CP_OEMCP;
|
||||
Byte hostOS = MadeByVersion.HostOS;
|
||||
return (UINT)((
|
||||
hostOS == NFileHeader::NHostOS::kFAT
|
||||
|| hostOS == NFileHeader::NHostOS::kNTFS
|
||||
|| hostOS == NFileHeader::NHostOS::kUnix // do we need it?
|
||||
) ? CP_OEMCP : CP_ACP);
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,428 @@
|
||||
// ZipOut.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
|
||||
#include "../../../Windows/TimeUtils.h"
|
||||
#include "../../Common/OffsetStream.h"
|
||||
|
||||
#include "ZipOut.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
HRESULT COutArchive::ClearRestriction()
|
||||
{
|
||||
if (SetRestriction)
|
||||
return SetRestriction->SetRestriction(0, 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT COutArchive::SetRestrictionFromCurrent()
|
||||
{
|
||||
if (SetRestriction)
|
||||
return SetRestriction->SetRestriction(m_Base + m_CurPos, (UInt64)(Int64)-1);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT COutArchive::Create(IOutStream *outStream)
|
||||
{
|
||||
m_CurPos = 0;
|
||||
if (!m_OutBuffer.Create(1 << 16))
|
||||
return E_OUTOFMEMORY;
|
||||
m_Stream = outStream;
|
||||
m_OutBuffer.SetStream(outStream);
|
||||
m_OutBuffer.Init();
|
||||
|
||||
return m_Stream->Seek(0, STREAM_SEEK_CUR, &m_Base);
|
||||
}
|
||||
|
||||
void COutArchive::SeekToCurPos()
|
||||
{
|
||||
HRESULT res = m_Stream->Seek((Int64)(m_Base + m_CurPos), STREAM_SEEK_SET, NULL);
|
||||
if (res != S_OK)
|
||||
throw CSystemException(res);
|
||||
}
|
||||
|
||||
#define DOES_NEED_ZIP64(v) (v >= (UInt32)0xFFFFFFFF)
|
||||
// #define DOES_NEED_ZIP64(v) (v >= 0)
|
||||
|
||||
|
||||
Z7_NO_INLINE
|
||||
void COutArchive::WriteBytes(const void *data, size_t size)
|
||||
{
|
||||
m_OutBuffer.WriteBytes(data, size);
|
||||
m_CurPos += size;
|
||||
}
|
||||
|
||||
Z7_NO_INLINE
|
||||
void COutArchive::Write8(Byte b)
|
||||
{
|
||||
m_OutBuffer.WriteByte(b);
|
||||
m_CurPos++;
|
||||
}
|
||||
|
||||
Z7_NO_INLINE
|
||||
void COutArchive::Write16(UInt16 val)
|
||||
{
|
||||
Write8((Byte)val);
|
||||
Write8((Byte)(val >> 8));
|
||||
}
|
||||
|
||||
Z7_NO_INLINE
|
||||
void COutArchive::Write32(UInt32 val)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
// Write8((Byte)val);
|
||||
m_OutBuffer.WriteByte((Byte)val);
|
||||
val >>= 8;
|
||||
}
|
||||
m_CurPos += 4;
|
||||
}
|
||||
|
||||
#define WRITE_CONST_PAIR_16_16(a, b) { Write32((a) | ((UInt32)(b) << 16)); }
|
||||
|
||||
Z7_NO_INLINE
|
||||
void COutArchive::Write64(UInt64 val)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
// Write8((Byte)val);
|
||||
m_OutBuffer.WriteByte((Byte)val);
|
||||
val >>= 8;
|
||||
}
|
||||
m_CurPos += 8;
|
||||
}
|
||||
|
||||
Z7_NO_INLINE
|
||||
void COutArchive::WriteExtra(const CExtraBlock &extra)
|
||||
{
|
||||
FOR_VECTOR (i, extra.SubBlocks)
|
||||
{
|
||||
const CExtraSubBlock &subBlock = extra.SubBlocks[i];
|
||||
Write16((UInt16)subBlock.ID);
|
||||
Write16((UInt16)subBlock.Data.Size());
|
||||
WriteBytes(subBlock.Data, (UInt16)subBlock.Data.Size());
|
||||
}
|
||||
}
|
||||
|
||||
void COutArchive::WriteCommonItemInfo(const CLocalItem &item, bool isZip64)
|
||||
{
|
||||
{
|
||||
Byte ver = item.ExtractVersion.Version;
|
||||
if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
|
||||
ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
|
||||
Write8(ver);
|
||||
}
|
||||
Write8(item.ExtractVersion.HostOS);
|
||||
Write16(item.Flags);
|
||||
Write16(item.Method);
|
||||
Write32(item.Time);
|
||||
}
|
||||
|
||||
|
||||
#define WRITE_32_VAL_SPEC(_v_, _isZip64_) Write32((_isZip64_) ? 0xFFFFFFFF : (UInt32)(_v_));
|
||||
|
||||
|
||||
void COutArchive::WriteUtfName(const CItemOut &item)
|
||||
{
|
||||
if (item.Name_Utf.Size() == 0)
|
||||
return;
|
||||
Write16(NFileHeader::NExtraID::kIzUnicodeName);
|
||||
Write16((UInt16)(5 + item.Name_Utf.Size()));
|
||||
Write8(1); // (1 = version) of that extra field
|
||||
Write32(CrcCalc(item.Name.Ptr(), item.Name.Len()));
|
||||
WriteBytes(item.Name_Utf, (UInt16)item.Name_Utf.Size());
|
||||
}
|
||||
|
||||
|
||||
static const unsigned k_Ntfs_ExtraSize = 4 + 2 + 2 + (3 * 8);
|
||||
static const unsigned k_UnixTime_ExtraSize = 1 + (1 * 4);
|
||||
|
||||
void COutArchive::WriteTimeExtra(const CItemOut &item, bool writeNtfs)
|
||||
{
|
||||
if (writeNtfs)
|
||||
{
|
||||
// windows explorer ignores that extra
|
||||
WRITE_CONST_PAIR_16_16(NFileHeader::NExtraID::kNTFS, k_Ntfs_ExtraSize)
|
||||
Write32(0); // reserved
|
||||
WRITE_CONST_PAIR_16_16(NFileHeader::NNtfsExtra::kTagTime, 8 * 3)
|
||||
WriteNtfsTime(item.Ntfs_MTime);
|
||||
WriteNtfsTime(item.Ntfs_ATime);
|
||||
WriteNtfsTime(item.Ntfs_CTime);
|
||||
}
|
||||
|
||||
if (item.Write_UnixTime)
|
||||
{
|
||||
// windows explorer ignores that extra
|
||||
// by specification : should we write to local header also?
|
||||
WRITE_CONST_PAIR_16_16(NFileHeader::NExtraID::kUnixTime, k_UnixTime_ExtraSize)
|
||||
const Byte flags = (Byte)((unsigned)1 << NFileHeader::NUnixTime::kMTime);
|
||||
Write8(flags);
|
||||
UInt32 unixTime;
|
||||
NWindows::NTime::FileTime_To_UnixTime(item.Ntfs_MTime, unixTime);
|
||||
Write32(unixTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
|
||||
{
|
||||
m_LocalHeaderPos = m_CurPos;
|
||||
item.LocalHeaderPos = m_CurPos;
|
||||
|
||||
bool isZip64 =
|
||||
DOES_NEED_ZIP64(item.PackSize) ||
|
||||
DOES_NEED_ZIP64(item.Size);
|
||||
|
||||
if (needCheck && m_IsZip64)
|
||||
isZip64 = true;
|
||||
|
||||
// Why don't we write NTFS timestamps to local header?
|
||||
// Probably we want to reduce size of archive?
|
||||
const bool writeNtfs = false; // do not write NTFS timestamp to local header
|
||||
// const bool writeNtfs = item.Write_NtfsTime; // write NTFS time to local header
|
||||
const UInt32 localExtraSize = (UInt32)(
|
||||
(isZip64 ? (4 + 8 + 8): 0)
|
||||
+ (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0)
|
||||
+ (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0)
|
||||
+ item.Get_UtfName_ExtraSize()
|
||||
+ 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());
|
||||
|
||||
Write16((UInt16)localExtraSize);
|
||||
|
||||
WriteBytes((const char *)item.Name, (UInt16)item.Name.Len());
|
||||
|
||||
if (isZip64)
|
||||
{
|
||||
WRITE_CONST_PAIR_16_16(NFileHeader::NExtraID::kZip64, 8 + 8)
|
||||
Write64(size);
|
||||
Write64(packSize);
|
||||
}
|
||||
|
||||
WriteTimeExtra(item, writeNtfs);
|
||||
|
||||
WriteUtfName(item);
|
||||
|
||||
WriteExtra(item.LocalExtra);
|
||||
|
||||
const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos);
|
||||
if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize)
|
||||
throw CSystemException(E_FAIL);
|
||||
m_LocalFileHeaderSize = localFileHeaderSize;
|
||||
|
||||
m_OutBuffer.FlushWithCheck();
|
||||
}
|
||||
|
||||
|
||||
void COutArchive::WriteLocalHeader_Replace(CItemOut &item)
|
||||
{
|
||||
m_CurPos = m_LocalHeaderPos + m_LocalFileHeaderSize + item.PackSize;
|
||||
|
||||
if (item.HasDescriptor())
|
||||
{
|
||||
WriteDescriptor(item);
|
||||
m_OutBuffer.FlushWithCheck();
|
||||
return;
|
||||
// we don't replace local header, if we write Descriptor.
|
||||
// so local header with Descriptor flag must be written to local header before.
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const bool isUnPack64 = DOES_NEED_ZIP64(item.Size);
|
||||
const bool isPack64 = DOES_NEED_ZIP64(item.PackSize);
|
||||
const bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos);
|
||||
const bool isZip64 = isPack64 || isUnPack64 || isPosition64;
|
||||
|
||||
Write32(NSignature::kCentralFileHeader);
|
||||
Write8(item.MadeByVersion.Version);
|
||||
Write8(item.MadeByVersion.HostOS);
|
||||
|
||||
WriteCommonItemInfo(item, isZip64);
|
||||
Write32(item.Crc);
|
||||
|
||||
WRITE_32_VAL_SPEC(item.PackSize, isPack64)
|
||||
WRITE_32_VAL_SPEC(item.Size, isUnPack64)
|
||||
|
||||
Write16((UInt16)item.Name.Len());
|
||||
|
||||
const UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
|
||||
const bool writeNtfs = item.Write_NtfsTime;
|
||||
const size_t centralExtraSize =
|
||||
(isZip64 ? 4 + zip64ExtraSize : 0)
|
||||
+ (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0)
|
||||
+ (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0)
|
||||
+ item.Get_UtfName_ExtraSize()
|
||||
+ item.CentralExtra.GetSize();
|
||||
|
||||
const UInt16 centralExtraSize16 = (UInt16)centralExtraSize;
|
||||
if (centralExtraSize16 != centralExtraSize)
|
||||
throw CSystemException(E_FAIL);
|
||||
|
||||
Write16(centralExtraSize16);
|
||||
|
||||
const UInt16 commentSize = (UInt16)item.Comment.Size();
|
||||
|
||||
Write16(commentSize);
|
||||
Write16(0); // DiskNumberStart
|
||||
Write16(item.InternalAttrib);
|
||||
Write32(item.ExternalAttrib);
|
||||
WRITE_32_VAL_SPEC(item.LocalHeaderPos, isPosition64)
|
||||
WriteBytes((const char *)item.Name, item.Name.Len());
|
||||
|
||||
if (isZip64)
|
||||
{
|
||||
Write16(NFileHeader::NExtraID::kZip64);
|
||||
Write16(zip64ExtraSize);
|
||||
if (isUnPack64)
|
||||
Write64(item.Size);
|
||||
if (isPack64)
|
||||
Write64(item.PackSize);
|
||||
if (isPosition64)
|
||||
Write64(item.LocalHeaderPos);
|
||||
}
|
||||
|
||||
WriteTimeExtra(item, writeNtfs);
|
||||
WriteUtfName(item);
|
||||
|
||||
WriteExtra(item.CentralExtra);
|
||||
if (commentSize != 0)
|
||||
WriteBytes(item.Comment, commentSize);
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment)
|
||||
{
|
||||
RINOK(ClearRestriction())
|
||||
|
||||
const UInt64 cdOffset = GetCurPos();
|
||||
FOR_VECTOR (i, items)
|
||||
WriteCentralHeader(items[i]);
|
||||
const UInt64 cd64EndOffset = GetCurPos();
|
||||
const UInt64 cdSize = cd64EndOffset - cdOffset;
|
||||
const bool cdOffset64 = DOES_NEED_ZIP64(cdOffset);
|
||||
const bool cdSize64 = DOES_NEED_ZIP64(cdSize);
|
||||
const bool need_Items_64 = items.Size() >= 0xFFFF;
|
||||
const unsigned items16 = (UInt16)(need_Items_64 ? 0xFFFF: items.Size());
|
||||
const bool isZip64 = (cdOffset64 || cdSize64 || need_Items_64);
|
||||
|
||||
// isZip64 = true; // to test Zip64
|
||||
|
||||
if (isZip64)
|
||||
{
|
||||
Write32(NSignature::kEcd64);
|
||||
Write64(kEcd64_MainSize);
|
||||
|
||||
// to test extra block:
|
||||
// const UInt32 extraSize = 1 << 26;
|
||||
// Write64(kEcd64_MainSize + extraSize);
|
||||
|
||||
WRITE_CONST_PAIR_16_16(45, // made by version
|
||||
45) // extract version
|
||||
Write32(0); // ThisDiskNumber
|
||||
Write32(0); // StartCentralDirectoryDiskNumber
|
||||
Write64((UInt64)items.Size());
|
||||
Write64((UInt64)items.Size());
|
||||
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);
|
||||
Write32(1); // total number of disks
|
||||
}
|
||||
|
||||
Write32(NSignature::kEcd);
|
||||
WRITE_CONST_PAIR_16_16(0, 0) // ThisDiskNumber, StartCentralDirectoryDiskNumber
|
||||
Write16((UInt16)items16);
|
||||
Write16((UInt16)items16);
|
||||
|
||||
WRITE_32_VAL_SPEC(cdSize, cdSize64)
|
||||
WRITE_32_VAL_SPEC(cdOffset, cdOffset64)
|
||||
|
||||
const UInt16 commentSize = (UInt16)(comment ? comment->Size() : 0);
|
||||
Write16((UInt16)commentSize);
|
||||
if (commentSize != 0)
|
||||
WriteBytes((const Byte *)*comment, commentSize);
|
||||
m_OutBuffer.FlushWithCheck();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void COutArchive::CreateStreamForCompressing(CMyComPtr<IOutStream> &outStream)
|
||||
{
|
||||
COffsetOutStream *streamSpec = new COffsetOutStream;
|
||||
outStream = streamSpec;
|
||||
streamSpec->Init(m_Stream, m_Base + m_CurPos);
|
||||
}
|
||||
|
||||
void COutArchive::CreateStreamForCopying(CMyComPtr<ISequentialOutStream> &outStream)
|
||||
{
|
||||
outStream = m_Stream;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,103 @@
|
||||
// ZipOut.h
|
||||
|
||||
#ifndef ZIP7_INC_ZIP_OUT_H
|
||||
#define ZIP7_INC_ZIP_OUT_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../Common/OutBuffer.h"
|
||||
|
||||
#include "ZipItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
class CItemOut: public CItem
|
||||
{
|
||||
public:
|
||||
FILETIME Ntfs_MTime;
|
||||
FILETIME Ntfs_ATime;
|
||||
FILETIME Ntfs_CTime;
|
||||
bool Write_NtfsTime;
|
||||
bool Write_UnixTime;
|
||||
|
||||
// It's possible that NtfsTime is not defined, but there is NtfsTime in Extra.
|
||||
|
||||
CByteBuffer Name_Utf; // for Info-Zip (kIzUnicodeName) Extra
|
||||
|
||||
size_t Get_UtfName_ExtraSize() const
|
||||
{
|
||||
const size_t size = Name_Utf.Size();
|
||||
if (size == 0)
|
||||
return 0;
|
||||
return 4 + 5 + size;
|
||||
}
|
||||
|
||||
CItemOut():
|
||||
Write_NtfsTime(false),
|
||||
Write_UnixTime(false)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
// COutArchive can throw CSystemException and COutBufferException
|
||||
|
||||
class COutArchive
|
||||
{
|
||||
COutBuffer m_OutBuffer;
|
||||
CMyComPtr<IOutStream> m_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 WriteBytes(const void *data, size_t size);
|
||||
void Write8(Byte b);
|
||||
void Write16(UInt16 val);
|
||||
void Write32(UInt32 val);
|
||||
void Write64(UInt64 val);
|
||||
void WriteNtfsTime(const FILETIME &ft)
|
||||
{
|
||||
Write32(ft.dwLowDateTime);
|
||||
Write32(ft.dwHighDateTime);
|
||||
}
|
||||
|
||||
void WriteTimeExtra(const CItemOut &item, bool writeNtfs);
|
||||
void WriteUtfName(const CItemOut &item);
|
||||
void WriteExtra(const CExtraBlock &extra);
|
||||
void WriteCommonItemInfo(const CLocalItem &item, bool isZip64);
|
||||
void WriteCentralHeader(const CItemOut &item);
|
||||
|
||||
void SeekToCurPos();
|
||||
public:
|
||||
CMyComPtr<IStreamSetRestriction> SetRestriction;
|
||||
|
||||
HRESULT ClearRestriction();
|
||||
HRESULT SetRestrictionFromCurrent();
|
||||
HRESULT Create(IOutStream *outStream);
|
||||
|
||||
UInt64 GetCurPos() const { return m_CurPos; }
|
||||
|
||||
void MoveCurPos(UInt64 distanceToMove)
|
||||
{
|
||||
m_CurPos += distanceToMove;
|
||||
}
|
||||
|
||||
void WriteLocalHeader(CItemOut &item, bool needCheck = false);
|
||||
void WriteLocalHeader_Replace(CItemOut &item);
|
||||
|
||||
void WriteDescriptor(const CItemOut &item);
|
||||
|
||||
HRESULT WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment);
|
||||
|
||||
void CreateStreamForCompressing(CMyComPtr<IOutStream> &outStream);
|
||||
void CreateStreamForCopying(CMyComPtr<ISequentialOutStream> &outStream);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
// ZipRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#include "ZipHandler.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
static const Byte k_Signature[] = {
|
||||
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 ipa apk appx", NULL, 1,
|
||||
k_Signature,
|
||||
0,
|
||||
NArcInfoFlags::kFindSignature
|
||||
| NArcInfoFlags::kMultiSignature
|
||||
| NArcInfoFlags::kUseGlobalOffset
|
||||
| NArcInfoFlags::kCTime
|
||||
// | NArcInfoFlags::kCTime_Default
|
||||
| NArcInfoFlags::kATime
|
||||
// | NArcInfoFlags::kATime_Default
|
||||
| NArcInfoFlags::kMTime
|
||||
| NArcInfoFlags::kMTime_Default
|
||||
, TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows)
|
||||
| TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
|
||||
| TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kDOS)
|
||||
| TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows)
|
||||
, IsArc_Zip)
|
||||
|
||||
}}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,107 @@
|
||||
// ZipUpdate.h
|
||||
|
||||
#ifndef ZIP7_INC_ZIP_UPDATE_H
|
||||
#define ZIP7_INC_ZIP_UPDATE_H
|
||||
|
||||
#include "../../ICoder.h"
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
|
||||
#include "ZipCompressionMode.h"
|
||||
#include "ZipIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
/*
|
||||
struct CUpdateRange
|
||||
{
|
||||
UInt64 Position;
|
||||
UInt64 Size;
|
||||
|
||||
// CUpdateRange() {}
|
||||
CUpdateRange(UInt64 position, UInt64 size): Position(position), Size(size) {}
|
||||
};
|
||||
*/
|
||||
|
||||
struct CUpdateItem
|
||||
{
|
||||
bool NewData;
|
||||
bool NewProps;
|
||||
bool IsDir;
|
||||
bool Write_NtfsTime;
|
||||
bool Write_UnixTime;
|
||||
// bool Write_UnixTime_ATime;
|
||||
bool IsUtf8;
|
||||
bool Size_WasSetFromStream;
|
||||
// bool IsAltStream;
|
||||
int IndexInArc;
|
||||
unsigned IndexInClient;
|
||||
UInt32 Attrib;
|
||||
UInt32 Time;
|
||||
UInt64 Size;
|
||||
AString Name;
|
||||
CByteBuffer Name_Utf; // for Info-Zip (kIzUnicodeName) Extra
|
||||
CByteBuffer Comment;
|
||||
// bool Commented;
|
||||
// CUpdateRange CommentRange;
|
||||
FILETIME Ntfs_MTime;
|
||||
FILETIME Ntfs_ATime;
|
||||
FILETIME Ntfs_CTime;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
IsDir = false;
|
||||
|
||||
Write_NtfsTime = false;
|
||||
Write_UnixTime = false;
|
||||
|
||||
IsUtf8 = false;
|
||||
Size_WasSetFromStream = false;
|
||||
// IsAltStream = false;
|
||||
Time = 0;
|
||||
Size = 0;
|
||||
Name.Empty();
|
||||
Name_Utf.Free();
|
||||
Comment.Free();
|
||||
|
||||
FILETIME_Clear(Ntfs_MTime);
|
||||
FILETIME_Clear(Ntfs_ATime);
|
||||
FILETIME_Clear(Ntfs_CTime);
|
||||
}
|
||||
|
||||
CUpdateItem():
|
||||
IsDir(false),
|
||||
Write_NtfsTime(false),
|
||||
Write_UnixTime(false),
|
||||
IsUtf8(false),
|
||||
Size_WasSetFromStream(false),
|
||||
// IsAltStream(false),
|
||||
Time(0),
|
||||
Size(0)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
struct CUpdateOptions
|
||||
{
|
||||
bool Write_MTime;
|
||||
bool Write_ATime;
|
||||
bool Write_CTime;
|
||||
};
|
||||
|
||||
|
||||
HRESULT Update(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
const CObjectVector<CItemEx> &inputItems,
|
||||
CObjectVector<CUpdateItem> &updateItems,
|
||||
ISequentialOutStream *seqOutStream,
|
||||
CInArchive *inArchive, bool removeSfx,
|
||||
const CUpdateOptions &updateOptions,
|
||||
const CCompressionMethodMode &compressionMethodMode,
|
||||
IArchiveUpdateCallback *updateCallback);
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user