summaryrefslogtreecommitdiffstats
path: root/src/libs/7zip/win/CPP/7zip/Archive/PeHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Archive/PeHandler.cpp')
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/PeHandler.cpp1752
1 files changed, 1752 insertions, 0 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/PeHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/PeHandler.cpp
new file mode 100644
index 000000000..c64067aa5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/PeHandler.cpp
@@ -0,0 +1,1752 @@
+// PeHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/DynamicBuffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariantUtils.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NPe {
+
+#define NUM_SCAN_SECTIONS_MAX (1 << 6)
+
+#define PE_SIG 0x00004550
+#define PE_OptHeader_Magic_32 0x10B
+#define PE_OptHeader_Magic_64 0x20B
+
+static AString GetDecString(UInt32 v)
+{
+ char sz[32];
+ ConvertUInt64ToString(v, sz);
+ return sz;
+}
+
+struct CVersion
+{
+ UInt16 Major;
+ UInt16 Minor;
+
+ void Parse(const Byte *buf);
+ AString GetString() const { return GetDecString(Major) + '.' + GetDecString(Minor); }
+};
+
+void CVersion::Parse(const Byte *p)
+{
+ Major = Get16(p);
+ Minor = Get16(p + 2);
+}
+
+static const UInt32 kHeaderSize = 4 + 20;
+
+struct CHeader
+{
+ UInt16 NumSections;
+ UInt32 Time;
+ UInt32 PointerToSymbolTable;
+ UInt32 NumSymbols;
+ UInt16 OptHeaderSize;
+ UInt16 Flags;
+ UInt16 Machine;
+
+ bool Parse(const Byte *buf);
+};
+
+bool CHeader::Parse(const Byte *p)
+{
+ if (Get32(p) != PE_SIG)
+ return false;
+ p += 4;
+ Machine = Get16(p + 0);
+ NumSections = Get16(p + 2);
+ Time = Get32(p + 4);
+ PointerToSymbolTable = Get32(p + 8);
+ NumSymbols = Get32(p + 12);
+ OptHeaderSize = Get16(p + 16);
+ Flags = Get16(p + 18);
+ return true;
+}
+
+struct CDirLink
+{
+ UInt32 Va;
+ UInt32 Size;
+ void Parse(const Byte *p);
+};
+
+void CDirLink::Parse(const Byte *p)
+{
+ Va = Get32(p);
+ Size = Get32(p + 4);
+}
+
+enum
+{
+ kDirLink_Certificate = 4,
+ kDirLink_Debug = 6
+};
+
+struct CDebugEntry
+{
+ UInt32 Flags;
+ UInt32 Time;
+ CVersion Ver;
+ UInt32 Type;
+ UInt32 Size;
+ UInt32 Va;
+ UInt32 Pa;
+
+ void Parse(const Byte *p);
+};
+
+void CDebugEntry::Parse(const Byte *p)
+{
+ Flags = Get32(p);
+ Time = Get32(p + 4);
+ Ver.Parse(p + 8);
+ Type = Get32(p + 12);
+ Size = Get32(p + 16);
+ Va = Get32(p + 20);
+ Pa = Get32(p + 24);
+}
+
+static const UInt32 kNumDirItemsMax = 16;
+
+struct COptHeader
+{
+ UInt16 Magic;
+ Byte LinkerVerMajor;
+ Byte LinkerVerMinor;
+
+ UInt32 CodeSize;
+ UInt32 InitDataSize;
+ UInt32 UninitDataSize;
+
+ // UInt32 AddressOfEntryPoint;
+ // UInt32 BaseOfCode;
+ // UInt32 BaseOfData32;
+ UInt64 ImageBase;
+
+ UInt32 SectAlign;
+ UInt32 FileAlign;
+
+ CVersion OsVer;
+ CVersion ImageVer;
+ CVersion SubsysVer;
+
+ UInt32 ImageSize;
+ UInt32 HeadersSize;
+ UInt32 CheckSum;
+ UInt16 SubSystem;
+ UInt16 DllCharacts;
+
+ UInt64 StackReserve;
+ UInt64 StackCommit;
+ UInt64 HeapReserve;
+ UInt64 HeapCommit;
+
+ UInt32 NumDirItems;
+ CDirLink DirItems[kNumDirItemsMax];
+
+ bool Is64Bit() const { return Magic == PE_OptHeader_Magic_64; }
+ bool Parse(const Byte *p, UInt32 size);
+
+ int GetNumFileAlignBits() const
+ {
+ for (int i = 9; i <= 16; i++)
+ if (((UInt32)1 << i) == FileAlign)
+ return i;
+ return -1;
+ }
+};
+
+bool COptHeader::Parse(const Byte *p, UInt32 size)
+{
+ Magic = Get16(p);
+ switch (Magic)
+ {
+ case PE_OptHeader_Magic_32:
+ case PE_OptHeader_Magic_64:
+ break;
+ default:
+ return false;
+ }
+ LinkerVerMajor = p[2];
+ LinkerVerMinor = p[3];
+
+ bool hdr64 = Is64Bit();
+
+ CodeSize = Get32(p + 4);
+ InitDataSize = Get32(p + 8);
+ UninitDataSize = Get32(p + 12);
+
+ // AddressOfEntryPoint = Get32(p + 16);
+ // BaseOfCode = Get32(p + 20);
+ // BaseOfData32 = hdr64 ? 0: Get32(p + 24);
+ ImageBase = hdr64 ? GetUi64(p + 24) : Get32(p + 28);
+
+ SectAlign = Get32(p + 32);
+ FileAlign = Get32(p + 36);
+
+ OsVer.Parse(p + 40);
+ ImageVer.Parse(p + 44);
+ SubsysVer.Parse(p + 48);
+
+ // reserved = Get32(p + 52);
+
+ ImageSize = Get32(p + 56);
+ HeadersSize = Get32(p + 60);
+ CheckSum = Get32(p + 64);
+ SubSystem = Get16(p + 68);
+ DllCharacts = Get16(p + 70);
+
+ if (hdr64)
+ {
+ StackReserve = Get64(p + 72);
+ StackCommit = Get64(p + 80);
+ HeapReserve = Get64(p + 88);
+ HeapCommit = Get64(p + 96);
+ }
+ else
+ {
+ StackReserve = Get32(p + 72);
+ StackCommit = Get32(p + 76);
+ HeapReserve = Get32(p + 80);
+ HeapCommit = Get32(p + 84);
+ }
+ UInt32 pos = (hdr64 ? 108 : 92);
+ NumDirItems = Get32(p + pos);
+ pos += 4;
+ if (pos + 8 * NumDirItems != size)
+ return false;
+ for (UInt32 i = 0; i < NumDirItems && i < kNumDirItemsMax; i++)
+ DirItems[i].Parse(p + pos + i * 8);
+ return true;
+}
+
+static const UInt32 kSectionSize = 40;
+
+struct CSection
+{
+ AString Name;
+
+ UInt32 VSize;
+ UInt32 Va;
+ UInt32 PSize;
+ UInt32 Pa;
+ UInt32 Flags;
+ UInt32 Time;
+ // UInt16 NumRelocs;
+ bool IsDebug;
+ bool IsRealSect;
+ bool IsAdditionalSection;
+
+ CSection(): IsRealSect(false), IsDebug(false), IsAdditionalSection(false) {}
+ UInt64 GetPackSize() const { return PSize; }
+
+ void UpdateTotalSize(UInt32 &totalSize)
+ {
+ UInt32 t = Pa + PSize;
+ if (t > totalSize)
+ totalSize = t;
+ }
+ void Parse(const Byte *p);
+};
+
+static bool operator <(const CSection &a1, const CSection &a2) { return (a1.Pa < a2.Pa) || ((a1.Pa == a2.Pa) && (a1.PSize < a2.PSize)) ; }
+static bool operator ==(const CSection &a1, const CSection &a2) { return (a1.Pa == a2.Pa) && (a1.PSize == a2.PSize); }
+
+static AString GetName(const Byte *name)
+{
+ const int kNameSize = 8;
+ AString res;
+ char *p = res.GetBuffer(kNameSize);
+ memcpy(p, name, kNameSize);
+ p[kNameSize] = 0;
+ res.ReleaseBuffer();
+ return res;
+}
+
+void CSection::Parse(const Byte *p)
+{
+ Name = GetName(p);
+ VSize = Get32(p + 8);
+ Va = Get32(p + 12);
+ PSize = Get32(p + 16);
+ Pa = Get32(p + 20);
+ // NumRelocs = Get16(p + 32);
+ Flags = Get32(p + 36);
+}
+
+static const CUInt32PCharPair g_HeaderCharacts[] =
+{
+ { 1, "Executable" },
+ { 13, "DLL" },
+ { 8, "32-bit" },
+ { 5, "LargeAddress" },
+ { 0, "NoRelocs" },
+ { 2, "NoLineNums" },
+ { 3, "NoLocalSyms" },
+ { 4, "AggressiveWsTrim" },
+ { 9, "NoDebugInfo" },
+ { 10, "RemovableRun" },
+ { 11, "NetRun" },
+ { 12, "System" },
+ { 14, "UniCPU" },
+ { 7, "Little-Endian" },
+ { 15, "Big-Endian" }
+};
+
+static const CUInt32PCharPair g_DllCharacts[] =
+{
+ { 6, "Relocated" },
+ { 7, "Integrity" },
+ { 8, "NX-Compatible" },
+ { 9, "NoIsolation" },
+ { 10, "NoSEH" },
+ { 11, "NoBind" },
+ { 13, "WDM" },
+ { 15, "TerminalServerAware" }
+};
+
+static const CUInt32PCharPair g_SectFlags[] =
+{
+ { 3, "NoPad" },
+ { 5, "Code" },
+ { 6, "InitializedData" },
+ { 7, "UninitializedData" },
+ { 9, "Comments" },
+ { 11, "Remove" },
+ { 12, "COMDAT" },
+ { 15, "GP" },
+ { 24, "ExtendedRelocations" },
+ { 25, "Discardable" },
+ { 26, "NotCached" },
+ { 27, "NotPaged" },
+ { 28, "Shared" },
+ { 29, "Execute" },
+ { 30, "Read" },
+ { 31, "Write" }
+};
+
+static const CUInt32PCharPair g_MachinePairs[] =
+{
+ { 0x014C, "x86" },
+ { 0x0162, "MIPS-R3000" },
+ { 0x0166, "MIPS-R4000" },
+ { 0x0168, "MIPS-R10000" },
+ { 0x0169, "MIPS-V2" },
+ { 0x0184, "Alpha" },
+ { 0x01A2, "SH3" },
+ { 0x01A3, "SH3-DSP" },
+ { 0x01A4, "SH3E" },
+ { 0x01A6, "SH4" },
+ { 0x01A8, "SH5" },
+ { 0x01C0, "ARM" },
+ { 0x01C2, "ARM-Thumb" },
+ { 0x01F0, "PPC" },
+ { 0x01F1, "PPC-FP" },
+ { 0x0200, "IA-64" },
+ { 0x0284, "Alpha-64" },
+ { 0x0200, "IA-64" },
+ { 0x0366, "MIPSFPU" },
+ { 0x8664, "x64" },
+ { 0x0EBC, "EFI" }
+};
+
+static const CUInt32PCharPair g_SubSystems[] =
+{
+ { 0, "Unknown" },
+ { 1, "Native" },
+ { 2, "Windows GUI" },
+ { 3, "Windows CUI" },
+ { 7, "Posix" },
+ { 9, "Windows CE" },
+ { 10, "EFI" },
+ { 11, "EFI Boot" },
+ { 12, "EFI Runtime" },
+ { 13, "EFI ROM" },
+ { 14, "XBOX" }
+};
+
+static const wchar_t *g_ResTypes[] =
+{
+ NULL,
+ L"CURSOR",
+ L"BITMAP",
+ L"ICON",
+ L"MENU",
+ L"DIALOG",
+ L"STRING",
+ L"FONTDIR",
+ L"FONT",
+ L"ACCELERATOR",
+ L"RCDATA",
+ L"MESSAGETABLE",
+ L"GROUP_CURSOR",
+ NULL,
+ L"GROUP_ICON",
+ NULL,
+ L"VERSION",
+ L"DLGINCLUDE",
+ NULL,
+ L"PLUGPLAY",
+ L"VXD",
+ L"ANICURSOR",
+ L"ANIICON",
+ L"HTML",
+ L"MANIFEST"
+};
+
+const UInt32 kFlag = (UInt32)1 << 31;
+const UInt32 kMask = ~kFlag;
+
+struct CTableItem
+{
+ UInt32 Offset;
+ UInt32 ID;
+};
+
+
+const UInt32 kBmpHeaderSize = 14;
+const UInt32 kIconHeaderSize = 22;
+
+struct CResItem
+{
+ UInt32 Type;
+ UInt32 ID;
+ UInt32 Lang;
+
+ UInt32 Size;
+ UInt32 Offset;
+
+ UInt32 HeaderSize;
+ Byte Header[kIconHeaderSize]; // it must be enough for max size header.
+ bool Enabled;
+
+ bool IsNameEqual(const CResItem &item) const { return Lang == item.Lang; }
+ UInt32 GetSize() const { return Size + HeaderSize; }
+ bool IsBmp() const { return Type == 2; }
+ bool IsIcon() const { return Type == 3; }
+ bool IsString() const { return Type == 6; }
+ bool IsRcData() const { return Type == 10; }
+ bool IsRcDataOrUnknown() const { return IsRcData() || Type > 64; }
+};
+
+struct CStringItem
+{
+ UInt32 Lang;
+ UInt32 Size;
+ CByteDynamicBuffer Buf;
+
+ void AddChar(Byte c);
+ void AddWChar(UInt16 c);
+};
+
+void CStringItem::AddChar(Byte c)
+{
+ Buf.EnsureCapacity(Size + 2);
+ Buf[Size++] = c;
+ Buf[Size++] = 0;
+}
+
+void CStringItem::AddWChar(UInt16 c)
+{
+ if (c == '\n')
+ {
+ AddChar('\\');
+ c = 'n';
+ }
+ Buf.EnsureCapacity(Size + 2);
+ SetUi16(Buf + Size, c);
+ Size += 2;
+}
+
+struct CMixItem
+{
+ int SectionIndex;
+ int ResourceIndex;
+ int StringIndex;
+
+ bool IsSectionItem() const { return ResourceIndex < 0 && StringIndex < 0; };
+};
+
+struct CUsedBitmap
+{
+ CByteBuffer Buf;
+public:
+ void Alloc(size_t size)
+ {
+ size = (size + 7) / 8;
+ Buf.SetCapacity(size);
+ memset(Buf, 0, size);
+ }
+ void Free()
+ {
+ Buf.SetCapacity(0);
+ }
+ bool SetRange(size_t from, int size)
+ {
+ for (int i = 0; i < size; i++)
+ {
+ size_t pos = (from + i) >> 3;
+ Byte mask = (Byte)(1 << ((from + i) & 7));
+ Byte b = Buf[pos];
+ if ((b & mask) != 0)
+ return false;
+ Buf[pos] = b | mask;
+ }
+ return true;
+ }
+};
+
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CObjectVector<CSection> _sections;
+ UInt32 _peOffset;
+ CHeader _header;
+ COptHeader _optHeader;
+ UInt32 _totalSize;
+ UInt32 _totalSizeLimited;
+ Int32 _mainSubfile;
+
+ CRecordVector<CResItem> _items;
+ CObjectVector<CStringItem> _strings;
+
+ CByteBuffer _buf;
+ bool _oneLang;
+ UString _resourceFileName;
+ CUsedBitmap _usedRes;
+ bool _parseResources;
+
+ CRecordVector<CMixItem> _mixItems;
+
+ HRESULT LoadDebugSections(IInStream *stream, bool &thereIsSection);
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
+ bool Parse(const Byte *buf, UInt32 size);
+
+ void AddResNameToString(UString &s, UInt32 id) const;
+ UString GetLangPrefix(UInt32 lang);
+ HRESULT ReadString(UInt32 offset, UString &dest) const;
+ HRESULT ReadTable(UInt32 offset, CRecordVector<CTableItem> &items);
+ bool ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size);
+ HRESULT OpenResources(int sectIndex, IInStream *stream, IArchiveOpenCallback *callback);
+ void CloseResources();
+
+
+ bool CheckItem(const CSection &sect, const CResItem &item, size_t offset) const
+ {
+ return item.Offset >= sect.Va && offset <= _buf.GetCapacity() && _buf.GetCapacity() - offset >= item.Size;
+ }
+
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+bool CHandler::Parse(const Byte *buf, UInt32 size)
+{
+ UInt32 i;
+ if (size < 512)
+ return false;
+ _peOffset = Get32(buf + 0x3C);
+ if (_peOffset >= 0x1000 || _peOffset + 512 > size || (_peOffset & 7) != 0)
+ return false;
+
+ UInt32 pos = _peOffset;
+ if (!_header.Parse(buf + pos))
+ return false;
+ if (_header.OptHeaderSize > 512 || _header.NumSections > NUM_SCAN_SECTIONS_MAX)
+ return false;
+ pos += kHeaderSize;
+
+ if (!_optHeader.Parse(buf + pos, _header.OptHeaderSize))
+ return false;
+
+ pos += _header.OptHeaderSize;
+ _totalSize = pos;
+
+ for (i = 0; i < _header.NumSections; i++, pos += kSectionSize)
+ {
+ CSection sect;
+ if (pos + kSectionSize > size)
+ return false;
+ sect.Parse(buf + pos);
+ sect.IsRealSect = true;
+ sect.UpdateTotalSize(_totalSize);
+ _sections.Add(sect);
+ }
+
+ return true;
+}
+
+enum
+{
+ kpidSectAlign = kpidUserDefined,
+ kpidFileAlign,
+ kpidLinkerVer,
+ kpidOsVer,
+ kpidImageVer,
+ kpidSubsysVer,
+ kpidCodeSize,
+ kpidImageSize,
+ kpidInitDataSize,
+ kpidUnInitDataSize,
+ kpidHeadersSizeUnInitDataSize,
+ kpidSubSystem,
+ kpidDllCharacts,
+ kpidStackReserve,
+ kpidStackCommit,
+ kpidHeapReserve,
+ kpidHeapCommit,
+ kpidImageBase
+ // kpidAddressOfEntryPoint,
+ // kpidBaseOfCode,
+ // kpidBaseOfData32,
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidCpu, VT_BSTR},
+ { NULL, kpidBit64, VT_BOOL},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidPhySize, VT_UI4},
+ { NULL, kpidHeadersSize, VT_UI4},
+ { NULL, kpidChecksum, VT_UI4},
+ { L"Image Size", kpidImageSize, VT_UI4},
+ { L"Section Alignment", kpidSectAlign, VT_UI4},
+ { L"File Alignment", kpidFileAlign, VT_UI4},
+ { L"Code Size", kpidCodeSize, VT_UI4},
+ { L"Initialized Data Size", kpidInitDataSize, VT_UI4},
+ { L"Uninitialized Data Size", kpidUnInitDataSize, VT_UI4},
+ { L"Linker Version", kpidLinkerVer, VT_BSTR},
+ { L"OS Version", kpidOsVer, VT_BSTR},
+ { L"Image Version", kpidImageVer, VT_BSTR},
+ { L"Subsystem Version", kpidSubsysVer, VT_BSTR},
+ { L"Subsystem", kpidSubSystem, VT_BSTR},
+ { L"DLL Characteristics", kpidDllCharacts, VT_BSTR},
+ { L"Stack Reserve", kpidStackReserve, VT_UI8},
+ { L"Stack Commit", kpidStackCommit, VT_UI8},
+ { L"Heap Reserve", kpidHeapReserve, VT_UI8},
+ { L"Heap Commit", kpidHeapCommit, VT_UI8},
+ { L"Image Base", kpidImageBase, VT_UI8}
+ // { L"Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8},
+ // { L"Base Of Code", kpidBaseOfCode, VT_UI8},
+ // { L"Base Of Data", kpidBaseOfData32, VT_UI8},
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidOffset, VT_UI8},
+ { NULL, kpidVa, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+static void VerToProp(const CVersion &v, NCOM::CPropVariant &prop)
+{
+ StringToProp(v.GetString(), prop);
+}
+
+void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop)
+{
+ if (unixTime != 0)
+ {
+ FILETIME ft;
+ NTime::UnixTimeToFileTime(unixTime, ft);
+ prop = ft;
+ }
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidSectAlign: prop = _optHeader.SectAlign; break;
+ case kpidFileAlign: prop = _optHeader.FileAlign; break;
+ case kpidLinkerVer:
+ {
+ CVersion v = { _optHeader.LinkerVerMajor, _optHeader.LinkerVerMinor };
+ VerToProp(v, prop);
+ break;
+ }
+
+ case kpidOsVer: VerToProp(_optHeader.OsVer, prop); break;
+ case kpidImageVer: VerToProp(_optHeader.ImageVer, prop); break;
+ case kpidSubsysVer: VerToProp(_optHeader.SubsysVer, prop); break;
+ case kpidCodeSize: prop = _optHeader.CodeSize; break;
+ case kpidInitDataSize: prop = _optHeader.InitDataSize; break;
+ case kpidUnInitDataSize: prop = _optHeader.UninitDataSize; break;
+ case kpidImageSize: prop = _optHeader.ImageSize; break;
+ case kpidPhySize: prop = _totalSize; break;
+ case kpidHeadersSize: prop = _optHeader.HeadersSize; break;
+ case kpidChecksum: prop = _optHeader.CheckSum; break;
+
+ case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
+ case kpidBit64: if (_optHeader.Is64Bit()) prop = true; break;
+ case kpidSubSystem: PAIR_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break;
+
+ case kpidMTime:
+ case kpidCTime: TimeToProp(_header.Time, prop); break;
+ case kpidCharacts: FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break;
+ case kpidDllCharacts: FLAGS_TO_PROP(g_DllCharacts, _optHeader.DllCharacts, prop); break;
+ case kpidStackReserve: prop = _optHeader.StackReserve; break;
+ case kpidStackCommit: prop = _optHeader.StackCommit; break;
+ case kpidHeapReserve: prop = _optHeader.HeapReserve; break;
+ case kpidHeapCommit: prop = _optHeader.HeapCommit; break;
+
+ case kpidImageBase: prop = _optHeader.ImageBase; break;
+ // case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break;
+ // case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break;
+ // case kpidBaseOfData32: if (!_optHeader.Is64Bit()) prop = _optHeader.BaseOfData32; break;
+
+ case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+void CHandler::AddResNameToString(UString &s, UInt32 id) const
+{
+ if ((id & kFlag) != 0)
+ {
+ UString name;
+ if (ReadString(id & kMask, name) == S_OK)
+ {
+ if (name.IsEmpty())
+ s += L"[]";
+ else
+ {
+ if (name.Length() > 1 && name[0] == '"' && name.Back() == '"')
+ name = name.Mid(1, name.Length() - 2);
+ s += name;
+ }
+ return;
+ }
+ }
+ wchar_t sz[32];
+ ConvertUInt32ToString(id, sz);
+ s += sz;
+}
+
+UString CHandler::GetLangPrefix(UInt32 lang)
+{
+ UString s = _resourceFileName;
+ s += WCHAR_PATH_SEPARATOR;
+ if (!_oneLang)
+ {
+ AddResNameToString(s, lang);
+ s += WCHAR_PATH_SEPARATOR;
+ }
+ return s;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CMixItem &mixItem = _mixItems[index];
+ if (mixItem.StringIndex >= 0)
+ {
+ const CStringItem &item = _strings[mixItem.StringIndex];
+ switch(propID)
+ {
+ case kpidPath: prop = GetLangPrefix(item.Lang) + L"string.txt"; break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)item.Size; break;
+ }
+ }
+ else if (mixItem.ResourceIndex < 0)
+ {
+ const CSection &item = _sections[mixItem.SectionIndex];
+ switch(propID)
+ {
+ case kpidPath: StringToProp(item.Name, prop); break;
+ case kpidSize: prop = (UInt64)item.VSize; break;
+ case kpidPackSize: prop = (UInt64)item.GetPackSize(); break;
+ case kpidOffset: prop = item.Pa; break;
+ case kpidVa: if (item.IsRealSect) prop = item.Va; break;
+ case kpidMTime:
+ case kpidCTime:
+ TimeToProp(item.IsDebug ? item.Time : _header.Time, prop); break;
+ case kpidCharacts: if (item.IsRealSect) FLAGS_TO_PROP(g_SectFlags, item.Flags, prop); break;
+ }
+ }
+ else
+ {
+ const CResItem &item = _items[mixItem.ResourceIndex];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString s = GetLangPrefix(item.Lang);
+ {
+ const wchar_t *p = NULL;
+ if (item.Type < sizeof(g_ResTypes) / sizeof(g_ResTypes[0]))
+ p = g_ResTypes[item.Type];
+ if (p != 0)
+ s += p;
+ else
+ AddResNameToString(s, item.Type);
+ }
+ s += WCHAR_PATH_SEPARATOR;
+ AddResNameToString(s, item.ID);
+ if (item.HeaderSize != 0)
+ {
+ if (item.IsBmp())
+ s += L".bmp";
+ else if (item.IsIcon())
+ s += L".ico";
+ }
+ prop = s;
+ break;
+ }
+ case kpidSize: prop = (UInt64)item.GetSize(); break;
+ case kpidPackSize: prop = (UInt64)item.Size; break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection)
+{
+ thereIsSection = false;
+ const CDirLink &debugLink = _optHeader.DirItems[kDirLink_Debug];
+ if (debugLink.Size == 0)
+ return S_OK;
+ const unsigned kEntrySize = 28;
+ UInt32 numItems = debugLink.Size / kEntrySize;
+ if (numItems * kEntrySize != debugLink.Size || numItems > 16)
+ return S_FALSE;
+
+ UInt64 pa = 0;
+ int i;
+ for (i = 0; i < _sections.Size(); i++)
+ {
+ const CSection &sect = _sections[i];
+ if (sect.Va < debugLink.Va && debugLink.Va + debugLink.Size <= sect.Va + sect.PSize)
+ {
+ pa = sect.Pa + (debugLink.Va - sect.Va);
+ break;
+ }
+ }
+ if (i == _sections.Size())
+ {
+ return S_OK;
+ // Exe for ARM requires S_OK
+ // return S_FALSE;
+ }
+
+ CByteBuffer buffer;
+ buffer.SetCapacity(debugLink.Size);
+ Byte *buf = buffer;
+
+ RINOK(stream->Seek(pa, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(stream, buf, debugLink.Size));
+
+ for (i = 0; i < (int)numItems; i++)
+ {
+ CDebugEntry de;
+ de.Parse(buf);
+
+ if (de.Size == 0)
+ continue;
+
+ CSection sect;
+ sect.Name = ".debug" + GetDecString(i);
+
+ sect.IsDebug = true;
+ sect.Time = de.Time;
+ sect.Va = de.Va;
+ sect.Pa = de.Pa;
+ sect.PSize = sect.VSize = de.Size;
+ UInt32 totalSize = sect.Pa + sect.PSize;
+ if (totalSize > _totalSize)
+ {
+ _totalSize = totalSize;
+ _sections.Add(sect);
+ thereIsSection = true;
+ }
+ buf += kEntrySize;
+ }
+
+ return S_OK;
+}
+
+HRESULT CHandler::ReadString(UInt32 offset, UString &dest) const
+{
+ if ((offset & 1) != 0 || offset >= _buf.GetCapacity())
+ return S_FALSE;
+ size_t rem = _buf.GetCapacity() - offset;
+ if (rem < 2)
+ return S_FALSE;
+ unsigned length = Get16(_buf + offset);
+ if ((rem - 2) / 2 < length)
+ return S_FALSE;
+ dest.Empty();
+ offset += 2;
+ for (unsigned i = 0; i < length; i++)
+ dest += (wchar_t)Get16(_buf + offset + i * 2);
+ return S_OK;
+}
+
+HRESULT CHandler::ReadTable(UInt32 offset, CRecordVector<CTableItem> &items)
+{
+ if ((offset & 3) != 0 || offset >= _buf.GetCapacity())
+ return S_FALSE;
+ size_t rem = _buf.GetCapacity() - offset;
+ if (rem < 16)
+ return S_FALSE;
+ items.Clear();
+ unsigned numNameItems = Get16(_buf + offset + 12);
+ unsigned numIdItems = Get16(_buf + offset + 14);
+ unsigned numItems = numNameItems + numIdItems;
+ if ((rem - 16) / 8 < numItems)
+ return S_FALSE;
+ if (!_usedRes.SetRange(offset, 16 + numItems * 8))
+ return S_FALSE;
+ offset += 16;
+ _oneLang = true;
+ unsigned i;
+ for (i = 0; i < numItems; i++)
+ {
+ CTableItem item;
+ const Byte *buf = _buf + offset;
+ offset += 8;
+ item.ID = Get32(buf + 0);
+ if (((item.ID & kFlag) != 0) != (i < numNameItems))
+ return S_FALSE;
+ item.Offset = Get32(buf + 4);
+ items.Add(item);
+ }
+ return S_OK;
+}
+
+static const UInt32 kFileSizeMax = (UInt32)1 << 30;
+static const int kNumResItemsMax = (UInt32)1 << 23;
+static const int kNumStringLangsMax = 128;
+
+// BITMAPINFOHEADER
+struct CBitmapInfoHeader
+{
+ // UInt32 HeaderSize;
+ UInt32 XSize;
+ Int32 YSize;
+ UInt16 Planes;
+ UInt16 BitCount;
+ UInt32 Compression;
+ UInt32 SizeImage;
+
+ bool Parse(const Byte *p, size_t size);
+};
+
+static const UInt32 kBitmapInfoHeader_Size = 0x28;
+
+bool CBitmapInfoHeader::Parse(const Byte *p, size_t size)
+{
+ if (size < kBitmapInfoHeader_Size || Get32(p) != kBitmapInfoHeader_Size)
+ return false;
+ XSize = Get32(p + 4);
+ YSize = (Int32)Get32(p + 8);
+ Planes = Get16(p + 12);
+ BitCount = Get16(p + 14);
+ Compression = Get32(p + 16);
+ SizeImage = Get32(p + 20);
+ return true;
+}
+
+static UInt32 GetImageSize(UInt32 xSize, UInt32 ySize, UInt32 bitCount)
+{
+ return ((xSize * bitCount + 7) / 8 + 3) / 4 * 4 * ySize;
+}
+
+static UInt32 SetBitmapHeader(Byte *dest, const Byte *src, UInt32 size)
+{
+ CBitmapInfoHeader h;
+ if (!h.Parse(src, size))
+ return 0;
+ if (h.YSize < 0)
+ h.YSize = -h.YSize;
+ if (h.XSize > (1 << 26) || h.YSize > (1 << 26) || h.Planes != 1 || h.BitCount > 32 ||
+ h.Compression != 0) // BI_RGB
+ return 0;
+ if (h.SizeImage == 0)
+ h.SizeImage = GetImageSize(h.XSize, h.YSize, h.BitCount);
+ UInt32 totalSize = kBmpHeaderSize + size;
+ UInt32 offBits = totalSize - h.SizeImage;
+ // BITMAPFILEHEADER
+ SetUi16(dest, 0x4D42);
+ SetUi32(dest + 2, totalSize);
+ SetUi32(dest + 6, 0);
+ SetUi32(dest + 10, offBits);
+ return kBmpHeaderSize;
+}
+
+static UInt32 SetIconHeader(Byte *dest, const Byte *src, UInt32 size)
+{
+ CBitmapInfoHeader h;
+ if (!h.Parse(src, size))
+ return 0;
+ if (h.YSize < 0)
+ h.YSize = -h.YSize;
+ if (h.XSize > (1 << 26) || h.YSize > (1 << 26) || h.Planes != 1 ||
+ h.Compression != 0) // BI_RGB
+ return 0;
+
+ UInt32 numBitCount = h.BitCount;
+ if (numBitCount != 1 &&
+ numBitCount != 4 &&
+ numBitCount != 8 &&
+ numBitCount != 24 &&
+ numBitCount != 32)
+ return 0;
+
+ if ((h.YSize & 1) != 0)
+ return 0;
+ h.YSize /= 2;
+ if (h.XSize > 0x100 || h.YSize > 0x100)
+ return 0;
+
+ UInt32 imageSize;
+ // imageSize is not correct if AND mask array contains zeros
+ // in this case it is equal image1Size
+
+ // UInt32 imageSize = h.SizeImage;
+ // if (imageSize == 0)
+ // {
+ UInt32 image1Size = GetImageSize(h.XSize, h.YSize, h.BitCount);
+ UInt32 image2Size = GetImageSize(h.XSize, h.YSize, 1);
+ imageSize = image1Size + image2Size;
+ // }
+ UInt32 numColors = 0;
+ if (numBitCount < 16)
+ numColors = 1 << numBitCount;
+
+ SetUi16(dest, 0); // Reserved
+ SetUi16(dest + 2, 1); // RES_ICON
+ SetUi16(dest + 4, 1); // ResCount
+
+ dest[6] = (Byte)h.XSize; // Width
+ dest[7] = (Byte)h.YSize; // Height
+ dest[8] = (Byte)numColors; // ColorCount
+ dest[9] = 0; // Reserved
+
+ SetUi32(dest + 10, 0); // Reserved1 / Reserved2
+
+ UInt32 numQuadsBytes = numColors * 4;
+ UInt32 BytesInRes = kBitmapInfoHeader_Size + numQuadsBytes + imageSize;
+ SetUi32(dest + 14, BytesInRes);
+ SetUi32(dest + 18, kIconHeaderSize);
+
+ /*
+ Description = DWORDToString(xSize) +
+ kDelimiterChar + DWORDToString(ySize) +
+ kDelimiterChar + DWORDToString(numBitCount);
+ */
+ return kIconHeaderSize;
+}
+
+bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size)
+{
+ if ((size & 1) != 0)
+ return false;
+
+ int i;
+ for (i = 0; i < _strings.Size(); i++)
+ if (_strings[i].Lang == lang)
+ break;
+ if (i == _strings.Size())
+ {
+ if (_strings.Size() >= kNumStringLangsMax)
+ return false;
+ CStringItem item;
+ item.Size = 0;
+ item.Lang = lang;
+ i = _strings.Add(item);
+ }
+
+ CStringItem &item = _strings[i];
+ id = (id - 1) << 4;
+ UInt32 pos = 0;
+ for (i = 0; i < 16; i++)
+ {
+ if (size - pos < 2)
+ return false;
+ UInt32 len = Get16(src + pos);
+ pos += 2;
+ if (len != 0)
+ {
+ if (size - pos < len * 2)
+ return false;
+ char temp[32];
+ ConvertUInt32ToString(id + i, temp);
+ size_t tempLen = strlen(temp);
+ size_t j;
+ for (j = 0; j < tempLen; j++)
+ item.AddChar(temp[j]);
+ item.AddChar('\t');
+ for (j = 0; j < len; j++, pos += 2)
+ item.AddWChar(Get16(src + pos));
+ item.AddChar(0x0D);
+ item.AddChar(0x0A);
+ }
+ }
+ return (size == pos);
+}
+
+HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpenCallback *callback)
+{
+ const CSection &sect = _sections[sectionIndex];
+ size_t fileSize = sect.PSize; // Maybe we need sect.VSize here !!!
+ if (fileSize > kFileSizeMax)
+ return S_FALSE;
+ {
+ UInt64 fileSize64 = fileSize;
+ if (callback)
+ RINOK(callback->SetTotal(NULL, &fileSize64));
+ RINOK(stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL));
+ _buf.SetCapacity(fileSize);
+ for (size_t pos = 0; pos < fileSize;)
+ {
+ UInt64 offset64 = pos;
+ if (callback)
+ RINOK(callback->SetCompleted(NULL, &offset64))
+ size_t rem = MyMin(fileSize - pos, (size_t)(1 << 20));
+ RINOK(ReadStream_FALSE(stream, _buf + pos, rem));
+ pos += rem;
+ }
+ }
+
+ _usedRes.Alloc(fileSize);
+ CRecordVector<CTableItem> specItems;
+ RINOK(ReadTable(0, specItems));
+
+ _oneLang = true;
+ bool stringsOk = true;
+ size_t maxOffset = 0;
+ for (int i = 0; i < specItems.Size(); i++)
+ {
+ const CTableItem &item1 = specItems[i];
+ if ((item1.Offset & kFlag) == 0)
+ return S_FALSE;
+
+ CRecordVector<CTableItem> specItems2;
+ RINOK(ReadTable(item1.Offset & kMask, specItems2));
+
+ for (int j = 0; j < specItems2.Size(); j++)
+ {
+ const CTableItem &item2 = specItems2[j];
+ if ((item2.Offset & kFlag) == 0)
+ return S_FALSE;
+
+ CRecordVector<CTableItem> specItems3;
+ RINOK(ReadTable(item2.Offset & kMask, specItems3));
+
+ CResItem item;
+ item.Type = item1.ID;
+ item.ID = item2.ID;
+
+ for (int k = 0; k < specItems3.Size(); k++)
+ {
+ if (_items.Size() >= kNumResItemsMax)
+ return S_FALSE;
+ const CTableItem &item3 = specItems3[k];
+ if ((item3.Offset & kFlag) != 0)
+ return S_FALSE;
+ if (item3.Offset >= _buf.GetCapacity() || _buf.GetCapacity() - item3.Offset < 16)
+ return S_FALSE;
+ const Byte *buf = _buf + item3.Offset;
+ item.Lang = item3.ID;
+ item.Offset = Get32(buf + 0);
+ item.Size = Get32(buf + 4);
+ // UInt32 codePage = Get32(buf + 8);
+ if (Get32(buf + 12) != 0)
+ return S_FALSE;
+ if (!_items.IsEmpty() && _oneLang && !item.IsNameEqual(_items.Back()))
+ _oneLang = false;
+
+ item.HeaderSize = 0;
+
+ size_t offset = item.Offset - sect.Va;
+ if (offset > maxOffset)
+ maxOffset = offset;
+ if (offset + item.Size > maxOffset)
+ maxOffset = offset + item.Size;
+
+ if (CheckItem(sect, item, offset))
+ {
+ const Byte *data = _buf + offset;
+ if (item.IsBmp())
+ item.HeaderSize = SetBitmapHeader(item.Header, data, item.Size);
+ else if (item.IsIcon())
+ item.HeaderSize = SetIconHeader(item.Header, data, item.Size);
+ else if (item.IsString())
+ {
+ if (stringsOk)
+ stringsOk = ParseStringRes(item.ID, item.Lang, data, item.Size);
+ }
+ }
+
+ item.Enabled = true;
+ _items.Add(item);
+ }
+ }
+ }
+
+ if (stringsOk && !_strings.IsEmpty())
+ {
+ int i;
+ for (i = 0; i < _items.Size(); i++)
+ {
+ CResItem &item = _items[i];
+ if (item.IsString())
+ item.Enabled = false;
+ }
+ for (i = 0; i < _strings.Size(); i++)
+ {
+ if (_strings[i].Size == 0)
+ continue;
+ CMixItem mixItem;
+ mixItem.ResourceIndex = -1;
+ mixItem.StringIndex = i;
+ mixItem.SectionIndex = sectionIndex;
+ _mixItems.Add(mixItem);
+ }
+ }
+
+ _usedRes.Free();
+
+ int numBits = _optHeader.GetNumFileAlignBits();
+ if (numBits >= 0)
+ {
+ UInt32 mask = (1 << numBits) - 1;
+ size_t end = ((maxOffset + mask) & ~mask);
+ if (end < sect.VSize && end <= sect.PSize)
+ {
+ CSection sect2;
+ sect2.Flags = 0;
+
+ // we skip Zeros to start of aligned block
+ size_t i;
+ for (i = maxOffset; i < end; i++)
+ if (_buf[i] != 0)
+ break;
+ if (i == end)
+ maxOffset = end;
+
+ sect2.Pa = sect.Pa + (UInt32)maxOffset;
+ sect2.Va = sect.Va + (UInt32)maxOffset;
+ sect2.PSize = sect.VSize - (UInt32)maxOffset;
+ sect2.VSize = sect2.PSize;
+ sect2.Name = ".rsrc_1";
+ sect2.Time = 0;
+ sect2.IsAdditionalSection = true;
+ _sections.Add(sect2);
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
+{
+ const UInt32 kBufSize = 1 << 18;
+ const UInt32 kSigSize = 2;
+
+ _mainSubfile = -1;
+
+ CByteBuffer buffer;
+ buffer.SetCapacity(kBufSize);
+ Byte *buf = buffer;
+
+ size_t processed = kSigSize;
+ RINOK(ReadStream_FALSE(stream, buf, processed));
+ if (buf[0] != 'M' || buf[1] != 'Z')
+ return S_FALSE;
+ processed = kBufSize - kSigSize;
+ RINOK(ReadStream(stream, buf + kSigSize, &processed));
+ processed += kSigSize;
+ if (!Parse(buf, (UInt32)processed))
+ return S_FALSE;
+ bool thereISDebug;
+ RINOK(LoadDebugSections(stream, thereISDebug));
+
+ const CDirLink &certLink = _optHeader.DirItems[kDirLink_Certificate];
+ if (certLink.Size != 0)
+ {
+ CSection sect;
+ sect.Name = "CERTIFICATE";
+ sect.Va = 0;
+ sect.Pa = certLink.Va;
+ sect.PSize = sect.VSize = certLink.Size;
+ sect.UpdateTotalSize(_totalSize);
+ _sections.Add(sect);
+ }
+
+ if (thereISDebug)
+ {
+ const UInt32 kAlign = 1 << 12;
+ UInt32 alignPos = _totalSize & (kAlign - 1);
+ if (alignPos != 0)
+ {
+ UInt32 size = kAlign - alignPos;
+ RINOK(stream->Seek(_totalSize, STREAM_SEEK_SET, NULL));
+ buffer.Free();
+ buffer.SetCapacity(kAlign);
+ Byte *buf = buffer;
+ size_t processed = size;
+ RINOK(ReadStream(stream, buf, &processed));
+ size_t i;
+ for (i = 0; i < processed; i++)
+ {
+ if (buf[i] != 0)
+ break;
+ }
+ if (processed < size && processed < 100)
+ _totalSize += (UInt32)processed;
+ else if (((_totalSize + i) & 0x1FF) == 0 || processed < size)
+ _totalSize += (UInt32)i;
+ }
+ }
+
+ if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= 512)
+ {
+ if (_header.NumSymbols >= (1 << 24))
+ return S_FALSE;
+ CSection sect;
+ sect.Name = "COFF_SYMBOLS";
+ UInt32 size = _header.NumSymbols * 18;
+ RINOK(stream->Seek((UInt64)_header.PointerToSymbolTable + size, STREAM_SEEK_SET, NULL));
+ Byte buf[4];
+ RINOK(ReadStream_FALSE(stream, buf, 4));
+ UInt32 size2 = Get32(buf);
+ if (size2 >= (1 << 28))
+ return S_FALSE;
+ size += size2;
+
+ sect.Va = 0;
+ sect.Pa = _header.PointerToSymbolTable;
+ sect.PSize = sect.VSize = size;
+ sect.UpdateTotalSize(_totalSize);
+ _sections.Add(sect);
+ }
+
+ UInt64 fileSize;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
+ if (fileSize > _totalSize)
+ return S_FALSE;
+ _totalSizeLimited = (_totalSize < fileSize) ? _totalSize : (UInt32)fileSize;
+
+ {
+ CObjectVector<CSection> sections = _sections;
+ sections.Sort();
+ UInt32 limit = (1 << 12);
+ int num = 0;
+ int numSections = sections.Size();
+ for (int i = 0; i < numSections; i++)
+ {
+ const CSection &s = sections[i];
+ if (s.Pa > limit)
+ {
+ CSection s2;
+ s2.Pa = s2.Va = limit;
+ s2.PSize = s2.VSize = s.Pa - limit;
+ s2.IsAdditionalSection = true;
+ s2.Name = '[';
+ s2.Name += GetDecString(num++);
+ s2.Name += ']';
+ _sections.Add(s2);
+ limit = s.Pa;
+ }
+ UInt32 next = s.Pa + s.PSize;
+ if (next < s.Pa)
+ break;
+ if (next >= limit)
+ limit = next;
+ }
+ }
+
+ _parseResources = true;
+
+ UInt64 mainSize = 0, mainSize2 = 0;
+ int i;
+ for (i = 0; i < _sections.Size(); i++)
+ {
+ const CSection &sect = _sections[i];
+ CMixItem mixItem;
+ mixItem.SectionIndex = i;
+ if (_parseResources && sect.Name == ".rsrc" && _items.IsEmpty())
+ {
+ HRESULT res = OpenResources(i, stream, callback);
+ if (res == S_OK)
+ {
+ _resourceFileName = GetUnicodeString(sect.Name);
+ for (int j = 0; j < _items.Size(); j++)
+ {
+ const CResItem &item = _items[j];
+ if (item.Enabled)
+ {
+ mixItem.ResourceIndex = j;
+ mixItem.StringIndex = -1;
+ if (item.IsRcDataOrUnknown())
+ {
+ if (item.Size >= mainSize)
+ {
+ mainSize2 = mainSize;
+ mainSize = item.Size;
+ _mainSubfile = _mixItems.Size();
+ }
+ else if (item.Size >= mainSize2)
+ mainSize2 = item.Size;
+ }
+ _mixItems.Add(mixItem);
+ }
+ }
+ if (sect.PSize > sect.VSize)
+ {
+ int numBits = _optHeader.GetNumFileAlignBits();
+ if (numBits >= 0)
+ {
+ UInt32 mask = (1 << numBits) - 1;
+ UInt32 end = ((sect.VSize + mask) & ~mask);
+
+ if (sect.PSize > end)
+ {
+ CSection sect2;
+ sect2.Flags = 0;
+ sect2.Pa = sect.Pa + end;
+ sect2.Va = sect.Va + end;
+ sect2.PSize = sect.PSize - end;
+ sect2.VSize = sect2.PSize;
+ sect2.Name = ".rsrc_2";
+ sect2.Time = 0;
+ sect2.IsAdditionalSection = true;
+ _sections.Add(sect2);
+ }
+ }
+ }
+ continue;
+ }
+ if (res != S_FALSE)
+ return res;
+ CloseResources();
+ }
+ mixItem.StringIndex = -1;
+ mixItem.ResourceIndex = -1;
+ if (sect.IsAdditionalSection)
+ {
+ if (sect.PSize >= mainSize)
+ {
+ mainSize2 = mainSize;
+ mainSize = sect.PSize;
+ _mainSubfile = _mixItems.Size();
+ }
+ else
+ mainSize2 = sect.PSize;
+ }
+ _mixItems.Add(mixItem);
+ }
+
+ if (mainSize2 >= (1 << 20) && mainSize < mainSize2 * 2)
+ _mainSubfile = -1;
+
+ for (i = 0; i < _mixItems.Size(); i++)
+ {
+ const CMixItem &mixItem = _mixItems[i];
+ if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name == "_winzip_")
+ {
+ _mainSubfile = i;
+ break;
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 excludePos, UInt32 &res)
+{
+ // size &= ~1;
+ const UInt32 kBufSize = 1 << 23;
+ CByteBuffer buffer;
+ buffer.SetCapacity(kBufSize);
+ Byte *buf = buffer;
+
+ UInt32 sum = 0;
+ UInt32 pos = 0;
+ for (;;)
+ {
+ UInt32 rem = size - pos;
+ if (rem > kBufSize)
+ rem = kBufSize;
+ if (rem == 0)
+ break;
+ size_t processed = rem;
+ RINOK(ReadStream(stream, buf, &processed));
+
+ /*
+ for (; processed < rem; processed++)
+ buf[processed] = 0;
+ */
+
+ if ((processed & 1) != 0)
+ buf[processed] = 0;
+
+ for (int j = 0; j < 4; j++)
+ {
+ UInt32 p = excludePos + j;
+ if (pos <= p && p < pos + processed)
+ buf[p - pos] = 0;
+ }
+
+ for (size_t i = 0; i < processed; i += 2)
+ {
+ sum += Get16(buf + i);
+ sum = (sum + (sum >> 16)) & 0xFFFF;
+ }
+ pos += (UInt32)processed;
+ if (rem != processed)
+ break;
+ }
+ sum += pos;
+ res = sum;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(inStream, callback));
+ _stream = inStream;
+ return S_OK;
+ COM_TRY_END
+}
+
+void CHandler::CloseResources()
+{
+ _usedRes.Free();
+ _items.Clear();
+ _strings.Clear();
+ _buf.SetCapacity(0);
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _sections.Clear();
+ _mixItems.Clear();
+ CloseResources();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _mixItems.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _mixItems.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CMixItem &mixItem = _mixItems[allFilesMode ? i : indices[i]];
+ if (mixItem.StringIndex >= 0)
+ totalSize += _strings[mixItem.StringIndex].Size;
+ else if (mixItem.ResourceIndex < 0)
+ totalSize += _sections[mixItem.SectionIndex].GetPackSize();
+ else
+ totalSize += _items[mixItem.ResourceIndex].GetSize();
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ bool checkSumOK = true;
+ if (_optHeader.CheckSum != 0 && (int)numItems == _mixItems.Size())
+ {
+ UInt32 checkSum = 0;
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
+ CalcCheckSum(_stream, _totalSizeLimited, _peOffset + kHeaderSize + 64, checkSum);
+ checkSumOK = (checkSum == _optHeader.CheckSum);
+ }
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ const CMixItem &mixItem = _mixItems[index];
+
+ const CSection &sect = _sections[mixItem.SectionIndex];
+ bool isOk = true;
+ if (mixItem.StringIndex >= 0)
+ {
+ const CStringItem &item = _strings[mixItem.StringIndex];
+ currentItemSize = item.Size;
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (outStream)
+ RINOK(WriteStream(outStream, item.Buf, item.Size));
+ }
+ else if (mixItem.ResourceIndex < 0)
+ {
+ currentItemSize = sect.GetPackSize();
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(_stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ isOk = (copyCoderSpec->TotalSize == currentItemSize);
+ }
+ else
+ {
+ const CResItem &item = _items[mixItem.ResourceIndex];
+ currentItemSize = item.GetSize();
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ size_t offset = item.Offset - sect.Va;
+ if (!CheckItem(sect, item, offset))
+ isOk = false;
+ else if (outStream)
+ {
+ if (item.HeaderSize != 0)
+ RINOK(WriteStream(outStream, item.Header, item.HeaderSize));
+ RINOK(WriteStream(outStream, _buf + offset, item.Size));
+ }
+ }
+
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(isOk ?
+ checkSumOK ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kCRCError:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+
+ const CMixItem &mixItem = _mixItems[index];
+ const CSection &sect = _sections[mixItem.SectionIndex];
+ if (mixItem.IsSectionItem())
+ return CreateLimitedInStream(_stream, sect.Pa, sect.PSize, stream);
+
+ CBufInStream *inStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
+ CReferenceBuf *referenceBuf = new CReferenceBuf;
+ CMyComPtr<IUnknown> ref = referenceBuf;
+ if (mixItem.StringIndex >= 0)
+ {
+ const CStringItem &item = _strings[mixItem.StringIndex];
+ referenceBuf->Buf.SetCapacity(item.Size);
+ memcpy(referenceBuf->Buf, item.Buf, item.Size);
+ }
+ else
+ {
+ const CResItem &item = _items[mixItem.ResourceIndex];
+ size_t offset = item.Offset - sect.Va;
+ if (!CheckItem(sect, item, offset))
+ return S_FALSE;
+ if (item.HeaderSize == 0)
+ {
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp2 = streamSpec;
+ streamSpec->Init(_buf + offset, item.Size, (IInArchive *)this);
+ *stream = streamTemp2.Detach();
+ return S_OK;
+ }
+ referenceBuf->Buf.SetCapacity(item.HeaderSize + item.Size);
+ memcpy(referenceBuf->Buf, item.Header, item.HeaderSize);
+ memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size);
+ }
+ inStreamSpec->Init(referenceBuf);
+
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"PE", L"exe dll sys", 0, 0xDD, { 'P', 'E', 0, 0 }, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Pe)
+
+}}