summaryrefslogtreecommitdiffstats
path: root/src/libs/7zip/win/CPP/7zip/Archive/Zip
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Archive/Zip')
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/StdAfx.h8
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.cpp379
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.h56
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipCompressionMode.h42
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.cpp822
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.h101
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp531
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.cpp36
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.h284
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.cpp893
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.h125
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.cpp172
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.h281
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItemEx.h34
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.cpp289
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.h56
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipRegister.cpp18
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.cpp1068
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.h58
19 files changed, 5253 insertions, 0 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/StdAfx.h
new file mode 100644
index 000000000..e7fb6986d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
new file mode 100644
index 000000000..4c5fd38d1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
@@ -0,0 +1,379 @@
+// ZipAddCommon.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.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 "../Common/InStreamWithCRC.h"
+
+#include "ZipAddCommon.h"
+#include "ZipHeader.h"
+
+namespace NArchive {
+namespace NZip {
+
+static const CMethodId kMethodId_ZipBase = 0x040100;
+static const CMethodId kMethodId_BZip2 = 0x040202;
+
+static const UInt32 kLzmaPropsSize = 5;
+static const UInt32 kLzmaHeaderSize = 4 + kLzmaPropsSize;
+
+class CLzmaEncoder:
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ NCompress::NLzma::CEncoder *EncoderSpec;
+ CMyComPtr<ICompressCoder> Encoder;
+ Byte Header[kLzmaHeaderSize];
+public:
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ HRESULT SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+
+ MY_UNKNOWN_IMP
+};
+
+HRESULT CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+{
+ if (!Encoder)
+ {
+ EncoderSpec = new NCompress::NLzma::CEncoder;
+ Encoder = EncoderSpec;
+ }
+ CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->Init(Header + 4, kLzmaPropsSize);
+ RINOK(EncoderSpec->SetCoderProperties(propIDs, props, numProps));
+ RINOK(EncoderSpec->WriteCoderProperties(outStream));
+ if (outStreamSpec->GetPos() != kLzmaPropsSize)
+ return E_FAIL;
+ Header[0] = MY_VER_MAJOR;
+ Header[1] = MY_VER_MINOR;
+ Header[2] = kLzmaPropsSize;
+ Header[3] = 0;
+ return S_OK;
+}
+
+HRESULT CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ RINOK(WriteStream(outStream, Header, kLzmaHeaderSize));
+ return Encoder->Code(inStream, outStream, inSize, outSize, progress);
+}
+
+
+CAddCommon::CAddCommon(const CCompressionMethodMode &options):
+ _options(options),
+ _copyCoderSpec(NULL),
+ _cryptoStreamSpec(0)
+ {}
+
+static HRESULT GetStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC)
+{
+ UInt32 crc = CRC_INIT_VAL;
+ const UInt32 kBufferSize = (1 << 14);
+ Byte buffer[kBufferSize];
+ for (;;)
+ {
+ UInt32 realProcessedSize;
+ RINOK(inStream->Read(buffer, kBufferSize, &realProcessedSize));
+ if (realProcessedSize == 0)
+ {
+ resultCRC = CRC_GET_DIGEST(crc);
+ return S_OK;
+ }
+ crc = CrcUpdate(crc, buffer, (size_t)realProcessedSize);
+ }
+}
+
+HRESULT CAddCommon::Compress(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream, IOutStream *outStream,
+ ICompressProgressInfo *progress, CCompressingResult &opRes)
+{
+ CSequentialInStreamWithCRC *inSecCrcStreamSpec = 0;
+ CInStreamWithCRC *inCrcStreamSpec = 0;
+ CMyComPtr<ISequentialInStream> inCrcStream;
+ {
+ CMyComPtr<IInStream> inStream2;
+ // we don't support stdin, since stream from stdin can require 64-bit size header
+ RINOK(inStream->QueryInterface(IID_IInStream, (void **)&inStream2));
+ if (inStream2)
+ {
+ inCrcStreamSpec = new CInStreamWithCRC;
+ inCrcStream = inCrcStreamSpec;
+ inCrcStreamSpec->SetStream(inStream2);
+ inCrcStreamSpec->Init();
+ }
+ else
+ {
+ inSecCrcStreamSpec = new CSequentialInStreamWithCRC;
+ inCrcStream = inSecCrcStreamSpec;
+ inSecCrcStreamSpec->SetStream(inStream);
+ inSecCrcStreamSpec->Init();
+ }
+ }
+
+ int numTestMethods = _options.MethodSequence.Size();
+ if (numTestMethods > 1 || _options.PasswordIsDefined)
+ {
+ if (inCrcStreamSpec == 0)
+ {
+ if (_options.PasswordIsDefined)
+ return E_NOTIMPL;
+ numTestMethods = 1;
+ }
+ }
+ Byte method = 0;
+ COutStreamReleaser outStreamReleaser;
+ opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default;
+ for (int i = 0; i < numTestMethods; i++)
+ {
+ opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default;
+ if (inCrcStreamSpec != 0)
+ RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(outStream->SetSize(0));
+ RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL));
+ if (_options.PasswordIsDefined)
+ {
+ opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_ZipCrypto;
+
+ if (!_cryptoStream)
+ {
+ _cryptoStreamSpec = new CFilterCoder;
+ _cryptoStream = _cryptoStreamSpec;
+ }
+ if (_options.IsAesMode)
+ {
+ opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Aes;
+ if (!_cryptoStreamSpec->Filter)
+ {
+ _cryptoStreamSpec->Filter = _filterAesSpec = new NCrypto::NWzAes::CEncoder;
+ _filterAesSpec->SetKeyMode(_options.AesKeyMode);
+ RINOK(_filterAesSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Length()));
+ }
+ RINOK(_filterAesSpec->WriteHeader(outStream));
+ }
+ else
+ {
+ if (!_cryptoStreamSpec->Filter)
+ {
+ _cryptoStreamSpec->Filter = _filterSpec = new NCrypto::NZip::CEncoder;
+ _filterSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Length());
+ }
+ UInt32 crc = 0;
+ RINOK(GetStreamCRC(inStream, crc));
+ RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(_filterSpec->WriteHeader(outStream, crc));
+ }
+ RINOK(_cryptoStreamSpec->SetOutStream(outStream));
+ outStreamReleaser.FilterCoder = _cryptoStreamSpec;
+ }
+
+ method = _options.MethodSequence[i];
+ switch(method)
+ {
+ case NFileHeader::NCompressionMethod::kStored:
+ {
+ if (_copyCoderSpec == NULL)
+ {
+ _copyCoderSpec = new NCompress::CCopyCoder;
+ _copyCoder = _copyCoderSpec;
+ }
+ CMyComPtr<ISequentialOutStream> outStreamNew;
+ if (_options.PasswordIsDefined)
+ outStreamNew = _cryptoStream;
+ else
+ outStreamNew = outStream;
+ RINOK(_copyCoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress));
+ break;
+ }
+ default:
+ {
+ if (!_compressEncoder)
+ {
+ if (method == NFileHeader::NCompressionMethod::kLZMA)
+ {
+ _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_LZMA;
+ CLzmaEncoder *_lzmaEncoder = new CLzmaEncoder();
+ _compressEncoder = _lzmaEncoder;
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ #ifndef _7ZIP_ST
+ _options.NumThreads,
+ #endif
+ _options.Algo,
+ _options.DicSize,
+ _options.NumFastBytes,
+ const_cast<BSTR>((const wchar_t *)_options.MatchFinder),
+ _options.NumMatchFinderCycles
+ };
+ PROPID propIDs[] =
+ {
+ #ifndef _7ZIP_ST
+ NCoderPropID::kNumThreads,
+ #endif
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kNumFastBytes,
+ NCoderPropID::kMatchFinder,
+ NCoderPropID::kMatchFinderCycles
+ };
+ int numProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ if (!_options.NumMatchFinderCyclesDefined)
+ numProps--;
+ RINOK(_lzmaEncoder->SetCoderProperties(propIDs, props, numProps));
+ }
+ else if (method == NFileHeader::NCompressionMethod::kPPMd)
+ {
+ _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_PPMd;
+ NCompress::NPpmdZip::CEncoder *encoder = new NCompress::NPpmdZip::CEncoder();
+ _compressEncoder = encoder;
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ _options.Algo,
+ _options.MemSize,
+ _options.Order
+
+ };
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kUsedMemorySize,
+ NCoderPropID::kOrder
+ };
+ RINOK(encoder->SetCoderProperties(propIDs, props, sizeof(propIDs) / sizeof(propIDs[0])));
+ }
+ else
+ {
+ CMethodId methodId;
+ switch(method)
+ {
+ case NFileHeader::NCompressionMethod::kBZip2:
+ methodId = kMethodId_BZip2;
+ _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_BZip2;
+ break;
+ default:
+ _compressExtractVersion = ((method == NFileHeader::NCompressionMethod::kDeflated64) ?
+ NFileHeader::NCompressionMethod::kExtractVersion_Deflate64 :
+ NFileHeader::NCompressionMethod::kExtractVersion_Deflate);
+ methodId = kMethodId_ZipBase + method;
+ break;
+ }
+ RINOK(CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId, _compressEncoder, true));
+ if (!_compressEncoder)
+ return E_NOTIMPL;
+
+ if (method == NFileHeader::NCompressionMethod::kDeflated ||
+ method == NFileHeader::NCompressionMethod::kDeflated64)
+ {
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ _options.Algo,
+ _options.NumPasses,
+ _options.NumFastBytes,
+ _options.NumMatchFinderCycles
+ };
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kNumPasses,
+ NCoderPropID::kNumFastBytes,
+ NCoderPropID::kMatchFinderCycles
+ };
+ int numProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ if (!_options.NumMatchFinderCyclesDefined)
+ numProps--;
+ CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+ _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties);
+ if (setCoderProperties)
+ {
+ RINOK(setCoderProperties->SetCoderProperties(propIDs, props, numProps));
+ }
+ }
+ else if (method == NFileHeader::NCompressionMethod::kBZip2)
+ {
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ _options.DicSize,
+ _options.NumPasses
+ #ifndef _7ZIP_ST
+ , _options.NumThreads
+ #endif
+ };
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kNumPasses
+ #ifndef _7ZIP_ST
+ , NCoderPropID::kNumThreads
+ #endif
+ };
+ CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+ _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties);
+ if (setCoderProperties)
+ {
+ RINOK(setCoderProperties->SetCoderProperties(propIDs, props, sizeof(propIDs) / sizeof(propIDs[0])));
+ }
+ }
+ }
+ }
+ CMyComPtr<ISequentialOutStream> outStreamNew;
+ if (_options.PasswordIsDefined)
+ outStreamNew = _cryptoStream;
+ else
+ outStreamNew = outStream;
+ if (_compressExtractVersion > opRes.ExtractVersion)
+ opRes.ExtractVersion = _compressExtractVersion;
+ RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress));
+ break;
+ }
+ }
+
+ RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize));
+
+ if (inCrcStreamSpec != 0)
+ {
+ opRes.CRC = inCrcStreamSpec->GetCRC();
+ opRes.UnpackSize = inCrcStreamSpec->GetSize();
+ }
+ else
+ {
+ opRes.CRC = inSecCrcStreamSpec->GetCRC();
+ opRes.UnpackSize = inSecCrcStreamSpec->GetSize();
+ }
+
+ if (_options.PasswordIsDefined)
+ {
+ if (opRes.PackSize < opRes.UnpackSize +
+ (_options.IsAesMode ? _filterAesSpec->GetHeaderSize() : NCrypto::NZip::kHeaderSize))
+ break;
+ }
+ else if (opRes.PackSize < opRes.UnpackSize)
+ break;
+ }
+ if (_options.IsAesMode)
+ {
+ RINOK(_filterAesSpec->WriteFooter(outStream));
+ RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize));
+ }
+ opRes.Method = method;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.h
new file mode 100644
index 000000000..e4c02db3f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.h
@@ -0,0 +1,56 @@
+// ZipAddCommon.h
+
+#ifndef __ZIP_ADD_COMMON_H
+#define __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;
+};
+
+class CAddCommon
+{
+ CCompressionMethodMode _options;
+ NCompress::CCopyCoder *_copyCoderSpec;
+ CMyComPtr<ICompressCoder> _copyCoder;
+
+ CMyComPtr<ICompressCoder> _compressEncoder;
+ Byte _compressExtractVersion;
+
+ CFilterCoder *_cryptoStreamSpec;
+ CMyComPtr<ISequentialOutStream> _cryptoStream;
+
+ NCrypto::NZip::CEncoder *_filterSpec;
+ NCrypto::NWzAes::CEncoder *_filterAesSpec;
+
+public:
+ CAddCommon(const CCompressionMethodMode &options);
+ HRESULT Compress(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream, IOutStream *outStream,
+ ICompressProgressInfo *progress, CCompressingResult &operationResult);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipCompressionMode.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipCompressionMode.h
new file mode 100644
index 000000000..7ef7cfb28
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipCompressionMode.h
@@ -0,0 +1,42 @@
+// CompressionMode.h
+
+#ifndef __ZIP_COMPRESSION_MODE_H
+#define __ZIP_COMPRESSION_MODE_H
+
+#include "Common/MyString.h"
+
+namespace NArchive {
+namespace NZip {
+
+struct CCompressionMethodMode
+{
+ CRecordVector<Byte> MethodSequence;
+ UString MatchFinder;
+ UInt32 Algo;
+ UInt32 NumPasses;
+ UInt32 NumFastBytes;
+ bool NumMatchFinderCyclesDefined;
+ UInt32 NumMatchFinderCycles;
+ UInt32 DicSize;
+ UInt32 MemSize;
+ UInt32 Order;
+
+ #ifndef _7ZIP_ST
+ UInt32 NumThreads;
+ #endif
+ bool PasswordIsDefined;
+ AString Password;
+ bool IsAesMode;
+ Byte AesKeyMode;
+
+ CCompressionMethodMode():
+ NumMatchFinderCyclesDefined(false),
+ PasswordIsDefined(false),
+ IsAesMode(false),
+ AesKeyMode(3)
+ {}
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.cpp
new file mode 100644
index 000000000..bd1563226
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.cpp
@@ -0,0 +1,822 @@
+// ZipHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/FilterCoder.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+#include "../../Compress/LzmaDecoder.h"
+#include "../../Compress/ImplodeDecoder.h"
+#include "../../Compress/PpmdZip.h"
+#include "../../Compress/ShrinkDecoder.h"
+
+#include "../../Crypto/WzAes.h"
+#include "../../Crypto/ZipCrypto.h"
+#include "../../Crypto/ZipStrong.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/OutStreamWithCRC.h"
+
+#include "ZipHandler.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NZip {
+
+static const CMethodId kMethodId_ZipBase = 0x040100;
+static const CMethodId kMethodId_BZip2 = 0x040202;
+
+static const char *kHostOS[] =
+{
+ "FAT",
+ "AMIGA",
+ "VMS",
+ "Unix",
+ "VM/CMS",
+ "Atari",
+ "HPFS",
+ "Macintosh",
+ "Z-System",
+ "CP/M",
+ "TOPS-20",
+ "NTFS",
+ "SMS/QDOS",
+ "Acorn",
+ "VFAT",
+ "MVS",
+ "BeOS",
+ "Tandem",
+ "OS/400",
+ "OS/X"
+};
+
+static const char *kUnknownOS = "Unknown";
+
+static const char *kMethods[] =
+{
+ "Store",
+ "Shrink",
+ "Reduced1",
+ "Reduced2",
+ "Reduced3",
+ "Reduced4",
+ "Implode",
+ "Tokenizing",
+ "Deflate",
+ "Deflate64",
+ "PKImploding"
+};
+
+static const char *kBZip2Method = "BZip2";
+static const char *kLZMAMethod = "LZMA";
+static const char *kJpegMethod = "Jpeg";
+static const char *kWavPackMethod = "WavPack";
+static const char *kPPMdMethod = "PPMd";
+static const char *kAESMethod = "AES";
+static const char *kZipCryptoMethod = "ZipCrypto";
+static const char *kStrongCryptoMethod = "StrongCrypto";
+
+static struct CStrongCryptoPair
+{
+ UInt16 Id;
+ const char *Name;
+} g_StrongCryptoPairs[] =
+{
+ { NStrongCryptoFlags::kDES, "DES" },
+ { NStrongCryptoFlags::kRC2old, "RC2a" },
+ { NStrongCryptoFlags::k3DES168, "3DES-168" },
+ { NStrongCryptoFlags::k3DES112, "3DES-112" },
+ { NStrongCryptoFlags::kAES128, "pkAES-128" },
+ { NStrongCryptoFlags::kAES192, "pkAES-192" },
+ { NStrongCryptoFlags::kAES256, "pkAES-256" },
+ { NStrongCryptoFlags::kRC2, "RC2" },
+ { NStrongCryptoFlags::kBlowfish, "Blowfish" },
+ { NStrongCryptoFlags::kTwofish, "Twofish" },
+ { NStrongCryptoFlags::kRC4, "RC4" }
+};
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidEncrypted, VT_BOOL},
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidCRC, VT_UI4},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidHostOS, VT_BSTR},
+ { NULL, kpidUnpackVer, VT_UI4}
+};
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidBit64, VT_BOOL},
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidOffset, VT_UI8}
+};
+
+CHandler::CHandler()
+{
+ InitMethodProperties();
+}
+
+static AString BytesToString(const CByteBuffer &data)
+{
+ AString s;
+ int size = (int)data.GetCapacity();
+ if (size > 0)
+ {
+ char *p = s.GetBuffer(size + 1);
+ memcpy(p, (const Byte *)data, size);
+ p[size] = '\0';
+ s.ReleaseBuffer();
+ }
+ return s;
+}
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break;
+ case kpidComment: prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break;
+ case kpidPhySize: prop = m_Archive.ArcInfo.GetPhySize(); break;
+ case kpidOffset: if (m_Archive.ArcInfo.StartPosition != 0) prop = m_Archive.ArcInfo.StartPosition; break;
+ }
+ prop.Detach(value);
+ COM_TRY_END
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = m_Items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItemEx &item = m_Items[index];
+ switch(propID)
+ {
+ case kpidPath: prop = NItemName::GetOSName2(item.GetUnicodeString(item.Name)); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.UnPackSize; break;
+ case kpidPackSize: prop = item.PackSize; break;
+ case kpidTimeType:
+ {
+ FILETIME ft;
+ UInt32 unixTime;
+ if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft))
+ prop = (UInt32)NFileTimeType::kWindows;
+ else if (item.CentralExtra.GetUnixTime(NFileHeader::NUnixTime::kMTime, unixTime))
+ prop = (UInt32)NFileTimeType::kUnix;
+ else
+ prop = (UInt32)NFileTimeType::kDOS;
+ break;
+ }
+ case kpidCTime:
+ {
+ FILETIME ft;
+ if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, ft))
+ prop = ft;
+ break;
+ }
+ case kpidATime:
+ {
+ FILETIME ft;
+ if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, ft))
+ prop = ft;
+ break;
+ }
+ case kpidMTime:
+ {
+ FILETIME utc;
+ if (!item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc))
+ {
+ UInt32 unixTime;
+ if (item.CentralExtra.GetUnixTime(NFileHeader::NUnixTime::kMTime, unixTime))
+ NTime::UnixTimeToFileTime(unixTime, utc);
+ else
+ {
+ FILETIME localFileTime;
+ if (!NTime::DosTimeToFileTime(item.Time, localFileTime) ||
+ !LocalFileTimeToFileTime(&localFileTime, &utc))
+ utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ }
+ }
+ prop = utc;
+ break;
+ }
+ case kpidAttrib: prop = item.GetWinAttributes(); break;
+ case kpidEncrypted: prop = item.IsEncrypted(); break;
+ case kpidComment: prop = item.GetUnicodeString(BytesToString(item.Comment)); break;
+ case kpidCRC: if (item.IsThereCrc()) prop = item.FileCRC; break;
+ case kpidMethod:
+ {
+ UInt16 methodId = item.CompressionMethod;
+ AString method;
+ if (item.IsEncrypted())
+ {
+ if (methodId == NFileHeader::NCompressionMethod::kWzAES)
+ {
+ method = kAESMethod;
+ CWzAesExtraField aesField;
+ if (item.CentralExtra.GetWzAesField(aesField))
+ {
+ method += '-';
+ char s[32];
+ ConvertUInt64ToString((aesField.Strength + 1) * 64 , s);
+ method += s;
+ method += ' ';
+ methodId = aesField.Method;
+ }
+ }
+ else
+ {
+ if (item.IsStrongEncrypted())
+ {
+ CStrongCryptoField f;
+ bool finded = false;
+ if (item.CentralExtra.GetStrongCryptoField(f))
+ {
+ for (int i = 0; i < sizeof(g_StrongCryptoPairs) / sizeof(g_StrongCryptoPairs[0]); i++)
+ {
+ const CStrongCryptoPair &pair = g_StrongCryptoPairs[i];
+ if (f.AlgId == pair.Id)
+ {
+ method += pair.Name;
+ finded = true;
+ break;
+ }
+ }
+ }
+ if (!finded)
+ method += kStrongCryptoMethod;
+ }
+ else
+ method += kZipCryptoMethod;
+ method += ' ';
+ }
+ }
+ if (methodId < sizeof(kMethods) / sizeof(kMethods[0]))
+ method += kMethods[methodId];
+ else switch (methodId)
+ {
+ case NFileHeader::NCompressionMethod::kLZMA:
+ method += kLZMAMethod;
+ if (item.IsLzmaEOS())
+ method += ":EOS";
+ break;
+ case NFileHeader::NCompressionMethod::kBZip2: method += kBZip2Method; break;
+ case NFileHeader::NCompressionMethod::kJpeg: method += kJpegMethod; break;
+ case NFileHeader::NCompressionMethod::kWavPack: method += kWavPackMethod; break;
+ case NFileHeader::NCompressionMethod::kPPMd: method += kPPMdMethod; break;
+ default:
+ {
+ char s[32];
+ ConvertUInt64ToString(methodId, s);
+ method += s;
+ }
+ }
+ prop = method;
+ break;
+ }
+ case kpidHostOS:
+ prop = (item.MadeByVersion.HostOS < sizeof(kHostOS) / sizeof(kHostOS[0])) ?
+ (kHostOS[item.MadeByVersion.HostOS]) : kUnknownOS;
+ break;
+ case kpidUnpackVer:
+ prop = (UInt32)item.ExtractVersion.Version;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CProgressImp: public CProgressVirt
+{
+ CMyComPtr<IArchiveOpenCallback> _callback;
+public:
+ STDMETHOD(SetTotal)(UInt64 numFiles);
+ STDMETHOD(SetCompleted)(UInt64 numFiles);
+ CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {}
+};
+
+STDMETHODIMP CProgressImp::SetTotal(UInt64 numFiles)
+{
+ if (_callback)
+ return _callback->SetTotal(&numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CProgressImp::SetCompleted(UInt64 numFiles)
+{
+ if (_callback)
+ return _callback->SetCompleted(&numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ try
+ {
+ Close();
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(m_Archive.Open(inStream, maxCheckStartPosition));
+ CProgressImp progressImp(callback);
+ return m_Archive.ReadHeaders(m_Items, &progressImp);
+ }
+ catch(const CInArchiveException &) { Close(); return S_FALSE; }
+ catch(...) { Close(); throw; }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ m_Items.Clear();
+ m_Archive.Close();
+ return S_OK;
+}
+
+//////////////////////////////////////
+// CHandler::DecompressItems
+
+class CLzmaDecoder:
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ NCompress::NLzma::CDecoder *DecoderSpec;
+ CMyComPtr<ICompressCoder> Decoder;
+public:
+ CLzmaDecoder();
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ MY_UNKNOWN_IMP
+};
+
+CLzmaDecoder::CLzmaDecoder()
+{
+ DecoderSpec = new NCompress::NLzma::CDecoder;
+ Decoder = DecoderSpec;
+}
+
+HRESULT CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ Byte buf[9];
+ RINOK(ReadStream_FALSE(inStream, buf, 9));
+ if (buf[2] != 5 || buf[3] != 0)
+ return E_NOTIMPL;
+ RINOK(DecoderSpec->SetDecoderProperties2(buf + 4, 5));
+ return Decoder->Code(inStream, outStream, NULL, outSize, progress);
+}
+
+struct CMethodItem
+{
+ UInt16 ZipMethod;
+ CMyComPtr<ICompressCoder> Coder;
+};
+
+class CZipDecoder
+{
+ NCrypto::NZip::CDecoder *_zipCryptoDecoderSpec;
+ NCrypto::NZipStrong::CDecoder *_pkAesDecoderSpec;
+ NCrypto::NWzAes::CDecoder *_wzAesDecoderSpec;
+
+ CMyComPtr<ICompressFilter> _zipCryptoDecoder;
+ CMyComPtr<ICompressFilter> _pkAesDecoder;
+ CMyComPtr<ICompressFilter> _wzAesDecoder;
+
+ CFilterCoder *filterStreamSpec;
+ CMyComPtr<ISequentialInStream> filterStream;
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ CObjectVector<CMethodItem> methodItems;
+
+public:
+ CZipDecoder():
+ _zipCryptoDecoderSpec(0),
+ _pkAesDecoderSpec(0),
+ _wzAesDecoderSpec(0),
+ filterStreamSpec(0) {}
+
+ HRESULT Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CInArchive &archive, const CItemEx &item,
+ ISequentialOutStream *realOutStream,
+ IArchiveExtractCallback *extractCallback,
+ ICompressProgressInfo *compressProgress,
+ UInt32 numThreads, Int32 &res);
+};
+
+HRESULT CZipDecoder::Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CInArchive &archive, const CItemEx &item,
+ ISequentialOutStream *realOutStream,
+ IArchiveExtractCallback *extractCallback,
+ ICompressProgressInfo *compressProgress,
+ UInt32 numThreads, Int32 &res)
+{
+ res = NExtract::NOperationResult::kDataError;
+ CInStreamReleaser inStreamReleaser;
+
+ bool needCRC = true;
+ bool wzAesMode = false;
+ bool pkAesMode = false;
+ UInt16 methodId = item.CompressionMethod;
+ if (item.IsEncrypted())
+ {
+ if (item.IsStrongEncrypted())
+ {
+ CStrongCryptoField f;
+ if (item.CentralExtra.GetStrongCryptoField(f))
+ {
+ pkAesMode = true;
+ }
+ if (!pkAesMode)
+ {
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ return S_OK;
+ }
+ }
+ if (methodId == NFileHeader::NCompressionMethod::kWzAES)
+ {
+ CWzAesExtraField aesField;
+ if (item.CentralExtra.GetWzAesField(aesField))
+ {
+ wzAesMode = true;
+ needCRC = aesField.NeedCrc();
+ }
+ }
+ }
+
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init(needCRC);
+
+ UInt64 authenticationPos;
+
+ CMyComPtr<ISequentialInStream> inStream;
+ {
+ UInt64 packSize = item.PackSize;
+ if (wzAesMode)
+ {
+ if (packSize < NCrypto::NWzAes::kMacSize)
+ return S_OK;
+ packSize -= NCrypto::NWzAes::kMacSize;
+ }
+ UInt64 dataPos = item.GetDataPosition();
+ inStream.Attach(archive.CreateLimitedStream(dataPos, packSize));
+ authenticationPos = dataPos + packSize;
+ }
+
+ CMyComPtr<ICompressFilter> cryptoFilter;
+ if (item.IsEncrypted())
+ {
+ if (wzAesMode)
+ {
+ CWzAesExtraField aesField;
+ if (!item.CentralExtra.GetWzAesField(aesField))
+ return S_OK;
+ methodId = aesField.Method;
+ if (!_wzAesDecoder)
+ {
+ _wzAesDecoderSpec = new NCrypto::NWzAes::CDecoder;
+ _wzAesDecoder = _wzAesDecoderSpec;
+ }
+ cryptoFilter = _wzAesDecoder;
+ Byte properties = aesField.Strength;
+ RINOK(_wzAesDecoderSpec->SetDecoderProperties2(&properties, 1));
+ }
+ else if (pkAesMode)
+ {
+ if (!_pkAesDecoder)
+ {
+ _pkAesDecoderSpec = new NCrypto::NZipStrong::CDecoder;
+ _pkAesDecoder = _pkAesDecoderSpec;
+ }
+ cryptoFilter = _pkAesDecoder;
+ }
+ else
+ {
+ if (!_zipCryptoDecoder)
+ {
+ _zipCryptoDecoderSpec = new NCrypto::NZip::CDecoder;
+ _zipCryptoDecoder = _zipCryptoDecoderSpec;
+ }
+ cryptoFilter = _zipCryptoDecoder;
+ }
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword));
+
+ if (!getTextPassword)
+ extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
+
+ if (getTextPassword)
+ {
+ CMyComBSTR password;
+ RINOK(getTextPassword->CryptoGetTextPassword(&password));
+ AString charPassword;
+ if (wzAesMode || pkAesMode)
+ {
+ charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP);
+ /*
+ for (int i = 0;; i++)
+ {
+ wchar_t c = password[i];
+ if (c == 0)
+ break;
+ if (c >= 0x80)
+ {
+ res = NExtract::NOperationResult::kDataError;
+ return S_OK;
+ }
+ charPassword += (char)c;
+ }
+ */
+ }
+ else
+ {
+ // we use OEM. WinZip/Windows probably use ANSI for some files
+ charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
+ }
+ HRESULT result = cryptoSetPassword->CryptoSetPassword(
+ (const Byte *)(const char *)charPassword, charPassword.Length());
+ if (result != S_OK)
+ return S_OK;
+ }
+ else
+ {
+ RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
+ }
+ }
+
+ int m;
+ for (m = 0; m < methodItems.Size(); m++)
+ if (methodItems[m].ZipMethod == methodId)
+ break;
+
+ if (m == methodItems.Size())
+ {
+ CMethodItem mi;
+ mi.ZipMethod = methodId;
+ if (methodId == NFileHeader::NCompressionMethod::kStored)
+ mi.Coder = new NCompress::CCopyCoder;
+ else if (methodId == NFileHeader::NCompressionMethod::kShrunk)
+ mi.Coder = new NCompress::NShrink::CDecoder;
+ else if (methodId == NFileHeader::NCompressionMethod::kImploded)
+ mi.Coder = new NCompress::NImplode::NDecoder::CCoder;
+ else if (methodId == NFileHeader::NCompressionMethod::kLZMA)
+ mi.Coder = new CLzmaDecoder;
+ else if (methodId == NFileHeader::NCompressionMethod::kPPMd)
+ mi.Coder = new NCompress::NPpmdZip::CDecoder(true);
+ else
+ {
+ CMethodId szMethodID;
+ if (methodId == NFileHeader::NCompressionMethod::kBZip2)
+ szMethodID = kMethodId_BZip2;
+ else
+ {
+ if (methodId > 0xFF)
+ {
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ return S_OK;
+ }
+ szMethodID = kMethodId_ZipBase + (Byte)methodId;
+ }
+
+ RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, mi.Coder, false));
+
+ if (mi.Coder == 0)
+ {
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ return S_OK;
+ }
+ }
+ m = methodItems.Add(mi);
+ }
+ ICompressCoder *coder = methodItems[m].Coder;
+
+ {
+ CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+ coder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties);
+ if (setDecoderProperties)
+ {
+ Byte properties = (Byte)item.Flags;
+ RINOK(setDecoderProperties->SetDecoderProperties2(&properties, 1));
+ }
+ }
+
+ #ifndef _7ZIP_ST
+ {
+ CMyComPtr<ICompressSetCoderMt> setCoderMt;
+ coder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt);
+ if (setCoderMt)
+ {
+ RINOK(setCoderMt->SetNumberOfThreads(numThreads));
+ }
+ }
+ #endif
+
+ {
+ HRESULT result = S_OK;
+ CMyComPtr<ISequentialInStream> inStreamNew;
+ if (item.IsEncrypted())
+ {
+ if (!filterStream)
+ {
+ filterStreamSpec = new CFilterCoder;
+ filterStream = filterStreamSpec;
+ }
+ filterStreamSpec->Filter = cryptoFilter;
+ if (wzAesMode)
+ {
+ result = _wzAesDecoderSpec->ReadHeader(inStream);
+ }
+ else if (pkAesMode)
+ {
+ result =_pkAesDecoderSpec->ReadHeader(inStream, item.FileCRC, item.UnPackSize);
+ if (result == S_OK)
+ {
+ bool passwOK;
+ result = _pkAesDecoderSpec->CheckPassword(passwOK);
+ if (result == S_OK && !passwOK)
+ result = S_FALSE;
+ }
+ }
+ else
+ {
+ result = _zipCryptoDecoderSpec->ReadHeader(inStream);
+ }
+
+ if (result == S_OK)
+ {
+ RINOK(filterStreamSpec->SetInStream(inStream));
+ inStreamReleaser.FilterCoder = filterStreamSpec;
+ inStreamNew = filterStream;
+ if (wzAesMode)
+ {
+ if (!_wzAesDecoderSpec->CheckPasswordVerifyCode())
+ result = S_FALSE;
+ }
+ }
+ }
+ else
+ inStreamNew = inStream;
+ if (result == S_OK)
+ result = coder->Code(inStreamNew, outStream, NULL, &item.UnPackSize, compressProgress);
+ if (result == S_FALSE)
+ return S_OK;
+ if (result == E_NOTIMPL)
+ {
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ return S_OK;
+ }
+
+ RINOK(result);
+ }
+ bool crcOK = true;
+ bool authOk = true;
+ if (needCRC)
+ crcOK = (outStreamSpec->GetCRC() == item.FileCRC);
+ if (wzAesMode)
+ {
+ inStream.Attach(archive.CreateLimitedStream(authenticationPos, NCrypto::NWzAes::kMacSize));
+ if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK)
+ authOk = false;
+ }
+
+ res = ((crcOK && authOk) ?
+ NExtract::NOperationResult::kOK :
+ NExtract::NOperationResult::kCRCError);
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ CZipDecoder myDecoder;
+ UInt64 totalUnPacked = 0, totalPacked = 0;
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = m_Items.Size();
+ if(numItems == 0)
+ return S_OK;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItemEx &item = m_Items[allFilesMode ? i : indices[i]];
+ totalUnPacked += item.UnPackSize;
+ totalPacked += item.PackSize;
+ }
+ RINOK(extractCallback->SetTotal(totalUnPacked));
+
+ UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;
+ UInt64 currentItemUnPacked, currentItemPacked;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,
+ currentTotalPacked += currentItemPacked)
+ {
+ currentItemUnPacked = 0;
+ currentItemPacked = 0;
+
+ lps->InSize = currentTotalPacked;
+ lps->OutSize = currentTotalUnPacked;
+ RINOK(lps->SetCur());
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ CItemEx item = m_Items[index];
+ if (!item.FromLocal)
+ {
+ HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item);
+ if (res == S_FALSE)
+ {
+ if (item.IsDir() || realOutStream || testMode)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ }
+ continue;
+ }
+ RINOK(res);
+ }
+
+ if (item.IsDir() || item.IgnoreItem())
+ {
+ // if (!testMode)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ continue;
+ }
+
+ currentItemUnPacked = item.UnPackSize;
+ currentItemPacked = item.PackSize;
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ Int32 res;
+ RINOK(myDecoder.Decode(
+ EXTERNAL_CODECS_VARS
+ m_Archive, item, realOutStream, extractCallback,
+ progress, _numThreads, res));
+ realOutStream.Release();
+
+ RINOK(extractCallback->SetOperationResult(res))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.h
new file mode 100644
index 000000000..fdb60aafe
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.h
@@ -0,0 +1,101 @@
+// Zip/Handler.h
+
+#ifndef __ZIP_HANDLER_H
+#define __ZIP_HANDLER_H
+
+#include "Common/DynamicBuffer.h"
+#include "../../ICoder.h"
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "ZipIn.h"
+#include "ZipCompressionMode.h"
+
+#ifndef _7ZIP_ST
+#include "../../../Windows/System.h"
+#endif
+
+namespace NArchive {
+namespace NZip {
+
+class CHandler:
+ public IInArchive,
+ public IOutArchive,
+ public ISetProperties,
+ PUBLIC_ISetCompressCodecsInfo
+ public CMyUnknownImp
+{
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ MY_QUERYINTERFACE_ENTRY(IOutArchive)
+ MY_QUERYINTERFACE_ENTRY(ISetProperties)
+ QUERY_ENTRY_ISetCompressCodecsInfo
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+ INTERFACE_IOutArchive(;)
+
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties);
+
+ DECL_ISetCompressCodecsInfo
+
+ CHandler();
+private:
+ CObjectVector<CItemEx> m_Items;
+ CInArchive m_Archive;
+
+ int m_Level;
+ int m_MainMethod;
+ UInt32 m_DicSize;
+ UInt32 m_Algo;
+ UInt32 m_NumPasses;
+ UInt32 m_NumFastBytes;
+ UInt32 m_NumMatchFinderCycles;
+ UInt32 m_MemSize;
+ UInt32 m_Order;
+
+ bool m_NumMatchFinderCyclesDefined;
+
+ bool m_ForceAesMode;
+ bool m_IsAesMode;
+ Byte m_AesKeyMode;
+
+ bool m_WriteNtfsTimeExtra;
+ bool m_ForceLocal;
+ bool m_ForceUtf8;
+
+ #ifndef _7ZIP_ST
+ UInt32 _numThreads;
+ #endif
+
+ DECL_EXTERNAL_CODECS_VARS
+
+ void InitMethodProperties()
+ {
+ m_Level = -1;
+ m_MainMethod = -1;
+ m_Algo =
+ m_DicSize =
+ m_NumPasses =
+ m_NumFastBytes =
+ m_Order =
+ m_MemSize =
+ m_NumMatchFinderCycles = 0xFFFFFFFF;
+ m_NumMatchFinderCyclesDefined = false;
+ m_ForceAesMode = false;
+ m_IsAesMode = false;
+ m_AesKeyMode = 3; // aes-256
+ m_WriteNtfsTimeExtra = true;
+ m_ForceLocal = false;
+ m_ForceUtf8 = false;
+ #ifndef _7ZIP_ST
+ _numThreads = NWindows::NSystem::GetNumberOfProcessors();;
+ #endif
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
new file mode 100644
index 000000000..a5e0f59d7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
@@ -0,0 +1,531 @@
+// ZipHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.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 {
+
+static const UInt32 kLzAlgoX1 = 0;
+static const UInt32 kLzAlgoX5 = 1;
+
+static const UInt32 kDeflateNumPassesX1 = 1;
+static const UInt32 kDeflateNumPassesX7 = 3;
+static const UInt32 kDeflateNumPassesX9 = 10;
+
+static const UInt32 kDeflateNumFastBytesX1 = 32;
+static const UInt32 kDeflateNumFastBytesX7 = 64;
+static const UInt32 kDeflateNumFastBytesX9 = 128;
+
+static const wchar_t *kLzmaMatchFinderX1 = L"HC4";
+static const wchar_t *kLzmaMatchFinderX5 = L"BT4";
+
+static const UInt32 kLzmaNumFastBytesX1 = 32;
+static const UInt32 kLzmaNumFastBytesX7 = 64;
+
+static const UInt32 kLzmaDicSizeX1 = 1 << 16;
+static const UInt32 kLzmaDicSizeX3 = 1 << 20;
+static const UInt32 kLzmaDicSizeX5 = 1 << 24;
+static const UInt32 kLzmaDicSizeX7 = 1 << 25;
+static const UInt32 kLzmaDicSizeX9 = 1 << 26;
+
+static const UInt32 kBZip2NumPassesX1 = 1;
+static const UInt32 kBZip2NumPassesX7 = 2;
+static const UInt32 kBZip2NumPassesX9 = 7;
+
+static const UInt32 kBZip2DicSizeX1 = 100000;
+static const UInt32 kBZip2DicSizeX3 = 500000;
+static const UInt32 kBZip2DicSizeX5 = 900000;
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
+{
+ *timeType = NFileTimeType::kDOS;
+ return S_OK;
+}
+
+static bool IsAsciiString(const UString &s)
+{
+ for (int i = 0; i < s.Length(); i++)
+ {
+ wchar_t c = s[i];
+ if (c < 0x20 || c > 0x7F)
+ return false;
+ }
+ return true;
+}
+
+#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, int 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;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *callback)
+{
+ COM_TRY_BEGIN2
+ CObjectVector<CUpdateItem> updateItems;
+ bool thereAreAesUpdates = false;
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ CUpdateItem ui;
+ Int32 newData;
+ Int32 newProperties;
+ UInt32 indexInArchive;
+ if (!callback)
+ return E_FAIL;
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProperties, &indexInArchive));
+ ui.NewProperties = IntToBool(newProperties);
+ ui.NewData = IntToBool(newData);
+ ui.IndexInArchive = indexInArchive;
+ ui.IndexInClient = i;
+ bool existInArchive = (indexInArchive != (UInt32)-1);
+ if (existInArchive && newData)
+ if (m_Items[indexInArchive].IsAesEncrypted())
+ thereAreAesUpdates = true;
+
+ if (IntToBool(newProperties))
+ {
+ UString name;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidAttrib, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.Attributes = 0;
+ else if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ else
+ ui.Attributes = 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);
+ }
+
+ {
+ CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidTimeType, &prop));
+ if (prop.vt == VT_UI4)
+ ui.NtfsTimeIsDefined = (prop.ulVal == NFileTimeType::kWindows);
+ else
+ ui.NtfsTimeIsDefined = m_WriteNtfsTimeExtra;
+ }
+ RINOK(GetTime(callback, i, kpidMTime, ui.NtfsMTime));
+ RINOK(GetTime(callback, i, kpidATime, ui.NtfsATime));
+ RINOK(GetTime(callback, i, kpidCTime, ui.NtfsCTime));
+
+ {
+ FILETIME localFileTime = { 0, 0 };
+ if (ui.NtfsMTime.dwHighDateTime != 0 ||
+ ui.NtfsMTime.dwLowDateTime != 0)
+ if (!FileTimeToLocalFileTime(&ui.NtfsMTime, &localFileTime))
+ return E_INVALIDARG;
+ FileTimeToDosTime(localFileTime, ui.Time);
+ }
+
+ name = NItemName::MakeLegalName(name);
+ bool needSlash = ui.IsDir;
+ const wchar_t kSlash = L'/';
+ if (!name.IsEmpty())
+ {
+ if (name[name.Length() - 1] == kSlash)
+ {
+ if (!ui.IsDir)
+ return E_INVALIDARG;
+ needSlash = false;
+ }
+ }
+ if (needSlash)
+ name += kSlash;
+
+ bool tryUtf8 = true;
+ if (m_ForceLocal || !m_ForceUtf8)
+ {
+ bool defaultCharWasUsed;
+ ui.Name = UnicodeStringToMultiByte(name, CP_OEMCP, '_', defaultCharWasUsed);
+ tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed ||
+ MultiByteToUnicodeString(ui.Name, CP_OEMCP) != name));
+ }
+
+ if (tryUtf8)
+ {
+ int i;
+ for (i = 0; i < name.Length() && (unsigned)name[i] < 0x80; i++);
+ ui.IsUtf8 = (i != name.Length());
+ if (!ConvertUnicodeToUTF8(name, ui.Name))
+ return E_INVALIDARG;
+ }
+
+ if (ui.Name.Length() >= (1 << 16))
+ return E_INVALIDARG;
+
+ ui.IndexInClient = i;
+ /*
+ if (existInArchive)
+ {
+ const CItemEx &itemInfo = m_Items[indexInArchive];
+ // 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;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+ ui.Size = size;
+ }
+ updateItems.Add(ui);
+ }
+
+ CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
+ {
+ CMyComPtr<IArchiveUpdateCallback> udateCallBack2(callback);
+ udateCallBack2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword);
+ }
+ CCompressionMethodMode options;
+
+ if (getTextPassword)
+ {
+ CMyComBSTR password;
+ Int32 passwordIsDefined;
+ RINOK(getTextPassword->CryptoGetTextPassword2(&passwordIsDefined, &password));
+ options.PasswordIsDefined = IntToBool(passwordIsDefined);
+ if (options.PasswordIsDefined)
+ {
+ options.IsAesMode = (m_ForceAesMode ? m_IsAesMode : thereAreAesUpdates);
+ options.AesKeyMode = m_AesKeyMode;
+
+ if (!IsAsciiString((const wchar_t *)password))
+ return E_INVALIDARG;
+ if (options.IsAesMode)
+ {
+ if (options.Password.Length() > NCrypto::NWzAes::kPasswordSizeMax)
+ return E_INVALIDARG;
+ }
+ options.Password = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
+ }
+ }
+ else
+ options.PasswordIsDefined = false;
+
+ int level = m_Level;
+ if (level < 0)
+ level = 5;
+
+ Byte mainMethod;
+ if (m_MainMethod < 0)
+ mainMethod = (Byte)(((level == 0) ?
+ NFileHeader::NCompressionMethod::kStored :
+ NFileHeader::NCompressionMethod::kDeflated));
+ else
+ mainMethod = (Byte)m_MainMethod;
+ options.MethodSequence.Add(mainMethod);
+ if (mainMethod != NFileHeader::NCompressionMethod::kStored)
+ options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStored);
+ bool isDeflate = (mainMethod == NFileHeader::NCompressionMethod::kDeflated) ||
+ (mainMethod == NFileHeader::NCompressionMethod::kDeflated64);
+ bool isLZMA = (mainMethod == NFileHeader::NCompressionMethod::kLZMA);
+ bool isLz = (isLZMA || isDeflate);
+ options.NumPasses = m_NumPasses;
+ options.DicSize = m_DicSize;
+ options.NumFastBytes = m_NumFastBytes;
+ options.NumMatchFinderCycles = m_NumMatchFinderCycles;
+ options.NumMatchFinderCyclesDefined = m_NumMatchFinderCyclesDefined;
+ options.Algo = m_Algo;
+ options.MemSize = m_MemSize;
+ options.Order = m_Order;
+ #ifndef _7ZIP_ST
+ options.NumThreads = _numThreads;
+ #endif
+ if (isLz)
+ {
+ if (isDeflate)
+ {
+ if (options.NumPasses == 0xFFFFFFFF)
+ options.NumPasses = (level >= 9 ? kDeflateNumPassesX9 :
+ (level >= 7 ? kDeflateNumPassesX7 :
+ kDeflateNumPassesX1));
+ if (options.NumFastBytes == 0xFFFFFFFF)
+ options.NumFastBytes = (level >= 9 ? kDeflateNumFastBytesX9 :
+ (level >= 7 ? kDeflateNumFastBytesX7 :
+ kDeflateNumFastBytesX1));
+ }
+ else if (isLZMA)
+ {
+ if (options.DicSize == 0xFFFFFFFF)
+ options.DicSize =
+ (level >= 9 ? kLzmaDicSizeX9 :
+ (level >= 7 ? kLzmaDicSizeX7 :
+ (level >= 5 ? kLzmaDicSizeX5 :
+ (level >= 3 ? kLzmaDicSizeX3 :
+ kLzmaDicSizeX1))));
+
+ if (options.NumFastBytes == 0xFFFFFFFF)
+ options.NumFastBytes = (level >= 7 ? kLzmaNumFastBytesX7 :
+ kLzmaNumFastBytesX1);
+
+ options.MatchFinder =
+ (level >= 5 ? kLzmaMatchFinderX5 :
+ kLzmaMatchFinderX1);
+ }
+
+ if (options.Algo == 0xFFFFFFFF)
+ options.Algo = (level >= 5 ? kLzAlgoX5 :
+ kLzAlgoX1);
+ }
+ if (mainMethod == NFileHeader::NCompressionMethod::kBZip2)
+ {
+ if (options.NumPasses == 0xFFFFFFFF)
+ options.NumPasses = (level >= 9 ? kBZip2NumPassesX9 :
+ (level >= 7 ? kBZip2NumPassesX7 :
+ kBZip2NumPassesX1));
+ if (options.DicSize == 0xFFFFFFFF)
+ options.DicSize = (level >= 5 ? kBZip2DicSizeX5 :
+ (level >= 3 ? kBZip2DicSizeX3 :
+ kBZip2DicSizeX1));
+ }
+ if (mainMethod == NFileHeader::NCompressionMethod::kPPMd)
+ {
+ int level2 = level;
+ if (level2 < 1) level2 = 1;
+ if (level2 > 9) level2 = 9;
+
+ if (options.MemSize == 0xFFFFFFFF)
+ options.MemSize = (1 << (19 + (level2 > 8 ? 8 : level2)));
+
+ if (options.Order == 0xFFFFFFFF)
+ options.Order = 3 + level2;
+
+ if (options.Algo == 0xFFFFFFFF)
+ options.Algo = (level2 >= 7 ? 1 : 0);
+ }
+
+ return Update(
+ EXTERNAL_CODECS_VARS
+ m_Items, updateItems, outStream,
+ m_Archive.IsOpen() ? &m_Archive : NULL, &options, callback);
+ COM_TRY_END2
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
+{
+ #ifndef _7ZIP_ST
+ const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
+ _numThreads = numProcessors;
+ #endif
+ InitMethodProperties();
+ for (int i = 0; i < numProperties; i++)
+ {
+ UString name = UString(names[i]);
+ name.MakeUpper();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ const PROPVARIANT &prop = values[i];
+
+ if (name[0] == L'X')
+ {
+ UInt32 level = 9;
+ RINOK(ParsePropValue(name.Mid(1), prop, level));
+ m_Level = level;
+ continue;
+ }
+ else if (name == L"M")
+ {
+ if (prop.vt == VT_BSTR)
+ {
+ UString m = prop.bstrVal;
+ m.MakeUpper();
+ if (m == L"COPY") m_MainMethod = NFileHeader::NCompressionMethod::kStored;
+ else if (m == L"DEFLATE") m_MainMethod = NFileHeader::NCompressionMethod::kDeflated;
+ else if (m == L"DEFLATE64") m_MainMethod = NFileHeader::NCompressionMethod::kDeflated64;
+ else if (m == L"BZIP2") m_MainMethod = NFileHeader::NCompressionMethod::kBZip2;
+ else if (m == L"LZMA") m_MainMethod = NFileHeader::NCompressionMethod::kLZMA;
+ else if (m == L"PPMD") m_MainMethod = NFileHeader::NCompressionMethod::kPPMd;
+ else return E_INVALIDARG;
+ }
+ else if (prop.vt == VT_UI4)
+ {
+ switch(prop.ulVal)
+ {
+ case NFileHeader::NCompressionMethod::kStored:
+ case NFileHeader::NCompressionMethod::kDeflated:
+ case NFileHeader::NCompressionMethod::kDeflated64:
+ case NFileHeader::NCompressionMethod::kBZip2:
+ case NFileHeader::NCompressionMethod::kLZMA:
+ m_MainMethod = (Byte)prop.ulVal;
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ else
+ return E_INVALIDARG;
+ }
+ else if (name.Left(2) == L"EM")
+ {
+ if (prop.vt == VT_BSTR)
+ {
+ UString valueString = prop.bstrVal;
+ valueString.MakeUpper();
+ if (valueString.Left(3) == L"AES")
+ {
+ valueString = valueString.Mid(3);
+ if (valueString == L"128")
+ m_AesKeyMode = 1;
+ else if (valueString == L"192")
+ m_AesKeyMode = 2;
+ else if (valueString == L"256" || valueString.IsEmpty())
+ m_AesKeyMode = 3;
+ else
+ return E_INVALIDARG;
+ m_IsAesMode = true;
+ m_ForceAesMode = true;
+ }
+ else if (valueString == L"ZIPCRYPTO")
+ {
+ m_IsAesMode = false;
+ m_ForceAesMode = true;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ else if (name[0] == L'D')
+ {
+ UInt32 dicSize = kBZip2DicSizeX5;
+ RINOK(ParsePropDictionaryValue(name.Mid(1), prop, dicSize));
+ m_DicSize = dicSize;
+ }
+ else if (name.Left(3) == L"MEM")
+ {
+ UInt32 memSize = 1 << 24;
+ RINOK(ParsePropDictionaryValue(name.Mid(3), prop, memSize));
+ m_MemSize = memSize;
+ }
+ else if (name[0] == L'O')
+ {
+ UInt32 order = 8;
+ RINOK(ParsePropValue(name.Mid(1), prop, order));
+ m_Order = order;
+ }
+ else if (name.Left(4) == L"PASS")
+ {
+ UInt32 num = kDeflateNumPassesX9;
+ RINOK(ParsePropValue(name.Mid(4), prop, num));
+ m_NumPasses = num;
+ }
+ else if (name.Left(2) == L"FB")
+ {
+ UInt32 num = kDeflateNumFastBytesX9;
+ RINOK(ParsePropValue(name.Mid(2), prop, num));
+ m_NumFastBytes = num;
+ }
+ else if (name.Left(2) == L"MC")
+ {
+ UInt32 num = 0xFFFFFFFF;
+ RINOK(ParsePropValue(name.Mid(2), prop, num));
+ m_NumMatchFinderCycles = num;
+ m_NumMatchFinderCyclesDefined = true;
+ }
+ else if (name.Left(2) == L"MT")
+ {
+ #ifndef _7ZIP_ST
+ RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _numThreads));
+ #endif
+ }
+ else if (name.Left(1) == L"A")
+ {
+ UInt32 num = kLzAlgoX5;
+ RINOK(ParsePropValue(name.Mid(1), prop, num));
+ m_Algo = num;
+ }
+ else if (name.CompareNoCase(L"TC") == 0)
+ {
+ RINOK(SetBoolProperty(m_WriteNtfsTimeExtra, prop));
+ }
+ else if (name.CompareNoCase(L"CL") == 0)
+ {
+ RINOK(SetBoolProperty(m_ForceLocal, prop));
+ if (m_ForceLocal)
+ m_ForceUtf8 = false;
+ }
+ else if (name.CompareNoCase(L"CU") == 0)
+ {
+ RINOK(SetBoolProperty(m_ForceUtf8, prop));
+ if (m_ForceUtf8)
+ m_ForceLocal = false;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.cpp
new file mode 100644
index 000000000..582187b51
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.cpp
@@ -0,0 +1,36 @@
+// Archive/Zip/Header.h
+
+#include "StdAfx.h"
+
+#include "ZipHeader.h"
+
+namespace NArchive {
+namespace NZip {
+
+namespace NSignature
+{
+ UInt32 kLocalFileHeader = 0x04034B50 + 1;
+ UInt32 kDataDescriptor = 0x08074B50 + 1;
+ UInt32 kCentralFileHeader = 0x02014B50 + 1;
+ UInt32 kEndOfCentralDir = 0x06054B50 + 1;
+ UInt32 kZip64EndOfCentralDir = 0x06064B50 + 1;
+ UInt32 kZip64EndOfCentralDirLocator = 0x07064B50 + 1;
+
+ class CMarkersInitializer
+ {
+ public:
+ CMarkersInitializer()
+ {
+ kLocalFileHeader--;
+ kDataDescriptor--;
+ kCentralFileHeader--;
+ kEndOfCentralDir--;
+ kZip64EndOfCentralDir--;
+ kZip64EndOfCentralDirLocator--;
+ }
+ };
+ static CMarkersInitializer g_MarkerInitializer;
+}
+
+}}
+
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.h
new file mode 100644
index 000000000..ce8c1e4f7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.h
@@ -0,0 +1,284 @@
+// Archive/Zip/Header.h
+
+#ifndef __ARCHIVE_ZIP_HEADER_H
+#define __ARCHIVE_ZIP_HEADER_H
+
+#include "Common/Types.h"
+
+namespace NArchive {
+namespace NZip {
+
+namespace NSignature
+{
+ extern UInt32 kLocalFileHeader;
+ extern UInt32 kDataDescriptor;
+ extern UInt32 kCentralFileHeader;
+ extern UInt32 kEndOfCentralDir;
+ extern UInt32 kZip64EndOfCentralDir;
+ extern UInt32 kZip64EndOfCentralDirLocator;
+
+ static const UInt32 kMarkerSize = 4;
+}
+
+const UInt32 kEcdSize = 22;
+const UInt32 kZip64EcdSize = 44;
+const UInt32 kZip64EcdLocatorSize = 20;
+/*
+struct CEndOfCentralDirectoryRecord
+{
+ UInt16 ThisDiskNumber;
+ UInt16 StartCentralDirectoryDiskNumber;
+ UInt16 NumEntriesInCentaralDirectoryOnThisDisk;
+ UInt16 NumEntriesInCentaralDirectory;
+ UInt32 CentralDirectorySize;
+ UInt32 CentralDirectoryStartOffset;
+ UInt16 CommentSize;
+};
+
+struct CEndOfCentralDirectoryRecordFull
+{
+ UInt32 Signature;
+ CEndOfCentralDirectoryRecord Header;
+};
+*/
+
+namespace NFileHeader
+{
+ /*
+ struct CVersion
+ {
+ Byte Version;
+ Byte HostOS;
+ };
+ */
+
+ namespace NCompressionMethod
+ {
+ enum EType
+ {
+ kStored = 0,
+ kShrunk = 1,
+ kReduced1 = 2,
+ kReduced2 = 3,
+ kReduced3 = 4,
+ kReduced4 = 5,
+ kImploded = 6,
+ kReservedTokenizing = 7, // reserved for tokenizing
+ kDeflated = 8,
+ kDeflated64 = 9,
+ kPKImploding = 10,
+
+ kBZip2 = 12,
+ kLZMA = 14,
+ kTerse = 18,
+ kLz77 = 19,
+ kJpeg = 0x60,
+ kWavPack = 0x61,
+ kPPMd = 0x62,
+ kWzAES = 0x63
+ };
+ const int kNumCompressionMethods = 11;
+ 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 kSupportedVersion = 20;
+ }
+
+ namespace NExtraID
+ {
+ enum
+ {
+ kZip64 = 0x01,
+ kNTFS = 0x0A,
+ kStrongEncrypt = 0x17,
+ kUnixTime = 0x5455,
+ kWzAES = 0x9901
+ };
+ }
+
+ namespace NNtfsExtra
+ {
+ const UInt16 kTagTime = 1;
+ enum
+ {
+ kMTime = 0,
+ kATime,
+ kCTime
+ };
+ }
+
+ namespace NUnixTime
+ {
+ enum
+ {
+ kMTime = 0,
+ kATime,
+ kCTime
+ };
+ }
+
+ const UInt32 kLocalBlockSize = 26;
+ /*
+ struct CLocalBlock
+ {
+ CVersion ExtractVersion;
+
+ UInt16 Flags;
+ UInt16 CompressionMethod;
+ UInt32 Time;
+ UInt32 FileCRC;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ UInt16 NameSize;
+ UInt16 ExtraSize;
+ };
+ */
+
+ const UInt32 kDataDescriptorSize = 16;
+ // const UInt32 kDataDescriptor64Size = 16 + 8;
+ /*
+ struct CDataDescriptor
+ {
+ UInt32 Signature;
+ UInt32 FileCRC;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ };
+
+ struct CLocalBlockFull
+ {
+ UInt32 Signature;
+ CLocalBlock Header;
+ };
+ */
+
+ const UInt32 kCentralBlockSize = 42;
+ /*
+ struct CBlock
+ {
+ CVersion MadeByVersion;
+ CVersion ExtractVersion;
+ UInt16 Flags;
+ UInt16 CompressionMethod;
+ UInt32 Time;
+ UInt32 FileCRC;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ UInt16 NameSize;
+ UInt16 ExtraSize;
+ UInt16 CommentSize;
+ UInt16 DiskNumberStart;
+ UInt16 InternalAttributes;
+ UInt32 ExternalAttributes;
+ UInt32 LocalHeaderOffset;
+ };
+
+ struct CBlockFull
+ {
+ UInt32 Signature;
+ CBlock Header;
+ };
+ */
+
+ namespace NFlags
+ {
+ const int kEncrypted = 1 << 0;
+ const int kLzmaEOS = 1 << 1;
+ const int kDescriptorUsedMask = 1 << 3;
+ const int kStrongEncrypted = 1 << 6;
+ const int kUtf8 = 1 << 11;
+
+ const int kImplodeDictionarySizeMask = 1 << 1;
+ const int kImplodeLiteralsOnMask = 1 << 2;
+
+ const int kDeflateTypeBitStart = 1;
+ const int kNumDeflateTypeBits = 2;
+ const int kNumDeflateTypes = (1 << kNumDeflateTypeBits);
+ const int 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 NUnixAttribute
+ {
+ const UInt32 kIFMT = 0170000; /* Unix file type mask */
+
+ const UInt32 kIFDIR = 0040000; /* Unix directory */
+ const UInt32 kIFREG = 0100000; /* Unix regular file */
+ const UInt32 kIFSOCK = 0140000; /* Unix socket (BSD, not SysV or Amiga) */
+ const UInt32 kIFLNK = 0120000; /* Unix symbolic link (not SysV, Amiga) */
+ const UInt32 kIFBLK = 0060000; /* Unix block special (not Amiga) */
+ const UInt32 kIFCHR = 0020000; /* Unix character special (not Amiga) */
+ const UInt32 kIFIFO = 0010000; /* Unix fifo (BCC, not MSC or Amiga) */
+
+ const UInt32 kISUID = 04000; /* Unix set user id on execution */
+ const UInt32 kISGID = 02000; /* Unix set group id on execution */
+ const UInt32 kISVTX = 01000; /* Unix directory permissions control */
+ const UInt32 kENFMT = kISGID; /* Unix record locking enforcement flag */
+ const UInt32 kIRWXU = 00700; /* Unix read, write, execute: owner */
+ const UInt32 kIRUSR = 00400; /* Unix read permission: owner */
+ const UInt32 kIWUSR = 00200; /* Unix write permission: owner */
+ const UInt32 kIXUSR = 00100; /* Unix execute permission: owner */
+ const UInt32 kIRWXG = 00070; /* Unix read, write, execute: group */
+ const UInt32 kIRGRP = 00040; /* Unix read permission: group */
+ const UInt32 kIWGRP = 00020; /* Unix write permission: group */
+ const UInt32 kIXGRP = 00010; /* Unix execute permission: group */
+ const UInt32 kIRWXO = 00007; /* Unix read, write, execute: other */
+ const UInt32 kIROTH = 00004; /* Unix read permission: other */
+ const UInt32 kIWOTH = 00002; /* Unix write permission: other */
+ const UInt32 kIXOTH = 00001; /* Unix execute permission: other */
+ }
+
+ namespace NAmigaAttribute
+ {
+ 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
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.cpp
new file mode 100644
index 000000000..b36b61be7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.cpp
@@ -0,0 +1,893 @@
+// Archive/ZipIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/DynamicBuffer.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "ZipIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+namespace NArchive {
+namespace NZip {
+
+HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ _inBufMode = false;
+ Close();
+ RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition));
+ m_Position = m_StreamStartPosition;
+ RINOK(FindAndReadMarker(stream, searchHeaderSizeLimit));
+ RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
+ m_Stream = stream;
+ return S_OK;
+}
+
+void CInArchive::Close()
+{
+ _inBuffer.ReleaseStream();
+ m_Stream.Release();
+}
+
+HRESULT CInArchive::Seek(UInt64 offset)
+{
+ return m_Stream->Seek(offset, STREAM_SEEK_SET, NULL);
+}
+
+//////////////////////////////////////
+// Markers
+
+static inline bool TestMarkerCandidate(const Byte *p, UInt32 &value)
+{
+ value = Get32(p);
+ return
+ (value == NSignature::kLocalFileHeader) ||
+ (value == NSignature::kEndOfCentralDir);
+}
+
+static const UInt32 kNumMarkerAddtionalBytes = 2;
+static inline bool TestMarkerCandidate2(const Byte *p, UInt32 &value)
+{
+ value = Get32(p);
+ if (value == NSignature::kEndOfCentralDir)
+ return (Get16(p + 4) == 0);
+ return (value == NSignature::kLocalFileHeader && p[4] < 128);
+}
+
+HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ ArcInfo.Clear();
+ m_Position = m_StreamStartPosition;
+
+ Byte marker[NSignature::kMarkerSize];
+ RINOK(ReadStream_FALSE(stream, marker, NSignature::kMarkerSize));
+ m_Position += NSignature::kMarkerSize;
+ if (TestMarkerCandidate(marker, m_Signature))
+ return S_OK;
+
+ CByteDynamicBuffer dynamicBuffer;
+ const UInt32 kSearchMarkerBufferSize = 0x10000;
+ dynamicBuffer.EnsureCapacity(kSearchMarkerBufferSize);
+ Byte *buffer = dynamicBuffer;
+ UInt32 numBytesPrev = NSignature::kMarkerSize - 1;
+ memcpy(buffer, marker + 1, numBytesPrev);
+ UInt64 curTestPos = m_StreamStartPosition + 1;
+ for (;;)
+ {
+ if (searchHeaderSizeLimit != NULL)
+ if (curTestPos - m_StreamStartPosition > *searchHeaderSizeLimit)
+ break;
+ size_t numReadBytes = kSearchMarkerBufferSize - numBytesPrev;
+ RINOK(ReadStream(stream, buffer + numBytesPrev, &numReadBytes));
+ m_Position += numReadBytes;
+ UInt32 numBytesInBuffer = numBytesPrev + (UInt32)numReadBytes;
+ const UInt32 kMarker2Size = NSignature::kMarkerSize + kNumMarkerAddtionalBytes;
+ if (numBytesInBuffer < kMarker2Size)
+ break;
+ UInt32 numTests = numBytesInBuffer - kMarker2Size + 1;
+ for (UInt32 pos = 0; pos < numTests; pos++)
+ {
+ if (buffer[pos] != 0x50)
+ continue;
+ if (TestMarkerCandidate2(buffer + pos, m_Signature))
+ {
+ curTestPos += pos;
+ ArcInfo.StartPosition = curTestPos;
+ m_Position = curTestPos + NSignature::kMarkerSize;
+ return S_OK;
+ }
+ }
+ curTestPos += numTests;
+ numBytesPrev = numBytesInBuffer - numTests;
+ memmove(buffer, buffer + numTests, numBytesPrev);
+ }
+ return S_FALSE;
+}
+
+HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize)
+{
+ size_t realProcessedSize = size;
+ HRESULT result = S_OK;
+ if (_inBufMode)
+ {
+ try { realProcessedSize = _inBuffer.ReadBytes((Byte *)data, size); }
+ catch (const CInBufferException &e) { return e.ErrorCode; }
+ }
+ else
+ result = ReadStream(m_Stream, data, &realProcessedSize);
+ if (processedSize != NULL)
+ *processedSize = (UInt32)realProcessedSize;
+ m_Position += realProcessedSize;
+ return result;
+}
+
+void CInArchive::Skip(UInt64 num)
+{
+ for (UInt64 i = 0; i < num; i++)
+ ReadByte();
+}
+
+void CInArchive::IncreaseRealPosition(UInt64 addValue)
+{
+ if (m_Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position) != S_OK)
+ throw CInArchiveException(CInArchiveException::kSeekStreamError);
+}
+
+bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size)
+{
+ UInt32 realProcessedSize;
+ if (ReadBytes(data, size, &realProcessedSize) != S_OK)
+ throw CInArchiveException(CInArchiveException::kReadStreamError);
+ return (realProcessedSize == size);
+}
+
+void CInArchive::SafeReadBytes(void *data, UInt32 size)
+{
+ if (!ReadBytesAndTestSize(data, size))
+ throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
+}
+
+void CInArchive::ReadBuffer(CByteBuffer &buffer, UInt32 size)
+{
+ buffer.SetCapacity(size);
+ if (size > 0)
+ SafeReadBytes(buffer, size);
+}
+
+Byte CInArchive::ReadByte()
+{
+ Byte b;
+ SafeReadBytes(&b, 1);
+ return b;
+}
+
+UInt16 CInArchive::ReadUInt16()
+{
+ Byte buf[2];
+ SafeReadBytes(buf, 2);
+ return Get16(buf);
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ Byte buf[4];
+ SafeReadBytes(buf, 4);
+ return Get32(buf);
+}
+
+UInt64 CInArchive::ReadUInt64()
+{
+ Byte buf[8];
+ SafeReadBytes(buf, 8);
+ return Get64(buf);
+}
+
+bool CInArchive::ReadUInt32(UInt32 &value)
+{
+ Byte buf[4];
+ if (!ReadBytesAndTestSize(buf, 4))
+ return false;
+ value = Get32(buf);
+ return true;
+}
+
+void CInArchive::ReadFileName(UInt32 nameSize, AString &dest)
+{
+ if (nameSize == 0)
+ dest.Empty();
+ char *p = dest.GetBuffer((int)nameSize);
+ SafeReadBytes(p, nameSize);
+ p[nameSize] = 0;
+ dest.ReleaseBuffer();
+}
+
+void CInArchive::ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock,
+ UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber)
+{
+ extraBlock.Clear();
+ UInt32 remain = extraSize;
+ while(remain >= 4)
+ {
+ CExtraSubBlock subBlock;
+ subBlock.ID = ReadUInt16();
+ UInt32 dataSize = ReadUInt16();
+ remain -= 4;
+ if (dataSize > remain) // it's bug
+ dataSize = remain;
+ if (subBlock.ID == NFileHeader::NExtraID::kZip64)
+ {
+ if (unpackSize == 0xFFFFFFFF)
+ {
+ if (dataSize < 8)
+ break;
+ unpackSize = ReadUInt64();
+ remain -= 8;
+ dataSize -= 8;
+ }
+ if (packSize == 0xFFFFFFFF)
+ {
+ if (dataSize < 8)
+ break;
+ packSize = ReadUInt64();
+ remain -= 8;
+ dataSize -= 8;
+ }
+ if (localHeaderOffset == 0xFFFFFFFF)
+ {
+ if (dataSize < 8)
+ break;
+ localHeaderOffset = ReadUInt64();
+ remain -= 8;
+ dataSize -= 8;
+ }
+ if (diskStartNumber == 0xFFFF)
+ {
+ if (dataSize < 4)
+ break;
+ diskStartNumber = ReadUInt32();
+ remain -= 4;
+ dataSize -= 4;
+ }
+ for (UInt32 i = 0; i < dataSize; i++)
+ ReadByte();
+ }
+ else
+ {
+ ReadBuffer(subBlock.Data, dataSize);
+ extraBlock.SubBlocks.Add(subBlock);
+ }
+ remain -= dataSize;
+ }
+ Skip(remain);
+}
+
+HRESULT CInArchive::ReadLocalItem(CItemEx &item)
+{
+ const int kBufSize = 26;
+ Byte p[kBufSize];
+ SafeReadBytes(p, kBufSize);
+
+ item.ExtractVersion.Version = p[0];
+ item.ExtractVersion.HostOS = p[1];
+ item.Flags = Get16(p + 2);
+ item.CompressionMethod = Get16(p + 4);
+ item.Time = Get32(p + 6);
+ item.FileCRC = Get32(p + 10);
+ item.PackSize = Get32(p + 14);
+ item.UnPackSize = Get32(p + 18);
+ UInt32 fileNameSize = Get16(p + 22);
+ item.LocalExtraSize = Get16(p + 24);
+ ReadFileName(fileNameSize, item.Name);
+ item.FileHeaderWithNameSize = 4 + NFileHeader::kLocalBlockSize + fileNameSize;
+ if (item.LocalExtraSize > 0)
+ {
+ UInt64 localHeaderOffset = 0;
+ UInt32 diskStartNumber = 0;
+ ReadExtra(item.LocalExtraSize, item.LocalExtra, item.UnPackSize, item.PackSize,
+ localHeaderOffset, diskStartNumber);
+ }
+ /*
+ if (item.IsDir())
+ item.UnPackSize = 0; // check It
+ */
+ return S_OK;
+}
+
+static bool FlagsAreSame(CItem &i1, CItem &i2)
+{
+ if (i1.CompressionMethod != i2.CompressionMethod)
+ return false;
+ // i1.Time
+
+ if (i1.Flags == i2.Flags)
+ return true;
+ UInt32 mask = 0xFFFF;
+ switch(i1.CompressionMethod)
+ {
+ case NFileHeader::NCompressionMethod::kDeflated:
+ mask = 0x7FF9;
+ break;
+ default:
+ if (i1.CompressionMethod <= NFileHeader::NCompressionMethod::kImploded)
+ mask = 0x7FFF;
+ }
+ return ((i1.Flags & mask) == (i2.Flags & mask));
+}
+
+HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item)
+{
+ if (item.FromLocal)
+ return S_OK;
+ try
+ {
+ RINOK(Seek(ArcInfo.Base + item.LocalHeaderPosition));
+ CItemEx localItem;
+ if (ReadUInt32() != NSignature::kLocalFileHeader)
+ return S_FALSE;
+ RINOK(ReadLocalItem(localItem));
+ if (!FlagsAreSame(item, localItem))
+ return S_FALSE;
+
+ if ((!localItem.HasDescriptor() &&
+ (
+ item.FileCRC != localItem.FileCRC ||
+ item.PackSize != localItem.PackSize ||
+ item.UnPackSize != localItem.UnPackSize
+ )
+ ) ||
+ item.Name.Length() != localItem.Name.Length()
+ )
+ return S_FALSE;
+ item.FileHeaderWithNameSize = localItem.FileHeaderWithNameSize;
+ item.LocalExtraSize = localItem.LocalExtraSize;
+ item.LocalExtra = localItem.LocalExtra;
+ item.FromLocal = true;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadLocalItemDescriptor(CItemEx &item)
+{
+ if (item.HasDescriptor())
+ {
+ const int kBufferSize = (1 << 12);
+ Byte buffer[kBufferSize];
+
+ UInt32 numBytesInBuffer = 0;
+ UInt32 packedSize = 0;
+
+ bool descriptorWasFound = false;
+ for (;;)
+ {
+ UInt32 processedSize;
+ RINOK(ReadBytes(buffer + numBytesInBuffer, kBufferSize - numBytesInBuffer, &processedSize));
+ numBytesInBuffer += processedSize;
+ if (numBytesInBuffer < NFileHeader::kDataDescriptorSize)
+ return S_FALSE;
+ UInt32 i;
+ for (i = 0; i <= numBytesInBuffer - NFileHeader::kDataDescriptorSize; i++)
+ {
+ // descriptorSignature field is Info-ZIP's extension
+ // to Zip specification.
+ UInt32 descriptorSignature = Get32(buffer + i);
+
+ // !!!! It must be fixed for Zip64 archives
+ UInt32 descriptorPackSize = Get32(buffer + i + 8);
+ if (descriptorSignature== NSignature::kDataDescriptor && descriptorPackSize == packedSize + i)
+ {
+ descriptorWasFound = true;
+ item.FileCRC = Get32(buffer + i + 4);
+ item.PackSize = descriptorPackSize;
+ item.UnPackSize = Get32(buffer + i + 12);
+ IncreaseRealPosition(Int64(Int32(0 - (numBytesInBuffer - i - NFileHeader::kDataDescriptorSize))));
+ break;
+ }
+ }
+ if (descriptorWasFound)
+ break;
+ packedSize += i;
+ int j;
+ for (j = 0; i < numBytesInBuffer; i++, j++)
+ buffer[j] = buffer[i];
+ numBytesInBuffer = j;
+ }
+ }
+ else
+ IncreaseRealPosition(item.PackSize);
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item)
+{
+ if (item.FromLocal)
+ return S_OK;
+ try
+ {
+ RINOK(ReadLocalItemAfterCdItem(item));
+ if (item.HasDescriptor())
+ {
+ RINOK(Seek(ArcInfo.Base + item.GetDataPosition() + item.PackSize));
+ if (ReadUInt32() != NSignature::kDataDescriptor)
+ return S_FALSE;
+ UInt32 crc = ReadUInt32();
+ UInt64 packSize, unpackSize;
+
+ /*
+ if (IsZip64)
+ {
+ packSize = ReadUInt64();
+ unpackSize = ReadUInt64();
+ }
+ else
+ */
+ {
+ packSize = ReadUInt32();
+ unpackSize = ReadUInt32();
+ }
+
+ if (crc != item.FileCRC || item.PackSize != packSize || item.UnPackSize != unpackSize)
+ return S_FALSE;
+ }
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadCdItem(CItemEx &item)
+{
+ item.FromCentral = true;
+ const int kBufSize = 42;
+ Byte p[kBufSize];
+ SafeReadBytes(p, kBufSize);
+ item.MadeByVersion.Version = p[0];
+ item.MadeByVersion.HostOS = p[1];
+ item.ExtractVersion.Version = p[2];
+ item.ExtractVersion.HostOS = p[3];
+ item.Flags = Get16(p + 4);
+ item.CompressionMethod = Get16(p + 6);
+ item.Time = Get32(p + 8);
+ item.FileCRC = Get32(p + 12);
+ item.PackSize = Get32(p + 16);
+ item.UnPackSize = Get32(p + 20);
+ UInt16 headerNameSize = Get16(p + 24);
+ UInt16 headerExtraSize = Get16(p + 26);
+ UInt16 headerCommentSize = Get16(p + 28);
+ UInt32 headerDiskNumberStart = Get16(p + 30);
+ item.InternalAttributes = Get16(p + 32);
+ item.ExternalAttributes = Get32(p + 34);
+ item.LocalHeaderPosition = Get32(p + 38);
+ ReadFileName(headerNameSize, item.Name);
+
+ if (headerExtraSize > 0)
+ {
+ ReadExtra(headerExtraSize, item.CentralExtra, item.UnPackSize, item.PackSize,
+ item.LocalHeaderPosition, headerDiskNumberStart);
+ }
+
+ if (headerDiskNumberStart != 0)
+ throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported);
+
+ // May be these strings must be deleted
+ /*
+ if (item.IsDir())
+ item.UnPackSize = 0;
+ */
+
+ ReadBuffer(item.Comment, headerCommentSize);
+ return S_OK;
+}
+
+HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo)
+{
+ RINOK(Seek(offset));
+ const UInt32 kEcd64Size = 56;
+ Byte buf[kEcd64Size];
+ if (!ReadBytesAndTestSize(buf, kEcd64Size))
+ return S_FALSE;
+ if (Get32(buf) != NSignature::kZip64EndOfCentralDir)
+ return S_FALSE;
+ // cdInfo.NumEntries = Get64(buf + 24);
+ cdInfo.Size = Get64(buf + 40);
+ cdInfo.Offset = Get64(buf + 48);
+ return S_OK;
+}
+
+HRESULT CInArchive::FindCd(CCdInfo &cdInfo)
+{
+ UInt64 endPosition;
+ RINOK(m_Stream->Seek(0, STREAM_SEEK_END, &endPosition));
+ const UInt32 kBufSizeMax = (1 << 16) + kEcdSize + kZip64EcdLocatorSize;
+ CByteBuffer byteBuffer;
+ byteBuffer.SetCapacity(kBufSizeMax);
+ Byte *buf = byteBuffer;
+ UInt32 bufSize = (endPosition < kBufSizeMax) ? (UInt32)endPosition : kBufSizeMax;
+ if (bufSize < kEcdSize)
+ return S_FALSE;
+ UInt64 startPosition = endPosition - bufSize;
+ RINOK(m_Stream->Seek(startPosition, STREAM_SEEK_SET, &m_Position));
+ if (m_Position != startPosition)
+ return S_FALSE;
+ if (!ReadBytesAndTestSize(buf, bufSize))
+ return S_FALSE;
+ for (int i = (int)(bufSize - kEcdSize); i >= 0; i--)
+ {
+ if (Get32(buf + i) == NSignature::kEndOfCentralDir)
+ {
+ if (i >= kZip64EcdLocatorSize)
+ {
+ const Byte *locator = buf + i - kZip64EcdLocatorSize;
+ if (Get32(locator) == NSignature::kZip64EndOfCentralDirLocator)
+ {
+ UInt64 ecd64Offset = Get64(locator + 8);
+ if (TryEcd64(ecd64Offset, cdInfo) == S_OK)
+ return S_OK;
+ if (TryEcd64(ArcInfo.StartPosition + ecd64Offset, cdInfo) == S_OK)
+ {
+ ArcInfo.Base = ArcInfo.StartPosition;
+ return S_OK;
+ }
+ }
+ }
+ if (Get32(buf + i + 4) == 0)
+ {
+ // cdInfo.NumEntries = GetUInt16(buf + i + 10);
+ cdInfo.Size = Get32(buf + i + 12);
+ cdInfo.Offset = Get32(buf + i + 16);
+ UInt64 curPos = endPosition - bufSize + i;
+ UInt64 cdEnd = cdInfo.Size + cdInfo.Offset;
+ if (curPos != cdEnd)
+ {
+ /*
+ if (cdInfo.Offset <= 16 && cdInfo.Size != 0)
+ {
+ // here we support some rare ZIP files with Central directory at the start
+ ArcInfo.Base = 0;
+ }
+ else
+ */
+ ArcInfo.Base = curPos - cdEnd;
+ }
+ return S_OK;
+ }
+ }
+ }
+ return S_FALSE;
+}
+
+HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress)
+{
+ items.Clear();
+ RINOK(m_Stream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position));
+ if (m_Position != cdOffset)
+ return S_FALSE;
+
+ if (!_inBuffer.Create(1 << 15))
+ return E_OUTOFMEMORY;
+ _inBuffer.SetStream(m_Stream);
+ _inBuffer.Init();
+ _inBufMode = true;
+
+ while(m_Position - cdOffset < cdSize)
+ {
+ if (ReadUInt32() != NSignature::kCentralFileHeader)
+ return S_FALSE;
+ CItemEx cdItem;
+ RINOK(ReadCdItem(cdItem));
+ items.Add(cdItem);
+ if (progress && items.Size() % 1000 == 0)
+ RINOK(progress->SetCompleted(items.Size()));
+ }
+ return (m_Position - cdOffset == cdSize) ? S_OK : S_FALSE;
+}
+
+HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress)
+{
+ ArcInfo.Base = 0;
+ CCdInfo cdInfo;
+ RINOK(FindCd(cdInfo));
+ HRESULT res = S_FALSE;
+ cdSize = cdInfo.Size;
+ cdOffset = cdInfo.Offset;
+ res = TryReadCd(items, ArcInfo.Base + cdOffset, cdSize, progress);
+ if (res == S_FALSE && ArcInfo.Base == 0)
+ {
+ res = TryReadCd(items, cdInfo.Offset + ArcInfo.StartPosition, cdSize, progress);
+ if (res == S_OK)
+ ArcInfo.Base = ArcInfo.StartPosition;
+ }
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ return res;
+}
+
+HRESULT CInArchive::ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems)
+{
+ items.Clear();
+ numCdItems = 0;
+ while (m_Signature == NSignature::kLocalFileHeader)
+ {
+ // FSeek points to next byte after signature
+ // NFileHeader::CLocalBlock localHeader;
+ CItemEx item;
+ item.LocalHeaderPosition = m_Position - m_StreamStartPosition - 4; // points to signature;
+ RINOK(ReadLocalItem(item));
+ item.FromLocal = true;
+ ReadLocalItemDescriptor(item);
+ items.Add(item);
+ if (progress && items.Size() % 100 == 0)
+ RINOK(progress->SetCompleted(items.Size()));
+ if (!ReadUInt32(m_Signature))
+ break;
+ }
+ cdOffset = m_Position - 4;
+ int i;
+ for (i = 0; i < items.Size(); i++, numCdItems++)
+ {
+ if (progress && i % 1000 == 0)
+ RINOK(progress->SetCompleted(items.Size()));
+ if (m_Signature == NSignature::kEndOfCentralDir)
+ break;
+
+ if (m_Signature != NSignature::kCentralFileHeader)
+ return S_FALSE;
+
+ CItemEx cdItem;
+ RINOK(ReadCdItem(cdItem));
+
+ if (i == 0)
+ {
+ int j;
+ for (j = 0; j < items.Size(); j++)
+ {
+ CItemEx &item = items[j];
+ if (item.Name == cdItem.Name)
+ {
+ ArcInfo.Base = item.LocalHeaderPosition - cdItem.LocalHeaderPosition;
+ break;
+ }
+ }
+ if (j == items.Size())
+ return S_FALSE;
+ }
+
+ int index;
+ int left = 0, right = items.Size();
+ for (;;)
+ {
+ if (left >= right)
+ return S_FALSE;
+ index = (left + right) / 2;
+ UInt64 position = items[index].LocalHeaderPosition - ArcInfo.Base;
+ if (cdItem.LocalHeaderPosition == position)
+ break;
+ if (cdItem.LocalHeaderPosition < position)
+ right = index;
+ else
+ left = index + 1;
+ }
+ CItemEx &item = items[index];
+ // item.LocalHeaderPosition = cdItem.LocalHeaderPosition;
+ item.MadeByVersion = cdItem.MadeByVersion;
+ item.CentralExtra = cdItem.CentralExtra;
+
+ if (
+ // item.ExtractVersion != cdItem.ExtractVersion ||
+ !FlagsAreSame(item, cdItem) ||
+ item.FileCRC != cdItem.FileCRC)
+ return S_FALSE;
+
+ if (item.Name.Length() != cdItem.Name.Length() ||
+ item.PackSize != cdItem.PackSize ||
+ item.UnPackSize != cdItem.UnPackSize
+ )
+ return S_FALSE;
+ item.Name = cdItem.Name;
+ item.InternalAttributes = cdItem.InternalAttributes;
+ item.ExternalAttributes = cdItem.ExternalAttributes;
+ item.Comment = cdItem.Comment;
+ item.FromCentral = cdItem.FromCentral;
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ }
+ for (i = 0; i < items.Size(); i++)
+ items[i].LocalHeaderPosition -= ArcInfo.Base;
+ return S_OK;
+}
+
+struct CEcd
+{
+ UInt16 thisDiskNumber;
+ UInt16 startCDDiskNumber;
+ UInt16 numEntriesInCDOnThisDisk;
+ UInt16 numEntriesInCD;
+ UInt32 cdSize;
+ UInt32 cdStartOffset;
+ UInt16 commentSize;
+ void Parse(const Byte *p);
+};
+
+void CEcd::Parse(const Byte *p)
+{
+ thisDiskNumber = Get16(p);
+ startCDDiskNumber = Get16(p + 2);
+ numEntriesInCDOnThisDisk = Get16(p + 4);
+ numEntriesInCD = Get16(p + 6);
+ cdSize = Get32(p + 8);
+ cdStartOffset = Get32(p + 12);
+ commentSize = Get16(p + 16);
+}
+
+struct CEcd64
+{
+ UInt16 versionMade;
+ UInt16 versionNeedExtract;
+ UInt32 thisDiskNumber;
+ UInt32 startCDDiskNumber;
+ UInt64 numEntriesInCDOnThisDisk;
+ UInt64 numEntriesInCD;
+ UInt64 cdSize;
+ UInt64 cdStartOffset;
+ void Parse(const Byte *p);
+ CEcd64() { memset(this, 0, sizeof(*this)); }
+};
+
+void CEcd64::Parse(const Byte *p)
+{
+ versionMade = Get16(p);
+ versionNeedExtract = Get16(p + 2);
+ thisDiskNumber = Get32(p + 4);
+ startCDDiskNumber = Get32(p + 8);
+ numEntriesInCDOnThisDisk = Get64(p + 12);
+ numEntriesInCD = Get64(p + 20);
+ cdSize = Get64(p + 28);
+ cdStartOffset = Get64(p + 36);
+}
+
+#define COPY_ECD_ITEM_16(n) if (!isZip64 || ecd. n != 0xFFFF) ecd64. n = ecd. n;
+#define COPY_ECD_ITEM_32(n) if (!isZip64 || ecd. n != 0xFFFFFFFF) ecd64. n = ecd. n;
+
+HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress)
+{
+ // m_Signature must be kLocalFileHeaderSignature or
+ // kEndOfCentralDirSignature
+ // m_Position points to next byte after signature
+
+ IsZip64 = false;
+ items.Clear();
+
+ UInt64 cdSize, cdStartOffset;
+ HRESULT res;
+ try
+ {
+ res = ReadCd(items, cdStartOffset, cdSize, progress);
+ }
+ catch(CInArchiveException &)
+ {
+ res = S_FALSE;
+ }
+ if (res != S_FALSE && res != S_OK)
+ return res;
+
+ /*
+ if (res != S_OK)
+ return res;
+ res = S_FALSE;
+ */
+
+ int numCdItems = items.Size();
+ if (res == S_FALSE)
+ {
+ _inBufMode = false;
+ ArcInfo.Base = 0;
+ RINOK(m_Stream->Seek(ArcInfo.StartPosition, STREAM_SEEK_SET, &m_Position));
+ if (m_Position != ArcInfo.StartPosition)
+ return S_FALSE;
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ RINOK(ReadLocalsAndCd(items, progress, cdStartOffset, numCdItems));
+ cdSize = (m_Position - 4) - cdStartOffset;
+ cdStartOffset -= ArcInfo.Base;
+ }
+
+ CEcd64 ecd64;
+ bool isZip64 = false;
+ UInt64 zip64EcdStartOffset = m_Position - 4 - ArcInfo.Base;
+ if (m_Signature == NSignature::kZip64EndOfCentralDir)
+ {
+ IsZip64 = isZip64 = true;
+ UInt64 recordSize = ReadUInt64();
+
+ const int kBufSize = kZip64EcdSize;
+ Byte buf[kBufSize];
+ SafeReadBytes(buf, kBufSize);
+ ecd64.Parse(buf);
+
+ Skip(recordSize - kZip64EcdSize);
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0)
+ throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported);
+ if (ecd64.numEntriesInCDOnThisDisk != numCdItems ||
+ ecd64.numEntriesInCD != numCdItems ||
+ ecd64.cdSize != cdSize ||
+ (ecd64.cdStartOffset != cdStartOffset &&
+ (!items.IsEmpty())))
+ return S_FALSE;
+ }
+ if (m_Signature == NSignature::kZip64EndOfCentralDirLocator)
+ {
+ /* UInt32 startEndCDDiskNumber = */ ReadUInt32();
+ UInt64 endCDStartOffset = ReadUInt64();
+ /* UInt32 numberOfDisks = */ ReadUInt32();
+ if (zip64EcdStartOffset != endCDStartOffset)
+ return S_FALSE;
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ }
+ if (m_Signature != NSignature::kEndOfCentralDir)
+ return S_FALSE;
+
+ const int kBufSize = kEcdSize - 4;
+ Byte buf[kBufSize];
+ SafeReadBytes(buf, kBufSize);
+ CEcd ecd;
+ ecd.Parse(buf);
+
+ COPY_ECD_ITEM_16(thisDiskNumber);
+ COPY_ECD_ITEM_16(startCDDiskNumber);
+ COPY_ECD_ITEM_16(numEntriesInCDOnThisDisk);
+ COPY_ECD_ITEM_16(numEntriesInCD);
+ COPY_ECD_ITEM_32(cdSize);
+ COPY_ECD_ITEM_32(cdStartOffset);
+
+ ReadBuffer(ArcInfo.Comment, ecd.commentSize);
+
+ if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0)
+ throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported);
+ if ((UInt16)ecd64.numEntriesInCDOnThisDisk != ((UInt16)numCdItems) ||
+ (UInt16)ecd64.numEntriesInCD != ((UInt16)numCdItems) ||
+ (UInt32)ecd64.cdSize != (UInt32)cdSize ||
+ ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdStartOffset &&
+ (!items.IsEmpty())))
+ return S_FALSE;
+
+ _inBufMode = false;
+ _inBuffer.Free();
+ IsOkHeaders = (numCdItems == items.Size());
+ ArcInfo.FinishPosition = m_Position;
+ return S_OK;
+}
+
+ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size)
+{
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> stream(streamSpec);
+ SeekInArchive(ArcInfo.Base + position);
+ streamSpec->SetStream(m_Stream);
+ streamSpec->Init(size);
+ return stream.Detach();
+}
+
+IInStream* CInArchive::CreateStream()
+{
+ CMyComPtr<IInStream> stream = m_Stream;
+ return stream.Detach();
+}
+
+bool CInArchive::SeekInArchive(UInt64 position)
+{
+ UInt64 newPosition;
+ if (m_Stream->Seek(position, STREAM_SEEK_SET, &newPosition) != S_OK)
+ return false;
+ return (newPosition == position);
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.h
new file mode 100644
index 000000000..0565339a0
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.h
@@ -0,0 +1,125 @@
+// Archive/ZipIn.h
+
+#ifndef __ZIP_IN_H
+#define __ZIP_IN_H
+
+#include "Common/MyCom.h"
+
+#include "../../IStream.h"
+
+#include "../../Common/InBuffer.h"
+
+#include "ZipHeader.h"
+#include "ZipItemEx.h"
+
+namespace NArchive {
+namespace NZip {
+
+class CInArchiveException
+{
+public:
+ enum ECauseType
+ {
+ kUnexpectedEndOfArchive = 0,
+ kArchiceHeaderCRCError,
+ kFileHeaderCRCError,
+ kIncorrectArchive,
+ kDataDescroptorsAreNotSupported,
+ kMultiVolumeArchiveAreNotSupported,
+ kReadStreamError,
+ kSeekStreamError
+ }
+ Cause;
+ CInArchiveException(ECauseType cause): Cause(cause) {}
+};
+
+class CInArchiveInfo
+{
+public:
+ UInt64 Base;
+ UInt64 StartPosition;
+ UInt64 FinishPosition;
+ CByteBuffer Comment;
+
+ CInArchiveInfo(): Base(0), StartPosition(0) {}
+ UInt64 GetPhySize() const { return FinishPosition - StartPosition; }
+ void Clear()
+ {
+ Base = 0;
+ StartPosition = 0;
+ Comment.SetCapacity(0);
+ }
+};
+
+class CProgressVirt
+{
+public:
+ STDMETHOD(SetTotal)(UInt64 numFiles) PURE;
+ STDMETHOD(SetCompleted)(UInt64 numFiles) PURE;
+};
+
+struct CCdInfo
+{
+ // UInt64 NumEntries;
+ UInt64 Size;
+ UInt64 Offset;
+};
+
+class CInArchive
+{
+ CMyComPtr<IInStream> m_Stream;
+ UInt32 m_Signature;
+ UInt64 m_StreamStartPosition;
+ UInt64 m_Position;
+
+ bool _inBufMode;
+ CInBuffer _inBuffer;
+
+ HRESULT Seek(UInt64 offset);
+
+ HRESULT FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
+ void ReadFileName(UInt32 nameSize, AString &dest);
+
+ HRESULT ReadBytes(void *data, UInt32 size, UInt32 *processedSize);
+ bool ReadBytesAndTestSize(void *data, UInt32 size);
+ void SafeReadBytes(void *data, UInt32 size);
+ void ReadBuffer(CByteBuffer &buffer, UInt32 size);
+ Byte ReadByte();
+ UInt16 ReadUInt16();
+ UInt32 ReadUInt32();
+ UInt64 ReadUInt64();
+ bool ReadUInt32(UInt32 &signature);
+
+ void Skip(UInt64 num);
+ void IncreaseRealPosition(UInt64 addValue);
+
+ void ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock,
+ UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber);
+ HRESULT ReadLocalItem(CItemEx &item);
+ HRESULT ReadLocalItemDescriptor(CItemEx &item);
+ HRESULT ReadCdItem(CItemEx &item);
+ HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo);
+ HRESULT FindCd(CCdInfo &cdInfo);
+ HRESULT TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress);
+ HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress);
+ HRESULT ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems);
+public:
+ CInArchiveInfo ArcInfo;
+ bool IsZip64;
+ bool IsOkHeaders;
+
+ HRESULT ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress);
+ HRESULT ReadLocalItemAfterCdItem(CItemEx &item);
+ HRESULT ReadLocalItemAfterCdItemFull(CItemEx &item);
+ HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
+ void Close();
+ bool SeekInArchive(UInt64 position);
+ ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
+ IInStream* CreateStream();
+
+ bool IsOpen() const { return m_Stream != NULL; }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.cpp
new file mode 100644
index 000000000..139b01291
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.cpp
@@ -0,0 +1,172 @@
+// Archive/ZipItem.cpp
+
+#include "StdAfx.h"
+
+#include "ZipHeader.h"
+#include "ZipItem.h"
+#include "../Common/ItemNameUtils.h"
+#include "../../../../C/CpuArch.h"
+
+namespace NArchive {
+namespace NZip {
+
+bool operator==(const CVersion &v1, const CVersion &v2)
+{
+ return (v1.Version == v2.Version) && (v1.HostOS == v2.HostOS);
+}
+
+bool operator!=(const CVersion &v1, const CVersion &v2)
+{
+ return !(v1 == v2);
+}
+
+bool CExtraSubBlock::ExtractNtfsTime(int index, FILETIME &ft) const
+{
+ ft.dwHighDateTime = ft.dwLowDateTime = 0;
+ UInt32 size = (UInt32)Data.GetCapacity();
+ if (ID != NFileHeader::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);
+ UInt32 attrSize = GetUi16(p + 2);
+ p += 4;
+ size -= 4;
+ if (attrSize > size)
+ attrSize = size;
+
+ if (tag == NFileHeader::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::ExtractUnixTime(int index, UInt32 &res) const
+{
+ res = 0;
+ UInt32 size = (UInt32)Data.GetCapacity();
+ if (ID != NFileHeader::NExtraID::kUnixTime || size < 5)
+ return false;
+ const Byte *p = (const Byte *)Data;
+ Byte flags = *p++;
+ size--;
+ for (int 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;
+}
+
+bool CLocalItem::IsDir() const
+{
+ return NItemName::HasTailSlash(Name, GetCodePage());
+}
+
+bool CItem::IsDir() const
+{
+ if (NItemName::HasTailSlash(Name, GetCodePage()))
+ return true;
+ if (!FromCentral)
+ return false;
+ WORD highAttributes = WORD((ExternalAttributes >> 16 ) & 0xFFFF);
+ switch(MadeByVersion.HostOS)
+ {
+ case NFileHeader::NHostOS::kAMIGA:
+ switch (highAttributes & NFileHeader::NAmigaAttribute::kIFMT)
+ {
+ case NFileHeader::NAmigaAttribute::kIFDIR: return true;
+ case NFileHeader::NAmigaAttribute::kIFREG: return false;
+ default: return false; // change it throw kUnknownAttributes;
+ }
+ case NFileHeader::NHostOS::kFAT:
+ case NFileHeader::NHostOS::kNTFS:
+ case NFileHeader::NHostOS::kHPFS:
+ case NFileHeader::NHostOS::kVFAT:
+ return ((ExternalAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
+ case NFileHeader::NHostOS::kAtari:
+ case NFileHeader::NHostOS::kMac:
+ case NFileHeader::NHostOS::kVMS:
+ case NFileHeader::NHostOS::kVM_CMS:
+ case NFileHeader::NHostOS::kAcorn:
+ case NFileHeader::NHostOS::kMVS:
+ return false; // change it throw kUnknownAttributes;
+ default:
+ /*
+ switch (highAttributes & NFileHeader::NUnixAttribute::kIFMT)
+ {
+ case NFileHeader::NUnixAttribute::kIFDIR:
+ return true;
+ default:
+ return false;
+ }
+ */
+ return false;
+ }
+}
+
+UInt32 CLocalItem::GetWinAttributes() const
+{
+ DWORD winAttributes = 0;
+ if (IsDir())
+ winAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+ return winAttributes;
+}
+
+UInt32 CItem::GetWinAttributes() const
+{
+ DWORD winAttributes = 0;
+ switch(MadeByVersion.HostOS)
+ {
+ case NFileHeader::NHostOS::kFAT:
+ case NFileHeader::NHostOS::kNTFS:
+ if (FromCentral)
+ winAttributes = ExternalAttributes;
+ break;
+ default:
+ winAttributes = 0; // must be converted from unix value;
+ }
+ if (IsDir()) // test it;
+ winAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+ return winAttributes;
+}
+
+void CLocalItem::SetFlagBits(int startBitNumber, int numBits, int value)
+{
+ UInt16 mask = (UInt16)(((1 << numBits) - 1) << startBitNumber);
+ Flags &= ~mask;
+ Flags |= value << startBitNumber;
+}
+
+void CLocalItem::SetBitMask(int bitMask, bool enable)
+{
+ if(enable)
+ Flags |= bitMask;
+ else
+ Flags &= ~bitMask;
+}
+
+void CLocalItem::SetEncrypted(bool encrypted)
+ { SetBitMask(NFileHeader::NFlags::kEncrypted, encrypted); }
+void CLocalItem::SetUtf8(bool isUtf8)
+ { SetBitMask(NFileHeader::NFlags::kUtf8, isUtf8); }
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.h
new file mode 100644
index 000000000..31f2de732
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.h
@@ -0,0 +1,281 @@
+// Archive/ZipItem.h
+
+#ifndef __ARCHIVE_ZIP_ITEM_H
+#define __ARCHIVE_ZIP_ITEM_H
+
+#include "Common/Types.h"
+#include "Common/MyString.h"
+#include "Common/Buffer.h"
+#include "Common/UTFConvert.h"
+#include "Common/StringConvert.h"
+
+#include "ZipHeader.h"
+
+namespace NArchive {
+namespace NZip {
+
+struct CVersion
+{
+ Byte Version;
+ Byte HostOS;
+};
+
+bool operator==(const CVersion &v1, const CVersion &v2);
+bool operator!=(const CVersion &v1, const CVersion &v2);
+
+struct CExtraSubBlock
+{
+ UInt16 ID;
+ CByteBuffer Data;
+ bool ExtractNtfsTime(int index, FILETIME &ft) const;
+ bool ExtractUnixTime(int index, UInt32 &res) const;
+};
+
+struct CWzAesExtraField
+{
+ UInt16 VendorVersion; // 0x0001 - AE-1, 0x0002 - AE-2,
+ // UInt16 VendorId; // "AE"
+ Byte Strength; // 1 - 128-bit , 2 - 192-bit , 3 - 256-bit
+ UInt16 Method;
+
+ CWzAesExtraField(): 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.GetCapacity() < 7)
+ return false;
+ const Byte *p = (const Byte *)sb.Data;
+ VendorVersion = (((UInt16)p[1]) << 8) | p[0];
+ if (p[2] != 'A' || p[3] != 'E')
+ return false;
+ Strength = p[4];
+ Method = (((UInt16)p[6]) << 16) | p[5];
+ return true;
+ }
+ void SetSubBlock(CExtraSubBlock &sb) const
+ {
+ sb.Data.SetCapacity(7);
+ 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 NStrongCryptoFlags
+{
+ 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 CStrongCryptoField
+{
+ 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.GetCapacity() < 8)
+ return false;
+ Format = (((UInt16)p[1]) << 8) | p[0];
+ AlgId = (((UInt16)p[3]) << 8) | p[2];
+ BitLen = (((UInt16)p[5]) << 8) | p[4];
+ Flags = (((UInt16)p[7]) << 8) | p[6];
+ return (Format == 2);
+ }
+};
+
+struct CExtraBlock
+{
+ CObjectVector<CExtraSubBlock> SubBlocks;
+ void Clear() { SubBlocks.Clear(); }
+ size_t GetSize() const
+ {
+ size_t res = 0;
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ res += SubBlocks[i].Data.GetCapacity() + 2 + 2;
+ return res;
+ }
+ bool GetWzAesField(CWzAesExtraField &aesField) const
+ {
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ if (aesField.ParseFromSubBlock(SubBlocks[i]))
+ return true;
+ return false;
+ }
+
+ bool GetStrongCryptoField(CStrongCryptoField &f) const
+ {
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ if (f.ParseFromSubBlock(SubBlocks[i]))
+ return true;
+ return false;
+ }
+
+ bool HasWzAesField() const
+ {
+ CWzAesExtraField aesField;
+ return GetWzAesField(aesField);
+ }
+
+ bool GetNtfsTime(int index, FILETIME &ft) const
+ {
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ {
+ const CExtraSubBlock &sb = SubBlocks[i];
+ if (sb.ID == NFileHeader::NExtraID::kNTFS)
+ return sb.ExtractNtfsTime(index, ft);
+ }
+ return false;
+ }
+
+ bool GetUnixTime(int index, UInt32 &res) const
+ {
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ {
+ const CExtraSubBlock &sb = SubBlocks[i];
+ if (sb.ID == NFileHeader::NExtraID::kUnixTime)
+ return sb.ExtractUnixTime(index, res);
+ }
+ return false;
+ }
+
+ /*
+ bool HasStrongCryptoField() const
+ {
+ CStrongCryptoField f;
+ return GetStrongCryptoField(f);
+ }
+ */
+
+ void RemoveUnknownSubBlocks()
+ {
+ for (int i = SubBlocks.Size() - 1; i >= 0; i--)
+ if (SubBlocks[i].ID != NFileHeader::NExtraID::kWzAES)
+ SubBlocks.Delete(i);
+ }
+};
+
+
+class CLocalItem
+{
+public:
+ CVersion ExtractVersion;
+ UInt16 Flags;
+ UInt16 CompressionMethod;
+ UInt32 Time;
+ UInt32 FileCRC;
+ UInt64 PackSize;
+ UInt64 UnPackSize;
+
+ AString Name;
+
+ CExtraBlock LocalExtra;
+
+ 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() || CompressionMethod == NFileHeader::NCompressionMethod::kWzAES); };
+
+ bool IsLzmaEOS() const { return (Flags & NFileHeader::NFlags::kLzmaEOS) != 0; }
+
+ bool IsDir() const;
+ bool IgnoreItem() const { return false; }
+ UInt32 GetWinAttributes() const;
+
+ bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; }
+
+ UString GetUnicodeString(const AString &s) const
+ {
+ UString res;
+ if (IsUtf8())
+ if (!ConvertUTF8ToUnicode(s, res))
+ res.Empty();
+ if (res.IsEmpty())
+ res = MultiByteToUnicodeString(s, GetCodePage());
+ return res;
+ }
+
+private:
+ void SetFlagBits(int startBitNumber, int numBits, int value);
+ void SetBitMask(int bitMask, bool enable);
+public:
+ void ClearFlags() { Flags = 0; }
+ void SetEncrypted(bool encrypted);
+ void SetUtf8(bool isUtf8);
+
+ WORD GetCodePage() const { return CP_OEMCP; }
+};
+
+class CItem: public CLocalItem
+{
+public:
+ CVersion MadeByVersion;
+ UInt16 InternalAttributes;
+ UInt32 ExternalAttributes;
+
+ UInt64 LocalHeaderPosition;
+
+ FILETIME NtfsMTime;
+ FILETIME NtfsATime;
+ FILETIME NtfsCTime;
+
+ CExtraBlock CentralExtra;
+ CByteBuffer Comment;
+
+ bool FromLocal;
+ bool FromCentral;
+ bool NtfsTimeIsDefined;
+
+ bool IsDir() const;
+ UInt32 GetWinAttributes() const;
+
+ bool IsThereCrc() const
+ {
+ if (CompressionMethod == NFileHeader::NCompressionMethod::kWzAES)
+ {
+ CWzAesExtraField aesField;
+ if (CentralExtra.GetWzAesField(aesField))
+ return aesField.NeedCrc();
+ }
+ return (FileCRC != 0 || !IsDir());
+ }
+
+ WORD GetCodePage() const
+ {
+ return (WORD)((MadeByVersion.HostOS == NFileHeader::NHostOS::kFAT
+ || MadeByVersion.HostOS == NFileHeader::NHostOS::kNTFS
+ ) ? CP_OEMCP : CP_ACP);
+ }
+ CItem() : FromLocal(false), FromCentral(false), NtfsTimeIsDefined(false) {}
+};
+
+}}
+
+#endif
+
+
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItemEx.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItemEx.h
new file mode 100644
index 000000000..ab62cdbb4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItemEx.h
@@ -0,0 +1,34 @@
+// Archive/ZipItemEx.h
+
+#ifndef __ARCHIVE_ZIP_ITEMEX_H
+#define __ARCHIVE_ZIP_ITEMEX_H
+
+#include "ZipHeader.h"
+#include "ZipItem.h"
+
+namespace NArchive {
+namespace NZip {
+
+class CItemEx: public CItem
+{
+public:
+ UInt32 FileHeaderWithNameSize;
+ UInt16 LocalExtraSize;
+
+ UInt64 GetLocalFullSize() const
+ { return FileHeaderWithNameSize + LocalExtraSize + PackSize +
+ (HasDescriptor() ? NFileHeader::kDataDescriptorSize : 0); };
+ /*
+ UInt64 GetLocalFullSize(bool isZip64) const
+ { return FileHeaderWithNameSize + LocalExtraSize + PackSize +
+ (HasDescriptor() ? (isZip64 ? NFileHeader::kDataDescriptor64Size : NFileHeader::kDataDescriptorSize) : 0); };
+ */
+ UInt64 GetLocalExtraPosition() const
+ { return LocalHeaderPosition + FileHeaderWithNameSize; };
+ UInt64 GetDataPosition() const
+ { return GetLocalExtraPosition() + LocalExtraSize; };
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.cpp
new file mode 100644
index 000000000..aa82143e3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.cpp
@@ -0,0 +1,289 @@
+// ZipOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/OffsetStream.h"
+
+#include "ZipOut.h"
+
+namespace NArchive {
+namespace NZip {
+
+void COutArchive::Create(IOutStream *outStream)
+{
+ if (!m_OutBuffer.Create(1 << 16))
+ throw CSystemException(E_OUTOFMEMORY);
+ m_Stream = outStream;
+ m_OutBuffer.SetStream(outStream);
+ m_OutBuffer.Init();
+ m_BasePosition = 0;
+}
+
+void COutArchive::MoveBasePosition(UInt64 distanceToMove)
+{
+ m_BasePosition += distanceToMove; // test overflow
+}
+
+void COutArchive::PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption)
+{
+ m_IsZip64 = isZip64;
+ m_ExtraSize = isZip64 ? (4 + 8 + 8) : 0;
+ if (aesEncryption)
+ m_ExtraSize += 4 + 7;
+ m_LocalFileHeaderSize = 4 + NFileHeader::kLocalBlockSize + fileNameLength + m_ExtraSize;
+}
+
+void COutArchive::PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption)
+{
+ // We test it to 0xF8000000 to support case when compressed size
+ // can be larger than uncompressed size.
+ PrepareWriteCompressedDataZip64(fileNameLength, unPackSize >= 0xF8000000, aesEncryption);
+}
+
+void COutArchive::PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption)
+{
+ bool isUnPack64 = unPackSize >= 0xFFFFFFFF;
+ bool isPack64 = packSize >= 0xFFFFFFFF;
+ bool isZip64 = isPack64 || isUnPack64;
+ PrepareWriteCompressedDataZip64(fileNameLength, isZip64, aesEncryption);
+}
+
+void COutArchive::WriteBytes(const void *buffer, UInt32 size)
+{
+ m_OutBuffer.WriteBytes(buffer, size);
+ m_BasePosition += size;
+}
+
+void COutArchive::WriteByte(Byte b)
+{
+ WriteBytes(&b, 1);
+}
+
+void COutArchive::WriteUInt16(UInt16 value)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+void COutArchive::WriteUInt32(UInt32 value)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+void COutArchive::WriteUInt64(UInt64 value)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+void COutArchive::WriteExtra(const CExtraBlock &extra)
+{
+ if (extra.SubBlocks.Size() != 0)
+ {
+ for (int i = 0; i < extra.SubBlocks.Size(); i++)
+ {
+ const CExtraSubBlock &subBlock = extra.SubBlocks[i];
+ WriteUInt16(subBlock.ID);
+ WriteUInt16((UInt16)subBlock.Data.GetCapacity());
+ WriteBytes(subBlock.Data, (UInt32)subBlock.Data.GetCapacity());
+ }
+ }
+}
+
+void COutArchive::SeekTo(UInt64 offset)
+{
+ HRESULT res = m_Stream->Seek(offset, STREAM_SEEK_SET, NULL);
+ if (res != S_OK)
+ throw CSystemException(res);
+}
+
+void COutArchive::WriteLocalHeader(const CLocalItem &item)
+{
+ SeekTo(m_BasePosition);
+
+ bool isZip64 = m_IsZip64 || item.PackSize >= 0xFFFFFFFF || item.UnPackSize >= 0xFFFFFFFF;
+
+ WriteUInt32(NSignature::kLocalFileHeader);
+ {
+ Byte ver = item.ExtractVersion.Version;
+ if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
+ ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
+ WriteByte(ver);
+ }
+ WriteByte(item.ExtractVersion.HostOS);
+ WriteUInt16(item.Flags);
+ WriteUInt16(item.CompressionMethod);
+ WriteUInt32(item.Time);
+ WriteUInt32(item.FileCRC);
+ WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.PackSize);
+ WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize);
+ WriteUInt16((UInt16)item.Name.Length());
+ {
+ UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 16): 0) + item.LocalExtra.GetSize());
+ if (localExtraSize > m_ExtraSize)
+ throw CSystemException(E_FAIL);
+ }
+ WriteUInt16((UInt16)m_ExtraSize); // test it;
+ WriteBytes((const char *)item.Name, item.Name.Length());
+
+ UInt32 extraPos = 0;
+ if (isZip64)
+ {
+ extraPos += 4 + 16;
+ WriteUInt16(NFileHeader::NExtraID::kZip64);
+ WriteUInt16(16);
+ WriteUInt64(item.UnPackSize);
+ WriteUInt64(item.PackSize);
+ }
+
+ WriteExtra(item.LocalExtra);
+ extraPos += (UInt32)item.LocalExtra.GetSize();
+ for (; extraPos < m_ExtraSize; extraPos++)
+ WriteByte(0);
+
+ m_OutBuffer.FlushWithCheck();
+ MoveBasePosition(item.PackSize);
+ SeekTo(m_BasePosition);
+}
+
+void COutArchive::WriteCentralHeader(const CItem &item)
+{
+ bool isUnPack64 = item.UnPackSize >= 0xFFFFFFFF;
+ bool isPack64 = item.PackSize >= 0xFFFFFFFF;
+ bool isPosition64 = item.LocalHeaderPosition >= 0xFFFFFFFF;
+ bool isZip64 = isPack64 || isUnPack64 || isPosition64;
+
+ WriteUInt32(NSignature::kCentralFileHeader);
+ WriteByte(item.MadeByVersion.Version);
+ WriteByte(item.MadeByVersion.HostOS);
+ {
+ Byte ver = item.ExtractVersion.Version;
+ if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
+ ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
+ WriteByte(ver);
+ }
+ WriteByte(item.ExtractVersion.HostOS);
+ WriteUInt16(item.Flags);
+ WriteUInt16(item.CompressionMethod);
+ WriteUInt32(item.Time);
+ WriteUInt32(item.FileCRC);
+ WriteUInt32(isPack64 ? 0xFFFFFFFF: (UInt32)item.PackSize);
+ WriteUInt32(isUnPack64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize);
+ WriteUInt16((UInt16)item.Name.Length());
+ UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
+ const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8);
+ UInt16 centralExtraSize = (UInt16)(isZip64 ? (4 + zip64ExtraSize) : 0) + (item.NtfsTimeIsDefined ? (4 + kNtfsExtraSize) : 0);
+ centralExtraSize = (UInt16)(centralExtraSize + item.CentralExtra.GetSize());
+ WriteUInt16(centralExtraSize); // test it;
+ WriteUInt16((UInt16)item.Comment.GetCapacity());
+ WriteUInt16(0); // DiskNumberStart;
+ WriteUInt16(item.InternalAttributes);
+ WriteUInt32(item.ExternalAttributes);
+ WriteUInt32(isPosition64 ? 0xFFFFFFFF: (UInt32)item.LocalHeaderPosition);
+ WriteBytes((const char *)item.Name, item.Name.Length());
+ if (isZip64)
+ {
+ WriteUInt16(NFileHeader::NExtraID::kZip64);
+ WriteUInt16(zip64ExtraSize);
+ if(isUnPack64)
+ WriteUInt64(item.UnPackSize);
+ if(isPack64)
+ WriteUInt64(item.PackSize);
+ if(isPosition64)
+ WriteUInt64(item.LocalHeaderPosition);
+ }
+ if (item.NtfsTimeIsDefined)
+ {
+ WriteUInt16(NFileHeader::NExtraID::kNTFS);
+ WriteUInt16(kNtfsExtraSize);
+ WriteUInt32(0); // reserved
+ WriteUInt16(NFileHeader::NNtfsExtra::kTagTime);
+ WriteUInt16(8 * 3);
+ WriteUInt32(item.NtfsMTime.dwLowDateTime);
+ WriteUInt32(item.NtfsMTime.dwHighDateTime);
+ WriteUInt32(item.NtfsATime.dwLowDateTime);
+ WriteUInt32(item.NtfsATime.dwHighDateTime);
+ WriteUInt32(item.NtfsCTime.dwLowDateTime);
+ WriteUInt32(item.NtfsCTime.dwHighDateTime);
+ }
+ WriteExtra(item.CentralExtra);
+ if (item.Comment.GetCapacity() > 0)
+ WriteBytes(item.Comment, (UInt32)item.Comment.GetCapacity());
+}
+
+void COutArchive::WriteCentralDir(const CObjectVector<CItem> &items, const CByteBuffer *comment)
+{
+ SeekTo(m_BasePosition);
+
+ UInt64 cdOffset = GetCurrentPosition();
+ for(int i = 0; i < items.Size(); i++)
+ WriteCentralHeader(items[i]);
+ UInt64 cd64EndOffset = GetCurrentPosition();
+ UInt64 cdSize = cd64EndOffset - cdOffset;
+ bool cdOffset64 = cdOffset >= 0xFFFFFFFF;
+ bool cdSize64 = cdSize >= 0xFFFFFFFF;
+ bool items64 = items.Size() >= 0xFFFF;
+ bool isZip64 = (cdOffset64 || cdSize64 || items64);
+
+ if (isZip64)
+ {
+ WriteUInt32(NSignature::kZip64EndOfCentralDir);
+ WriteUInt64(kZip64EcdSize); // ThisDiskNumber = 0;
+ WriteUInt16(45); // version
+ WriteUInt16(45); // version
+ WriteUInt32(0); // ThisDiskNumber = 0;
+ WriteUInt32(0); // StartCentralDirectoryDiskNumber;;
+ WriteUInt64((UInt64)items.Size());
+ WriteUInt64((UInt64)items.Size());
+ WriteUInt64((UInt64)cdSize);
+ WriteUInt64((UInt64)cdOffset);
+
+ WriteUInt32(NSignature::kZip64EndOfCentralDirLocator);
+ WriteUInt32(0); // number of the disk with the start of the zip64 end of central directory
+ WriteUInt64(cd64EndOffset);
+ WriteUInt32(1); // total number of disks
+ }
+ WriteUInt32(NSignature::kEndOfCentralDir);
+ WriteUInt16(0); // ThisDiskNumber = 0;
+ WriteUInt16(0); // StartCentralDirectoryDiskNumber;
+ WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size()));
+ WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size()));
+ WriteUInt32(cdSize64 ? 0xFFFFFFFF: (UInt32)cdSize);
+ WriteUInt32(cdOffset64 ? 0xFFFFFFFF: (UInt32)cdOffset);
+ UInt32 commentSize = (UInt32)(comment ? comment->GetCapacity() : 0);
+ WriteUInt16((UInt16)commentSize);
+ if (commentSize > 0)
+ WriteBytes((const Byte *)*comment, commentSize);
+ m_OutBuffer.FlushWithCheck();
+}
+
+void COutArchive::CreateStreamForCompressing(IOutStream **outStream)
+{
+ COffsetOutStream *streamSpec = new COffsetOutStream;
+ CMyComPtr<IOutStream> tempStream(streamSpec);
+ streamSpec->Init(m_Stream, m_BasePosition + m_LocalFileHeaderSize);
+ *outStream = tempStream.Detach();
+}
+
+void COutArchive::SeekToPackedDataPosition()
+{
+ SeekTo(m_BasePosition + m_LocalFileHeaderSize);
+}
+
+void COutArchive::CreateStreamForCopying(ISequentialOutStream **outStream)
+{
+ CMyComPtr<ISequentialOutStream> tempStream(m_Stream);
+ *outStream = tempStream.Detach();
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.h
new file mode 100644
index 000000000..2f6349e5c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.h
@@ -0,0 +1,56 @@
+// ZipOut.h
+
+#ifndef __ZIP_OUT_H
+#define __ZIP_OUT_H
+
+#include "Common/MyCom.h"
+
+#include "../../IStream.h"
+#include "../../Common/OutBuffer.h"
+
+#include "ZipItem.h"
+
+namespace NArchive {
+namespace NZip {
+
+// can throw CSystemException and COutBufferException
+
+class COutArchive
+{
+ CMyComPtr<IOutStream> m_Stream;
+ COutBuffer m_OutBuffer;
+
+ UInt64 m_BasePosition;
+ UInt32 m_LocalFileHeaderSize;
+ UInt32 m_ExtraSize;
+ bool m_IsZip64;
+
+ void WriteBytes(const void *buffer, UInt32 size);
+ void WriteByte(Byte b);
+ void WriteUInt16(UInt16 value);
+ void WriteUInt32(UInt32 value);
+ void WriteUInt64(UInt64 value);
+
+ void WriteExtraHeader(const CItem &item);
+ void WriteCentralHeader(const CItem &item);
+ void WriteExtra(const CExtraBlock &extra);
+ void SeekTo(UInt64 offset);
+public:
+ void Create(IOutStream *outStream);
+ void MoveBasePosition(UInt64 distanceToMove);
+ UInt64 GetCurrentPosition() const { return m_BasePosition; };
+ void PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption);
+ void PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption);
+ void PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption);
+ void WriteLocalHeader(const CLocalItem &item);
+
+ void WriteCentralDir(const CObjectVector<CItem> &items, const CByteBuffer *comment);
+
+ void CreateStreamForCompressing(IOutStream **outStream);
+ void CreateStreamForCopying(ISequentialOutStream **outStream);
+ void SeekToPackedDataPosition();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipRegister.cpp
new file mode 100644
index 000000000..3e7aade85
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipRegister.cpp
@@ -0,0 +1,18 @@
+// ZipRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "ZipHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NZip::CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new NArchive::NZip::CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"zip", L"zip jar xpi odt ods docx xlsx", 0, 1, { 0x50, 0x4B, 0x03, 0x04 }, 4, false, CreateArc, CreateArcOut };
+
+REGISTER_ARC(Zip)
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.cpp
new file mode 100644
index 000000000..d4fdee3d7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.cpp
@@ -0,0 +1,1068 @@
+// ZipUpdate.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Alloc.h"
+
+#include "Common/AutoPtr.h"
+#include "Common/Defs.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/Defs.h"
+#include "Windows/Thread.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/OutMemStream.h"
+#include "../../Common/ProgressUtils.h"
+#ifndef _7ZIP_ST
+#include "../../Common/ProgressMt.h"
+#endif
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "ZipAddCommon.h"
+#include "ZipOut.h"
+#include "ZipUpdate.h"
+
+using namespace NWindows;
+using namespace NSynchronization;
+
+namespace NArchive {
+namespace NZip {
+
+static const Byte kHostOS =
+ #ifdef _WIN32
+ NFileHeader::NHostOS::kFAT;
+ #else
+ NFileHeader::NHostOS::kUnix;
+ #endif
+
+static const Byte kMadeByHostOS = kHostOS;
+static const Byte kExtractHostOS = kHostOS;
+
+static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStored;
+
+static HRESULT CopyBlockToArchive(ISequentialInStream *inStream,
+ COutArchive &outArchive, ICompressProgressInfo *progress)
+{
+ CMyComPtr<ISequentialOutStream> outStream;
+ outArchive.CreateStreamForCopying(&outStream);
+ return NCompress::CopyStream(inStream, outStream, progress);
+}
+
+static HRESULT WriteRange(IInStream *inStream, COutArchive &outArchive,
+ const CUpdateRange &range, ICompressProgressInfo *progress)
+{
+ UInt64 position;
+ RINOK(inStream->Seek(range.Position, STREAM_SEEK_SET, &position));
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
+ streamSpec->SetStream(inStream);
+ streamSpec->Init(range.Size);
+
+ RINOK(CopyBlockToArchive(inStreamLimited, outArchive, progress));
+ return progress->SetRatioInfo(&range.Size, &range.Size);
+}
+
+static void SetFileHeader(
+ COutArchive &archive,
+ const CCompressionMethodMode &options,
+ const CUpdateItem &ui,
+ CItem &item)
+{
+ item.UnPackSize = ui.Size;
+ bool isDir;
+
+ item.ClearFlags();
+
+ if (ui.NewProperties)
+ {
+ isDir = ui.IsDir;
+ item.Name = ui.Name;
+ item.SetUtf8(ui.IsUtf8);
+ item.ExternalAttributes = ui.Attributes;
+ item.Time = ui.Time;
+ item.NtfsMTime = ui.NtfsMTime;
+ item.NtfsATime = ui.NtfsATime;
+ item.NtfsCTime = ui.NtfsCTime;
+ item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
+ }
+ else
+ isDir = item.IsDir();
+
+ item.LocalHeaderPosition = archive.GetCurrentPosition();
+ item.MadeByVersion.HostOS = kMadeByHostOS;
+ item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion;
+
+ item.ExtractVersion.HostOS = kExtractHostOS;
+
+ item.InternalAttributes = 0; // test it
+ item.SetEncrypted(!isDir && options.PasswordIsDefined);
+ if (isDir)
+ {
+ item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir;
+ item.CompressionMethod = kMethodForDirectory;
+ item.PackSize = 0;
+ item.FileCRC = 0; // test it
+ }
+}
+
+static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult,
+ bool isAesMode, Byte aesKeyMode, CItem &item)
+{
+ item.ExtractVersion.Version = compressingResult.ExtractVersion;
+ item.CompressionMethod = compressingResult.Method;
+ item.FileCRC = compressingResult.CRC;
+ item.UnPackSize = compressingResult.UnpackSize;
+ item.PackSize = compressingResult.PackSize;
+
+ item.LocalExtra.Clear();
+ item.CentralExtra.Clear();
+
+ if (isAesMode)
+ {
+ CWzAesExtraField wzAesField;
+ wzAesField.Strength = aesKeyMode;
+ wzAesField.Method = compressingResult.Method;
+ item.CompressionMethod = NFileHeader::NCompressionMethod::kWzAES;
+ item.FileCRC = 0;
+ CExtraSubBlock sb;
+ wzAesField.SetSubBlock(sb);
+ item.LocalExtra.SubBlocks.Add(sb);
+ item.CentralExtra.SubBlocks.Add(sb);
+ }
+}
+
+#ifndef _7ZIP_ST
+
+static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo);
+
+struct CThreadInfo
+{
+ #ifdef EXTERNAL_CODECS
+ CMyComPtr<ICompressCodecsInfo> _codecsInfo;
+ const CObjectVector<CCodecInfoEx> *_externalCodecs;
+ #endif
+
+ NWindows::CThread Thread;
+ NWindows::NSynchronization::CAutoResetEvent CompressEvent;
+ NWindows::NSynchronization::CAutoResetEvent CompressionCompletedEvent;
+ bool ExitThread;
+
+ CMtCompressProgress *ProgressSpec;
+ CMyComPtr<ICompressProgressInfo> Progress;
+
+ COutMemStream *OutStreamSpec;
+ CMyComPtr<IOutStream> OutStream;
+ CMyComPtr<ISequentialInStream> InStream;
+
+ CAddCommon Coder;
+ HRESULT Result;
+ CCompressingResult CompressingResult;
+
+ bool IsFree;
+ UInt32 UpdateIndex;
+
+ CThreadInfo(const CCompressionMethodMode &options):
+ ExitThread(false),
+ ProgressSpec(0),
+ OutStreamSpec(0),
+ Coder(options)
+ {}
+
+ HRESULT CreateEvents()
+ {
+ RINOK(CompressEvent.CreateIfNotCreated());
+ return CompressionCompletedEvent.CreateIfNotCreated();
+ }
+ HRes CreateThread() { return Thread.Create(CoderThread, this); }
+
+ void WaitAndCode();
+ void StopWaitClose()
+ {
+ ExitThread = true;
+ if (OutStreamSpec != 0)
+ OutStreamSpec->StopWriting(E_ABORT);
+ if (CompressEvent.IsCreated())
+ CompressEvent.Set();
+ Thread.Wait();
+ Thread.Close();
+ }
+
+};
+
+void CThreadInfo::WaitAndCode()
+{
+ for (;;)
+ {
+ CompressEvent.Lock();
+ if (ExitThread)
+ return;
+ Result = Coder.Compress(
+ #ifdef EXTERNAL_CODECS
+ _codecsInfo, _externalCodecs,
+ #endif
+ InStream, OutStream, Progress, CompressingResult);
+ if (Result == S_OK && Progress)
+ Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize);
+ CompressionCompletedEvent.Set();
+ }
+}
+
+static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo)
+{
+ ((CThreadInfo *)threadCoderInfo)->WaitAndCode();
+ return 0;
+}
+
+class CThreads
+{
+public:
+ CObjectVector<CThreadInfo> Threads;
+ ~CThreads()
+ {
+ for (int i = 0; i < Threads.Size(); i++)
+ Threads[i].StopWaitClose();
+ }
+};
+
+struct CMemBlocks2: public CMemLockBlocks
+{
+ CCompressingResult CompressingResult;
+ bool Defined;
+ bool Skip;
+ CMemBlocks2(): Defined(false), Skip(false) {}
+};
+
+class CMemRefs
+{
+public:
+ CMemBlockManagerMt *Manager;
+ CObjectVector<CMemBlocks2> Refs;
+ CMemRefs(CMemBlockManagerMt *manager): Manager(manager) {} ;
+ ~CMemRefs()
+ {
+ for (int i = 0; i < Refs.Size(); i++)
+ Refs[i].FreeOpt(Manager);
+ }
+};
+
+class CMtProgressMixer2:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ UInt64 ProgressOffset;
+ UInt64 InSizes[2];
+ UInt64 OutSizes[2];
+ CMyComPtr<IProgress> Progress;
+ CMyComPtr<ICompressProgressInfo> RatioProgress;
+ bool _inSizeIsMain;
+public:
+ NWindows::NSynchronization::CCriticalSection CriticalSection;
+ MY_UNKNOWN_IMP
+ void Create(IProgress *progress, bool inSizeIsMain);
+ void SetProgressOffset(UInt64 progressOffset);
+ HRESULT SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize);
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+void CMtProgressMixer2::Create(IProgress *progress, bool inSizeIsMain)
+{
+ Progress = progress;
+ Progress.QueryInterface(IID_ICompressProgressInfo, &RatioProgress);
+ _inSizeIsMain = inSizeIsMain;
+ ProgressOffset = InSizes[0] = InSizes[1] = OutSizes[0] = OutSizes[1] = 0;
+}
+
+void CMtProgressMixer2::SetProgressOffset(UInt64 progressOffset)
+{
+ CriticalSection.Enter();
+ InSizes[1] = OutSizes[1] = 0;
+ ProgressOffset = progressOffset;
+ CriticalSection.Leave();
+}
+
+HRESULT CMtProgressMixer2::SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ if (index == 0 && RatioProgress)
+ {
+ RINOK(RatioProgress->SetRatioInfo(inSize, outSize));
+ }
+ if (inSize != 0)
+ InSizes[index] = *inSize;
+ if (outSize != 0)
+ OutSizes[index] = *outSize;
+ UInt64 v = ProgressOffset + (_inSizeIsMain ?
+ (InSizes[0] + InSizes[1]) :
+ (OutSizes[0] + OutSizes[1]));
+ return Progress->SetCompleted(&v);
+}
+
+STDMETHODIMP CMtProgressMixer2::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ return SetRatioInfo(0, inSize, outSize);
+}
+
+class CMtProgressMixer:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+public:
+ CMtProgressMixer2 *Mixer2;
+ CMyComPtr<ICompressProgressInfo> RatioProgress;
+ void Create(IProgress *progress, bool inSizeIsMain);
+ MY_UNKNOWN_IMP
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+void CMtProgressMixer::Create(IProgress *progress, bool inSizeIsMain)
+{
+ Mixer2 = new CMtProgressMixer2;
+ RatioProgress = Mixer2;
+ Mixer2->Create(progress, inSizeIsMain);
+}
+
+STDMETHODIMP CMtProgressMixer::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ return Mixer2->SetRatioInfo(1, inSize, outSize);
+}
+
+
+#endif
+
+
+static HRESULT UpdateItemOldData(COutArchive &archive,
+ IInStream *inStream,
+ const CUpdateItem &ui, CItemEx &item,
+ /* bool izZip64, */
+ ICompressProgressInfo *progress,
+ UInt64 &complexity)
+{
+ if (ui.NewProperties)
+ {
+ if (item.HasDescriptor())
+ return E_NOTIMPL;
+
+ // use old name size.
+ // CUpdateRange range(item.GetLocalExtraPosition(), item.LocalExtraSize + item.PackSize);
+ CUpdateRange range(item.GetDataPosition(), item.PackSize);
+
+ // item.ExternalAttributes = ui.Attributes;
+ // Test it
+ item.Name = ui.Name;
+ item.SetUtf8(ui.IsUtf8);
+ item.Time = ui.Time;
+ item.NtfsMTime = ui.NtfsMTime;
+ item.NtfsATime = ui.NtfsATime;
+ item.NtfsCTime = ui.NtfsCTime;
+ item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
+
+ item.CentralExtra.RemoveUnknownSubBlocks();
+ item.LocalExtra.RemoveUnknownSubBlocks();
+
+ archive.PrepareWriteCompressedData2((UInt16)item.Name.Length(), item.UnPackSize, item.PackSize, item.LocalExtra.HasWzAesField());
+ item.LocalHeaderPosition = archive.GetCurrentPosition();
+ archive.SeekToPackedDataPosition();
+ RINOK(WriteRange(inStream, archive, range, progress));
+ complexity += range.Size;
+ archive.WriteLocalHeader(item);
+ }
+ else
+ {
+ CUpdateRange range(item.LocalHeaderPosition, item.GetLocalFullSize());
+
+ // set new header position
+ item.LocalHeaderPosition = archive.GetCurrentPosition();
+
+ RINOK(WriteRange(inStream, archive, range, progress));
+ complexity += range.Size;
+ archive.MoveBasePosition(range.Size);
+ }
+ return S_OK;
+}
+
+static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options,
+ const CUpdateItem &ui, CItemEx &item)
+{
+ SetFileHeader(archive, *options, ui, item);
+ archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsAesMode);
+ archive.WriteLocalHeader(item);
+}
+
+static HRESULT Update2St(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ COutArchive &archive,
+ CInArchive *inArchive,
+ IInStream *inStream,
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ const CCompressionMethodMode *options,
+ const CByteBuffer *comment,
+ IArchiveUpdateCallback *updateCallback)
+{
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CAddCommon compressor(*options);
+
+ CObjectVector<CItem> items;
+ UInt64 unpackSizeTotal = 0, packSizeTotal = 0;
+
+ for (int itemIndex = 0; itemIndex < updateItems.Size(); itemIndex++)
+ {
+ lps->InSize = unpackSizeTotal;
+ lps->OutSize = packSizeTotal;
+ RINOK(lps->SetCur());
+ const CUpdateItem &ui = updateItems[itemIndex];
+ CItemEx item;
+ if (!ui.NewProperties || !ui.NewData)
+ {
+ item = inputItems[ui.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ return E_NOTIMPL;
+ }
+
+ if (ui.NewData)
+ {
+ bool isDir = ((ui.NewProperties) ? ui.IsDir : item.IsDir());
+ if (isDir)
+ {
+ WriteDirHeader(archive, options, ui, item);
+ }
+ else
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+ HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
+ if (res == S_FALSE)
+ {
+ lps->ProgressOffset += ui.Size;
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ continue;
+ }
+ RINOK(res);
+
+ // file Size can be 64-bit !!!
+ SetFileHeader(archive, *options, ui, item);
+ archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsAesMode);
+ CCompressingResult compressingResult;
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(&outStream);
+ RINOK(compressor.Compress(
+ EXTERNAL_CODECS_LOC_VARS
+ fileInStream, outStream, progress, compressingResult));
+ SetItemInfoFromCompressingResult(compressingResult, options->IsAesMode, options->AesKeyMode, item);
+ archive.WriteLocalHeader(item);
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ unpackSizeTotal += item.UnPackSize;
+ packSizeTotal += item.PackSize;
+ }
+ }
+ else
+ {
+ UInt64 complexity = 0;
+ lps->SendRatio = false;
+ RINOK(UpdateItemOldData(archive, inStream, ui, item, progress, complexity));
+ lps->SendRatio = true;
+ lps->ProgressOffset += complexity;
+ }
+ items.Add(item);
+ lps->ProgressOffset += NFileHeader::kLocalBlockSize;
+ }
+ archive.WriteCentralDir(items, comment);
+ return S_OK;
+}
+
+static HRESULT Update2(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ COutArchive &archive,
+ CInArchive *inArchive,
+ IInStream *inStream,
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ const CCompressionMethodMode *options,
+ const CByteBuffer *comment,
+ IArchiveUpdateCallback *updateCallback)
+{
+ UInt64 complexity = 0;
+ UInt64 numFilesToCompress = 0;
+ UInt64 numBytesToCompress = 0;
+
+ int i;
+ for(i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ {
+ complexity += ui.Size;
+ numBytesToCompress += ui.Size;
+ numFilesToCompress++;
+ /*
+ if (ui.Commented)
+ complexity += ui.CommentRange.Size;
+ */
+ }
+ else
+ {
+ CItemEx inputItem = inputItems[ui.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(inputItem) != S_OK)
+ return E_NOTIMPL;
+ complexity += inputItem.GetLocalFullSize();
+ // complexity += inputItem.GetCentralExtraPlusCommentSize();
+ }
+ complexity += NFileHeader::kLocalBlockSize;
+ complexity += NFileHeader::kCentralBlockSize;
+ }
+
+ if (comment)
+ complexity += comment->GetCapacity();
+ complexity++; // end of central
+ updateCallback->SetTotal(complexity);
+
+ CAddCommon compressor(*options);
+
+ complexity = 0;
+
+ #ifndef _7ZIP_ST
+
+ const size_t kNumMaxThreads = (1 << 10);
+ UInt32 numThreads = options->NumThreads;
+ if (numThreads > kNumMaxThreads)
+ numThreads = kNumMaxThreads;
+
+ const size_t kMemPerThread = (1 << 25);
+ const size_t kBlockSize = 1 << 16;
+
+ CCompressionMethodMode options2;
+ if (options != 0)
+ options2 = *options;
+
+ bool mtMode = ((options != 0) && (numThreads > 1));
+
+ if (numFilesToCompress <= 1)
+ mtMode = false;
+
+ if (mtMode)
+ {
+ Byte method = options->MethodSequence.Front();
+ if (method == NFileHeader::NCompressionMethod::kStored && !options->PasswordIsDefined)
+ mtMode = false;
+ if (method == NFileHeader::NCompressionMethod::kBZip2)
+ {
+ UInt64 averageSize = numBytesToCompress / numFilesToCompress;
+ UInt32 blockSize = options->DicSize;
+ if (blockSize == 0)
+ blockSize = 1;
+ UInt64 averageNumberOfBlocks = averageSize / blockSize;
+ UInt32 numBZip2Threads = 32;
+ if (averageNumberOfBlocks < numBZip2Threads)
+ numBZip2Threads = (UInt32)averageNumberOfBlocks;
+ if (numBZip2Threads < 1)
+ numBZip2Threads = 1;
+ numThreads = numThreads / numBZip2Threads;
+ options2.NumThreads = numBZip2Threads;
+ if (numThreads <= 1)
+ mtMode = false;
+ }
+ if (method == NFileHeader::NCompressionMethod::kLZMA)
+ {
+ UInt32 numLZMAThreads = (options->Algo > 0 ? 2 : 1);
+ numThreads /= numLZMAThreads;
+ options2.NumThreads = numLZMAThreads;
+ if (numThreads <= 1)
+ mtMode = false;
+ }
+ }
+
+ if (!mtMode)
+ #endif
+ return Update2St(
+ EXTERNAL_CODECS_LOC_VARS
+ archive, inArchive,inStream,
+ inputItems, updateItems, options, comment, updateCallback);
+
+
+ #ifndef _7ZIP_ST
+
+ CObjectVector<CItem> items;
+
+ CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer;
+ CMyComPtr<ICompressProgressInfo> progress = mtProgressMixerSpec;
+ mtProgressMixerSpec->Create(updateCallback, true);
+
+ CMtCompressProgressMixer mtCompressProgressMixer;
+ mtCompressProgressMixer.Init(numThreads, mtProgressMixerSpec->RatioProgress);
+
+ CMemBlockManagerMt memManager(kBlockSize);
+ CMemRefs refs(&memManager);
+
+ CThreads threads;
+ CRecordVector<HANDLE> compressingCompletedEvents;
+ CRecordVector<int> threadIndices; // list threads in order of updateItems
+
+ {
+ RINOK(memManager.AllocateSpaceAlways((size_t)numThreads * (kMemPerThread / kBlockSize)));
+ for(i = 0; i < updateItems.Size(); i++)
+ refs.Refs.Add(CMemBlocks2());
+
+ UInt32 i;
+ for (i = 0; i < numThreads; i++)
+ threads.Threads.Add(CThreadInfo(options2));
+
+ for (i = 0; i < numThreads; i++)
+ {
+ CThreadInfo &threadInfo = threads.Threads[i];
+ #ifdef EXTERNAL_CODECS
+ threadInfo._codecsInfo = codecsInfo;
+ threadInfo._externalCodecs = externalCodecs;
+ #endif
+ RINOK(threadInfo.CreateEvents());
+ threadInfo.OutStreamSpec = new COutMemStream(&memManager);
+ RINOK(threadInfo.OutStreamSpec->CreateEvents());
+ threadInfo.OutStream = threadInfo.OutStreamSpec;
+ threadInfo.IsFree = true;
+ threadInfo.ProgressSpec = new CMtCompressProgress();
+ threadInfo.Progress = threadInfo.ProgressSpec;
+ threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i);
+ RINOK(threadInfo.CreateThread());
+ }
+ }
+ int mtItemIndex = 0;
+
+ int itemIndex = 0;
+ int lastRealStreamItemIndex = -1;
+
+ while (itemIndex < updateItems.Size())
+ {
+ if ((UInt32)threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size())
+ {
+ const CUpdateItem &ui = updateItems[mtItemIndex++];
+ if (!ui.NewData)
+ continue;
+ CItemEx item;
+ if (ui.NewProperties)
+ {
+ if (ui.IsDir)
+ continue;
+ }
+ else
+ {
+ item = inputItems[ui.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ return E_NOTIMPL;
+ if (item.IsDir())
+ continue;
+ }
+ CMyComPtr<ISequentialInStream> fileInStream;
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(mtProgressMixerSpec->Mixer2->CriticalSection);
+ HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
+ if (res == S_FALSE)
+ {
+ complexity += ui.Size;
+ complexity += NFileHeader::kLocalBlockSize;
+ mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ refs.Refs[mtItemIndex - 1].Skip = true;
+ continue;
+ }
+ RINOK(res);
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ }
+
+ for (UInt32 i = 0; i < numThreads; i++)
+ {
+ CThreadInfo &threadInfo = threads.Threads[i];
+ if (threadInfo.IsFree)
+ {
+ threadInfo.IsFree = false;
+ threadInfo.InStream = fileInStream;
+
+ // !!!!! we must release ref before sending event
+ // BUG was here in v4.43 and v4.44. It could change ref counter in two threads in same time
+ fileInStream.Release();
+
+ threadInfo.OutStreamSpec->Init();
+ threadInfo.ProgressSpec->Reinit();
+ threadInfo.CompressEvent.Set();
+ threadInfo.UpdateIndex = mtItemIndex - 1;
+
+ compressingCompletedEvents.Add(threadInfo.CompressionCompletedEvent);
+ threadIndices.Add(i);
+ break;
+ }
+ }
+ continue;
+ }
+
+ if (refs.Refs[itemIndex].Skip)
+ {
+ itemIndex++;
+ continue;
+ }
+
+ const CUpdateItem &ui = updateItems[itemIndex];
+
+ CItemEx item;
+ if (!ui.NewProperties || !ui.NewData)
+ {
+ item = inputItems[ui.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ return E_NOTIMPL;
+ }
+
+ if (ui.NewData)
+ {
+ bool isDir = ((ui.NewProperties) ? ui.IsDir : item.IsDir());
+ if (isDir)
+ {
+ WriteDirHeader(archive, options, ui, item);
+ }
+ else
+ {
+ if (lastRealStreamItemIndex < itemIndex)
+ {
+ lastRealStreamItemIndex = itemIndex;
+ SetFileHeader(archive, *options, ui, item);
+ // file Size can be 64-bit !!!
+ archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsAesMode);
+ }
+
+ CMemBlocks2 &memRef = refs.Refs[itemIndex];
+ if (memRef.Defined)
+ {
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(&outStream);
+ memRef.WriteToStream(memManager.GetBlockSize(), outStream);
+ SetItemInfoFromCompressingResult(memRef.CompressingResult,
+ options->IsAesMode, options->AesKeyMode, item);
+ SetFileHeader(archive, *options, ui, item);
+ archive.WriteLocalHeader(item);
+ // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ memRef.FreeOpt(&memManager);
+ }
+ else
+ {
+ {
+ CThreadInfo &thread = threads.Threads[threadIndices.Front()];
+ if (!thread.OutStreamSpec->WasUnlockEventSent())
+ {
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(&outStream);
+ thread.OutStreamSpec->SetOutStream(outStream);
+ thread.OutStreamSpec->SetRealStreamMode();
+ }
+ }
+
+ DWORD result = ::WaitForMultipleObjects(compressingCompletedEvents.Size(),
+ &compressingCompletedEvents.Front(), FALSE, INFINITE);
+ int t = (int)(result - WAIT_OBJECT_0);
+ CThreadInfo &threadInfo = threads.Threads[threadIndices[t]];
+ threadInfo.InStream.Release();
+ threadInfo.IsFree = true;
+ RINOK(threadInfo.Result);
+ threadIndices.Delete(t);
+ compressingCompletedEvents.Delete(t);
+ if (t == 0)
+ {
+ RINOK(threadInfo.OutStreamSpec->WriteToRealStream());
+ threadInfo.OutStreamSpec->ReleaseOutStream();
+ SetItemInfoFromCompressingResult(threadInfo.CompressingResult,
+ options->IsAesMode, options->AesKeyMode, item);
+ SetFileHeader(archive, *options, ui, item);
+ archive.WriteLocalHeader(item);
+ }
+ else
+ {
+ CMemBlocks2 &memRef = refs.Refs[threadInfo.UpdateIndex];
+ threadInfo.OutStreamSpec->DetachData(memRef);
+ memRef.CompressingResult = threadInfo.CompressingResult;
+ memRef.Defined = true;
+ continue;
+ }
+ }
+ }
+ }
+ else
+ {
+ RINOK(UpdateItemOldData(archive, inStream, ui, item, progress, complexity));
+ }
+ items.Add(item);
+ complexity += NFileHeader::kLocalBlockSize;
+ mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
+ itemIndex++;
+ }
+ archive.WriteCentralDir(items, comment);
+ return S_OK;
+ #endif
+}
+
+static const size_t kCacheBlockSize = (1 << 20);
+static const size_t kCacheSize = (kCacheBlockSize << 2);
+static const size_t kCacheMask = (kCacheSize - 1);
+
+class CCacheOutStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IOutStream> _stream;
+ Byte *_cache;
+ UInt64 _virtPos;
+ UInt64 _virtSize;
+ UInt64 _phyPos;
+ UInt64 _phySize; // <= _virtSize
+ UInt64 _cachedPos; // (_cachedPos + _cachedSize) <= _virtSize
+ size_t _cachedSize;
+
+ HRESULT MyWrite(size_t size);
+ HRESULT MyWriteBlock()
+ {
+ return MyWrite(kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1)));
+ }
+ HRESULT FlushCache();
+public:
+ CCacheOutStream(): _cache(0) {}
+ ~CCacheOutStream();
+ bool Allocate();
+ HRESULT Init(IOutStream *stream);
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ STDMETHOD(SetSize)(UInt64 newSize);
+};
+
+bool CCacheOutStream::Allocate()
+{
+ if (!_cache)
+ _cache = (Byte *)::MidAlloc(kCacheSize);
+ return (_cache != NULL);
+}
+
+HRESULT CCacheOutStream::Init(IOutStream *stream)
+{
+ _virtPos = _phyPos = 0;
+ _stream = stream;
+ RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos));
+ RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize));
+ RINOK(_stream->Seek(_virtPos, STREAM_SEEK_SET, &_virtPos));
+ _phyPos = _virtPos;
+ _phySize = _virtSize;
+ _cachedPos = 0;
+ _cachedSize = 0;
+ return S_OK;
+}
+
+HRESULT CCacheOutStream::MyWrite(size_t size)
+{
+ while (size != 0 && _cachedSize != 0)
+ {
+ if (_phyPos != _cachedPos)
+ {
+ RINOK(_stream->Seek(_cachedPos, STREAM_SEEK_SET, &_phyPos));
+ }
+ size_t pos = (size_t)_cachedPos & kCacheMask;
+ size_t curSize = MyMin(kCacheSize - pos, _cachedSize);
+ curSize = MyMin(curSize, size);
+ RINOK(WriteStream(_stream, _cache + pos, curSize));
+ _phyPos += curSize;
+ if (_phySize < _phyPos)
+ _phySize = _phyPos;
+ _cachedPos += curSize;
+ _cachedSize -= curSize;
+ size -= curSize;
+ }
+ return S_OK;
+}
+
+HRESULT CCacheOutStream::FlushCache()
+{
+ return MyWrite(_cachedSize);
+}
+
+CCacheOutStream::~CCacheOutStream()
+{
+ FlushCache();
+ if (_virtSize != _phySize)
+ _stream->SetSize(_virtSize);
+ if (_virtPos != _phyPos)
+ _stream->Seek(_virtPos, STREAM_SEEK_SET, NULL);
+ ::MidFree(_cache);
+}
+
+STDMETHODIMP CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+
+ UInt64 zerosStart = _virtPos;
+ if (_cachedSize != 0)
+ {
+ if (_virtPos < _cachedPos)
+ {
+ RINOK(FlushCache());
+ }
+ else
+ {
+ UInt64 cachedEnd = _cachedPos + _cachedSize;
+ if (cachedEnd < _virtPos)
+ {
+ if (cachedEnd < _phySize)
+ {
+ RINOK(FlushCache());
+ }
+ else
+ zerosStart = cachedEnd;
+ }
+ }
+ }
+
+ if (_cachedSize == 0 && _phySize < _virtPos)
+ _cachedPos = zerosStart = _phySize;
+
+ if (zerosStart != _virtPos)
+ {
+ // write zeros to [cachedEnd ... _virtPos)
+
+ for (;;)
+ {
+ UInt64 cachedEnd = _cachedPos + _cachedSize;
+ size_t endPos = (size_t)cachedEnd & kCacheMask;
+ size_t curSize = kCacheSize - endPos;
+ if (curSize > _virtPos - cachedEnd)
+ curSize = (size_t)(_virtPos - cachedEnd);
+ if (curSize == 0)
+ break;
+ while (curSize > (kCacheSize - _cachedSize))
+ {
+ RINOK(MyWriteBlock());
+ }
+ memset(_cache + endPos, 0, curSize);
+ _cachedSize += curSize;
+ }
+ }
+
+ if (_cachedSize == 0)
+ _cachedPos = _virtPos;
+
+ size_t pos = (size_t)_virtPos & kCacheMask;
+ size = (UInt32)MyMin((size_t)size, kCacheSize - pos);
+ UInt64 cachedEnd = _cachedPos + _cachedSize;
+ if (_virtPos != cachedEnd) // _virtPos < cachedEnd
+ size = (UInt32)MyMin((size_t)size, (size_t)(cachedEnd - _virtPos));
+ else
+ {
+ // _virtPos == cachedEnd
+ if (_cachedSize == kCacheSize)
+ {
+ RINOK(MyWriteBlock());
+ }
+ size_t startPos = (size_t)_cachedPos & kCacheMask;
+ if (startPos > pos)
+ size = (UInt32)MyMin((size_t)size, (size_t)(startPos - pos));
+ _cachedSize += size;
+ }
+ memcpy(_cache + pos, data, size);
+ if (processedSize)
+ *processedSize = size;
+ _virtPos += size;
+ if (_virtSize < _virtPos)
+ _virtSize = _virtPos;
+ return S_OK;
+}
+
+STDMETHODIMP CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _virtPos = offset; break;
+ case STREAM_SEEK_CUR: _virtPos += offset; break;
+ case STREAM_SEEK_END: _virtPos = _virtSize + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+STDMETHODIMP CCacheOutStream::SetSize(UInt64 newSize)
+{
+ _virtSize = newSize;
+ if (newSize < _phySize)
+ {
+ RINOK(_stream->SetSize(newSize));
+ _phySize = newSize;
+ }
+ if (newSize <= _cachedPos)
+ {
+ _cachedSize = 0;
+ _cachedPos = newSize;
+ }
+ if (newSize < _cachedPos + _cachedSize)
+ _cachedSize = (size_t)(newSize - _cachedPos);
+ return S_OK;
+}
+
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ ISequentialOutStream *seqOutStream,
+ CInArchive *inArchive,
+ CCompressionMethodMode *compressionMethodMode,
+ IArchiveUpdateCallback *updateCallback)
+{
+ CMyComPtr<IOutStream> outStream;
+ {
+ CMyComPtr<IOutStream> outStreamReal;
+ seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal);
+ if (!outStreamReal)
+ return E_NOTIMPL;
+ CCacheOutStream *cacheStream = new CCacheOutStream();
+ outStream = cacheStream;
+ if (!cacheStream->Allocate())
+ return E_OUTOFMEMORY;
+ RINOK(cacheStream->Init(outStreamReal));
+ }
+
+ if (inArchive)
+ {
+ if (inArchive->ArcInfo.Base != 0 ||
+ inArchive->ArcInfo.StartPosition != 0 ||
+ !inArchive->IsOkHeaders)
+ return E_NOTIMPL;
+ }
+
+ COutArchive outArchive;
+ outArchive.Create(outStream);
+ /*
+ if (inArchive && inArchive->ArcInfo.StartPosition > 0)
+ {
+ CMyComPtr<ISequentialInStream> inStream;
+ inStream.Attach(inArchive->CreateLimitedStream(0, inArchive->ArcInfo.StartPosition));
+ RINOK(CopyBlockToArchive(inStream, outArchive, NULL));
+ outArchive.MoveBasePosition(inArchive->ArcInfo.StartPosition);
+ }
+ */
+ CMyComPtr<IInStream> inStream;
+ if (inArchive)
+ inStream.Attach(inArchive->CreateStream());
+
+ return Update2(
+ EXTERNAL_CODECS_LOC_VARS
+ outArchive, inArchive, inStream,
+ inputItems, updateItems,
+ compressionMethodMode,
+ inArchive ? &inArchive->ArcInfo.Comment : NULL,
+ updateCallback);
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.h
new file mode 100644
index 000000000..eee16738c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.h
@@ -0,0 +1,58 @@
+// Zip/Update.h
+
+#ifndef __ZIP_UPDATE_H
+#define __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 NewProperties;
+ bool IsDir;
+ bool NtfsTimeIsDefined;
+ bool IsUtf8;
+ int IndexInArchive;
+ int IndexInClient;
+ UInt32 Attributes;
+ UInt32 Time;
+ UInt64 Size;
+ AString Name;
+ // bool Commented;
+ // CUpdateRange CommentRange;
+ FILETIME NtfsMTime;
+ FILETIME NtfsATime;
+ FILETIME NtfsCTime;
+
+ CUpdateItem(): NtfsTimeIsDefined(false), IsUtf8(false), Size(0) {}
+};
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ ISequentialOutStream *seqOutStream,
+ CInArchive *inArchive,
+ CCompressionMethodMode *compressionMethodMode,
+ IArchiveUpdateCallback *updateCallback);
+
+}}
+
+#endif