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:
Simone
2026-04-29 14:07:51 +02:00
commit d074cc7c07
3848 changed files with 1076682 additions and 0 deletions
@@ -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
+449
View File
@@ -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