5 #include "../../../C/CpuArch.h"
\r
7 #include "Common/DynamicBuffer.h"
\r
8 #include "Common/ComTry.h"
\r
9 #include "Common/IntToString.h"
\r
10 #include "Common/StringConvert.h"
\r
12 #include "Windows/PropVariantUtils.h"
\r
13 #include "Windows/Time.h"
\r
15 #include "../Common/LimitedStreams.h"
\r
16 #include "../Common/ProgressUtils.h"
\r
17 #include "../Common/RegisterArc.h"
\r
18 #include "../Common/StreamObjects.h"
\r
19 #include "../Common/StreamUtils.h"
\r
21 #include "../Compress/CopyCoder.h"
\r
23 #define Get16(p) GetUi16(p)
\r
24 #define Get32(p) GetUi32(p)
\r
25 #define Get64(p) GetUi64(p)
\r
27 using namespace NWindows;
\r
29 namespace NArchive {
\r
32 #define NUM_SCAN_SECTIONS_MAX (1 << 6)
\r
34 #define PE_SIG 0x00004550
\r
35 #define PE_OptHeader_Magic_32 0x10B
\r
36 #define PE_OptHeader_Magic_64 0x20B
\r
38 static AString GetDecString(UInt32 v)
\r
41 ConvertUInt64ToString(v, sz);
\r
50 void Parse(const Byte *buf);
\r
51 AString GetString() const { return GetDecString(Major) + '.' + GetDecString(Minor); }
\r
54 void CVersion::Parse(const Byte *p)
\r
57 Minor = Get16(p + 2);
\r
60 static const UInt32 kHeaderSize = 4 + 20;
\r
66 UInt32 PointerToSymbolTable;
\r
68 UInt16 OptHeaderSize;
\r
72 bool Parse(const Byte *buf);
\r
75 bool CHeader::Parse(const Byte *p)
\r
77 if (Get32(p) != PE_SIG)
\r
80 Machine = Get16(p + 0);
\r
81 NumSections = Get16(p + 2);
\r
82 Time = Get32(p + 4);
\r
83 PointerToSymbolTable = Get32(p + 8);
\r
84 NumSymbols = Get32(p + 12);
\r
85 OptHeaderSize = Get16(p + 16);
\r
86 Flags = Get16(p + 18);
\r
94 void Parse(const Byte *p);
\r
97 void CDirLink::Parse(const Byte *p)
\r
100 Size = Get32(p + 4);
\r
105 kDirLink_Certificate = 4,
\r
119 void Parse(const Byte *p);
\r
122 void CDebugEntry::Parse(const Byte *p)
\r
125 Time = Get32(p + 4);
\r
127 Type = Get32(p + 12);
\r
128 Size = Get32(p + 16);
\r
129 Va = Get32(p + 20);
\r
130 Pa = Get32(p + 24);
\r
133 static const UInt32 kNumDirItemsMax = 16;
\r
138 Byte LinkerVerMajor;
\r
139 Byte LinkerVerMinor;
\r
142 UInt32 InitDataSize;
\r
143 UInt32 UninitDataSize;
\r
145 // UInt32 AddressOfEntryPoint;
\r
146 // UInt32 BaseOfCode;
\r
147 // UInt32 BaseOfData32;
\r
155 CVersion SubsysVer;
\r
158 UInt32 HeadersSize;
\r
161 UInt16 DllCharacts;
\r
163 UInt64 StackReserve;
\r
164 UInt64 StackCommit;
\r
165 UInt64 HeapReserve;
\r
168 UInt32 NumDirItems;
\r
169 CDirLink DirItems[kNumDirItemsMax];
\r
171 bool Is64Bit() const { return Magic == PE_OptHeader_Magic_64; }
\r
172 bool Parse(const Byte *p, UInt32 size);
\r
174 int GetNumFileAlignBits() const
\r
176 for (int i = 9; i <= 16; i++)
\r
177 if (((UInt32)1 << i) == FileAlign)
\r
183 bool COptHeader::Parse(const Byte *p, UInt32 size)
\r
188 case PE_OptHeader_Magic_32:
\r
189 case PE_OptHeader_Magic_64:
\r
194 LinkerVerMajor = p[2];
\r
195 LinkerVerMinor = p[3];
\r
197 bool hdr64 = Is64Bit();
\r
199 CodeSize = Get32(p + 4);
\r
200 InitDataSize = Get32(p + 8);
\r
201 UninitDataSize = Get32(p + 12);
\r
203 // AddressOfEntryPoint = Get32(p + 16);
\r
204 // BaseOfCode = Get32(p + 20);
\r
205 // BaseOfData32 = hdr64 ? 0: Get32(p + 24);
\r
206 ImageBase = hdr64 ? GetUi64(p + 24) : Get32(p + 28);
\r
208 SectAlign = Get32(p + 32);
\r
209 FileAlign = Get32(p + 36);
\r
211 OsVer.Parse(p + 40);
\r
212 ImageVer.Parse(p + 44);
\r
213 SubsysVer.Parse(p + 48);
\r
215 // reserved = Get32(p + 52);
\r
217 ImageSize = Get32(p + 56);
\r
218 HeadersSize = Get32(p + 60);
\r
219 CheckSum = Get32(p + 64);
\r
220 SubSystem = Get16(p + 68);
\r
221 DllCharacts = Get16(p + 70);
\r
225 StackReserve = Get64(p + 72);
\r
226 StackCommit = Get64(p + 80);
\r
227 HeapReserve = Get64(p + 88);
\r
228 HeapCommit = Get64(p + 96);
\r
232 StackReserve = Get32(p + 72);
\r
233 StackCommit = Get32(p + 76);
\r
234 HeapReserve = Get32(p + 80);
\r
235 HeapCommit = Get32(p + 84);
\r
237 UInt32 pos = (hdr64 ? 108 : 92);
\r
238 NumDirItems = Get32(p + pos);
\r
240 if (pos + 8 * NumDirItems != size)
\r
242 for (UInt32 i = 0; i < NumDirItems && i < kNumDirItemsMax; i++)
\r
243 DirItems[i].Parse(p + pos + i * 8);
\r
247 static const UInt32 kSectionSize = 40;
\r
259 // UInt16 NumRelocs;
\r
262 bool IsAdditionalSection;
\r
264 CSection(): IsRealSect(false), IsDebug(false), IsAdditionalSection(false) {}
\r
265 UInt64 GetPackSize() const { return PSize; }
\r
267 void UpdateTotalSize(UInt32 &totalSize)
\r
269 UInt32 t = Pa + PSize;
\r
273 void Parse(const Byte *p);
\r
276 static bool operator <(const CSection &a1, const CSection &a2) { return (a1.Pa < a2.Pa) || ((a1.Pa == a2.Pa) && (a1.PSize < a2.PSize)) ; }
\r
277 static bool operator ==(const CSection &a1, const CSection &a2) { return (a1.Pa == a2.Pa) && (a1.PSize == a2.PSize); }
\r
279 static AString GetName(const Byte *name)
\r
281 const int kNameSize = 8;
\r
283 char *p = res.GetBuffer(kNameSize);
\r
284 memcpy(p, name, kNameSize);
\r
286 res.ReleaseBuffer();
\r
290 void CSection::Parse(const Byte *p)
\r
293 VSize = Get32(p + 8);
\r
294 Va = Get32(p + 12);
\r
295 PSize = Get32(p + 16);
\r
296 Pa = Get32(p + 20);
\r
297 // NumRelocs = Get16(p + 32);
\r
298 Flags = Get32(p + 36);
\r
301 static const CUInt32PCharPair g_HeaderCharacts[] =
\r
303 { 1, "Executable" },
\r
306 { 5, "LargeAddress" },
\r
308 { 2, "NoLineNums" },
\r
309 { 3, "NoLocalSyms" },
\r
310 { 4, "AggressiveWsTrim" },
\r
311 { 9, "NoDebugInfo" },
\r
312 { 10, "RemovableRun" },
\r
316 { 7, "Little-Endian" },
\r
317 { 15, "Big-Endian" }
\r
320 static const CUInt32PCharPair g_DllCharacts[] =
\r
322 { 6, "Relocated" },
\r
323 { 7, "Integrity" },
\r
324 { 8, "NX-Compatible" },
\r
325 { 9, "NoIsolation" },
\r
329 { 15, "TerminalServerAware" }
\r
332 static const CUInt32PCharPair g_SectFlags[] =
\r
336 { 6, "InitializedData" },
\r
337 { 7, "UninitializedData" },
\r
342 { 24, "ExtendedRelocations" },
\r
343 { 25, "Discardable" },
\r
344 { 26, "NotCached" },
\r
345 { 27, "NotPaged" },
\r
352 static const CUInt32PCharPair g_MachinePairs[] =
\r
355 { 0x0162, "MIPS-R3000" },
\r
356 { 0x0166, "MIPS-R4000" },
\r
357 { 0x0168, "MIPS-R10000" },
\r
358 { 0x0169, "MIPS-V2" },
\r
359 { 0x0184, "Alpha" },
\r
361 { 0x01A3, "SH3-DSP" },
\r
362 { 0x01A4, "SH3E" },
\r
366 { 0x01C2, "ARM-Thumb" },
\r
368 { 0x01F1, "PPC-FP" },
\r
369 { 0x0200, "IA-64" },
\r
370 { 0x0284, "Alpha-64" },
\r
371 { 0x0200, "IA-64" },
\r
372 { 0x0366, "MIPSFPU" },
\r
377 static const CUInt32PCharPair g_SubSystems[] =
\r
381 { 2, "Windows GUI" },
\r
382 { 3, "Windows CUI" },
\r
384 { 9, "Windows CE" },
\r
386 { 11, "EFI Boot" },
\r
387 { 12, "EFI Runtime" },
\r
392 static const wchar_t *g_ResTypes[] =
\r
421 const UInt32 kFlag = (UInt32)1 << 31;
\r
422 const UInt32 kMask = ~kFlag;
\r
431 const UInt32 kBmpHeaderSize = 14;
\r
432 const UInt32 kIconHeaderSize = 22;
\r
444 Byte Header[kIconHeaderSize]; // it must be enough for max size header.
\r
447 bool IsNameEqual(const CResItem &item) const { return Lang == item.Lang; }
\r
448 UInt32 GetSize() const { return Size + HeaderSize; }
\r
449 bool IsBmp() const { return Type == 2; }
\r
450 bool IsIcon() const { return Type == 3; }
\r
451 bool IsString() const { return Type == 6; }
\r
452 bool IsRcData() const { return Type == 10; }
\r
453 bool IsRcDataOrUnknown() const { return IsRcData() || Type > 64; }
\r
460 CByteDynamicBuffer Buf;
\r
462 void AddChar(Byte c);
\r
463 void AddWChar(UInt16 c);
\r
466 void CStringItem::AddChar(Byte c)
\r
468 Buf.EnsureCapacity(Size + 2);
\r
473 void CStringItem::AddWChar(UInt16 c)
\r
480 Buf.EnsureCapacity(Size + 2);
\r
481 SetUi16(Buf + Size, c);
\r
491 bool IsSectionItem() const { return ResourceIndex < 0 && StringIndex < 0; };
\r
498 void Alloc(size_t size)
\r
500 size = (size + 7) / 8;
\r
501 Buf.SetCapacity(size);
\r
502 memset(Buf, 0, size);
\r
506 Buf.SetCapacity(0);
\r
508 bool SetRange(size_t from, int size)
\r
510 for (int i = 0; i < size; i++)
\r
512 size_t pos = (from + i) >> 3;
\r
513 Byte mask = (Byte)(1 << ((from + i) & 7));
\r
515 if ((b & mask) != 0)
\r
517 Buf[pos] = b | mask;
\r
526 public IInArchiveGetStream,
\r
527 public CMyUnknownImp
\r
529 CMyComPtr<IInStream> _stream;
\r
530 CObjectVector<CSection> _sections;
\r
533 COptHeader _optHeader;
\r
535 UInt32 _totalSizeLimited;
\r
536 Int32 _mainSubfile;
\r
538 CRecordVector<CResItem> _items;
\r
539 CObjectVector<CStringItem> _strings;
\r
543 UString _resourceFileName;
\r
544 CUsedBitmap _usedRes;
\r
545 bool _parseResources;
\r
547 CRecordVector<CMixItem> _mixItems;
\r
549 HRESULT LoadDebugSections(IInStream *stream, bool &thereIsSection);
\r
550 HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
\r
551 bool Parse(const Byte *buf, UInt32 size);
\r
553 void AddResNameToString(UString &s, UInt32 id) const;
\r
554 UString GetLangPrefix(UInt32 lang);
\r
555 HRESULT ReadString(UInt32 offset, UString &dest) const;
\r
556 HRESULT ReadTable(UInt32 offset, CRecordVector<CTableItem> &items);
\r
557 bool ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size);
\r
558 HRESULT OpenResources(int sectIndex, IInStream *stream, IArchiveOpenCallback *callback);
\r
559 void CloseResources();
\r
562 bool CheckItem(const CSection §, const CResItem &item, size_t offset) const
\r
564 return item.Offset >= sect.Va && offset <= _buf.GetCapacity() && _buf.GetCapacity() - offset >= item.Size;
\r
568 MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
\r
569 INTERFACE_IInArchive(;)
\r
570 STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
\r
573 bool CHandler::Parse(const Byte *buf, UInt32 size)
\r
578 _peOffset = Get32(buf + 0x3C);
\r
579 if (_peOffset >= 0x1000 || _peOffset + 512 > size || (_peOffset & 7) != 0)
\r
582 UInt32 pos = _peOffset;
\r
583 if (!_header.Parse(buf + pos))
\r
585 if (_header.OptHeaderSize > 512 || _header.NumSections > NUM_SCAN_SECTIONS_MAX)
\r
587 pos += kHeaderSize;
\r
589 if (!_optHeader.Parse(buf + pos, _header.OptHeaderSize))
\r
592 pos += _header.OptHeaderSize;
\r
595 for (i = 0; i < _header.NumSections; i++, pos += kSectionSize)
\r
598 if (pos + kSectionSize > size)
\r
600 sect.Parse(buf + pos);
\r
601 sect.IsRealSect = true;
\r
602 sect.UpdateTotalSize(_totalSize);
\r
603 _sections.Add(sect);
\r
611 kpidSectAlign = kpidUserDefined,
\r
620 kpidUnInitDataSize,
\r
621 kpidHeadersSizeUnInitDataSize,
\r
629 // kpidAddressOfEntryPoint,
\r
631 // kpidBaseOfData32,
\r
634 STATPROPSTG kArcProps[] =
\r
636 { NULL, kpidCpu, VT_BSTR},
\r
637 { NULL, kpidBit64, VT_BOOL},
\r
638 { NULL, kpidCharacts, VT_BSTR},
\r
639 { NULL, kpidCTime, VT_FILETIME},
\r
640 { NULL, kpidPhySize, VT_UI4},
\r
641 { NULL, kpidHeadersSize, VT_UI4},
\r
642 { NULL, kpidChecksum, VT_UI4},
\r
643 { L"Image Size", kpidImageSize, VT_UI4},
\r
644 { L"Section Alignment", kpidSectAlign, VT_UI4},
\r
645 { L"File Alignment", kpidFileAlign, VT_UI4},
\r
646 { L"Code Size", kpidCodeSize, VT_UI4},
\r
647 { L"Initialized Data Size", kpidInitDataSize, VT_UI4},
\r
648 { L"Uninitialized Data Size", kpidUnInitDataSize, VT_UI4},
\r
649 { L"Linker Version", kpidLinkerVer, VT_BSTR},
\r
650 { L"OS Version", kpidOsVer, VT_BSTR},
\r
651 { L"Image Version", kpidImageVer, VT_BSTR},
\r
652 { L"Subsystem Version", kpidSubsysVer, VT_BSTR},
\r
653 { L"Subsystem", kpidSubSystem, VT_BSTR},
\r
654 { L"DLL Characteristics", kpidDllCharacts, VT_BSTR},
\r
655 { L"Stack Reserve", kpidStackReserve, VT_UI8},
\r
656 { L"Stack Commit", kpidStackCommit, VT_UI8},
\r
657 { L"Heap Reserve", kpidHeapReserve, VT_UI8},
\r
658 { L"Heap Commit", kpidHeapCommit, VT_UI8},
\r
659 { L"Image Base", kpidImageBase, VT_UI8}
\r
660 // { L"Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8},
\r
661 // { L"Base Of Code", kpidBaseOfCode, VT_UI8},
\r
662 // { L"Base Of Data", kpidBaseOfData32, VT_UI8},
\r
665 STATPROPSTG kProps[] =
\r
667 { NULL, kpidPath, VT_BSTR},
\r
668 { NULL, kpidSize, VT_UI8},
\r
669 { NULL, kpidPackSize, VT_UI8},
\r
670 { NULL, kpidCharacts, VT_BSTR},
\r
671 { NULL, kpidOffset, VT_UI8},
\r
672 { NULL, kpidVa, VT_UI8}
\r
675 IMP_IInArchive_Props
\r
676 IMP_IInArchive_ArcProps_WITH_NAME
\r
678 static void VerToProp(const CVersion &v, NCOM::CPropVariant &prop)
\r
680 StringToProp(v.GetString(), prop);
\r
683 void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop)
\r
688 NTime::UnixTimeToFileTime(unixTime, ft);
\r
693 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
\r
696 NCOM::CPropVariant prop;
\r
699 case kpidSectAlign: prop = _optHeader.SectAlign; break;
\r
700 case kpidFileAlign: prop = _optHeader.FileAlign; break;
\r
701 case kpidLinkerVer:
\r
703 CVersion v = { _optHeader.LinkerVerMajor, _optHeader.LinkerVerMinor };
\r
704 VerToProp(v, prop);
\r
708 case kpidOsVer: VerToProp(_optHeader.OsVer, prop); break;
\r
709 case kpidImageVer: VerToProp(_optHeader.ImageVer, prop); break;
\r
710 case kpidSubsysVer: VerToProp(_optHeader.SubsysVer, prop); break;
\r
711 case kpidCodeSize: prop = _optHeader.CodeSize; break;
\r
712 case kpidInitDataSize: prop = _optHeader.InitDataSize; break;
\r
713 case kpidUnInitDataSize: prop = _optHeader.UninitDataSize; break;
\r
714 case kpidImageSize: prop = _optHeader.ImageSize; break;
\r
715 case kpidPhySize: prop = _totalSize; break;
\r
716 case kpidHeadersSize: prop = _optHeader.HeadersSize; break;
\r
717 case kpidChecksum: prop = _optHeader.CheckSum; break;
\r
719 case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
\r
720 case kpidBit64: if (_optHeader.Is64Bit()) prop = true; break;
\r
721 case kpidSubSystem: PAIR_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break;
\r
724 case kpidCTime: TimeToProp(_header.Time, prop); break;
\r
725 case kpidCharacts: FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break;
\r
726 case kpidDllCharacts: FLAGS_TO_PROP(g_DllCharacts, _optHeader.DllCharacts, prop); break;
\r
727 case kpidStackReserve: prop = _optHeader.StackReserve; break;
\r
728 case kpidStackCommit: prop = _optHeader.StackCommit; break;
\r
729 case kpidHeapReserve: prop = _optHeader.HeapReserve; break;
\r
730 case kpidHeapCommit: prop = _optHeader.HeapCommit; break;
\r
732 case kpidImageBase: prop = _optHeader.ImageBase; break;
\r
733 // case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break;
\r
734 // case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break;
\r
735 // case kpidBaseOfData32: if (!_optHeader.Is64Bit()) prop = _optHeader.BaseOfData32; break;
\r
737 case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
\r
739 prop.Detach(value);
\r
744 void CHandler::AddResNameToString(UString &s, UInt32 id) const
\r
746 if ((id & kFlag) != 0)
\r
749 if (ReadString(id & kMask, name) == S_OK)
\r
751 if (name.IsEmpty())
\r
755 if (name.Length() > 1 && name[0] == '"' && name.Back() == '"')
\r
756 name = name.Mid(1, name.Length() - 2);
\r
763 ConvertUInt32ToString(id, sz);
\r
767 UString CHandler::GetLangPrefix(UInt32 lang)
\r
769 UString s = _resourceFileName;
\r
770 s += WCHAR_PATH_SEPARATOR;
\r
773 AddResNameToString(s, lang);
\r
774 s += WCHAR_PATH_SEPARATOR;
\r
779 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
\r
782 NCOM::CPropVariant prop;
\r
783 const CMixItem &mixItem = _mixItems[index];
\r
784 if (mixItem.StringIndex >= 0)
\r
786 const CStringItem &item = _strings[mixItem.StringIndex];
\r
789 case kpidPath: prop = GetLangPrefix(item.Lang) + L"string.txt"; break;
\r
792 prop = (UInt64)item.Size; break;
\r
795 else if (mixItem.ResourceIndex < 0)
\r
797 const CSection &item = _sections[mixItem.SectionIndex];
\r
800 case kpidPath: StringToProp(item.Name, prop); break;
\r
801 case kpidSize: prop = (UInt64)item.VSize; break;
\r
802 case kpidPackSize: prop = (UInt64)item.GetPackSize(); break;
\r
803 case kpidOffset: prop = item.Pa; break;
\r
804 case kpidVa: if (item.IsRealSect) prop = item.Va; break;
\r
807 TimeToProp(item.IsDebug ? item.Time : _header.Time, prop); break;
\r
808 case kpidCharacts: if (item.IsRealSect) FLAGS_TO_PROP(g_SectFlags, item.Flags, prop); break;
\r
813 const CResItem &item = _items[mixItem.ResourceIndex];
\r
818 UString s = GetLangPrefix(item.Lang);
\r
820 const wchar_t *p = NULL;
\r
821 if (item.Type < sizeof(g_ResTypes) / sizeof(g_ResTypes[0]))
\r
822 p = g_ResTypes[item.Type];
\r
826 AddResNameToString(s, item.Type);
\r
828 s += WCHAR_PATH_SEPARATOR;
\r
829 AddResNameToString(s, item.ID);
\r
830 if (item.HeaderSize != 0)
\r
834 else if (item.IsIcon())
\r
840 case kpidSize: prop = (UInt64)item.GetSize(); break;
\r
841 case kpidPackSize: prop = (UInt64)item.Size; break;
\r
844 prop.Detach(value);
\r
849 HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection)
\r
851 thereIsSection = false;
\r
852 const CDirLink &debugLink = _optHeader.DirItems[kDirLink_Debug];
\r
853 if (debugLink.Size == 0)
\r
855 const unsigned kEntrySize = 28;
\r
856 UInt32 numItems = debugLink.Size / kEntrySize;
\r
857 if (numItems * kEntrySize != debugLink.Size || numItems > 16)
\r
862 for (i = 0; i < _sections.Size(); i++)
\r
864 const CSection § = _sections[i];
\r
865 if (sect.Va < debugLink.Va && debugLink.Va + debugLink.Size <= sect.Va + sect.PSize)
\r
867 pa = sect.Pa + (debugLink.Va - sect.Va);
\r
871 if (i == _sections.Size())
\r
874 // Exe for ARM requires S_OK
\r
878 CByteBuffer buffer;
\r
879 buffer.SetCapacity(debugLink.Size);
\r
880 Byte *buf = buffer;
\r
882 RINOK(stream->Seek(pa, STREAM_SEEK_SET, NULL));
\r
883 RINOK(ReadStream_FALSE(stream, buf, debugLink.Size));
\r
885 for (i = 0; i < (int)numItems; i++)
\r
894 sect.Name = ".debug" + GetDecString(i);
\r
896 sect.IsDebug = true;
\r
897 sect.Time = de.Time;
\r
900 sect.PSize = sect.VSize = de.Size;
\r
901 UInt32 totalSize = sect.Pa + sect.PSize;
\r
902 if (totalSize > _totalSize)
\r
904 _totalSize = totalSize;
\r
905 _sections.Add(sect);
\r
906 thereIsSection = true;
\r
914 HRESULT CHandler::ReadString(UInt32 offset, UString &dest) const
\r
916 if ((offset & 1) != 0 || offset >= _buf.GetCapacity())
\r
918 size_t rem = _buf.GetCapacity() - offset;
\r
921 unsigned length = Get16(_buf + offset);
\r
922 if ((rem - 2) / 2 < length)
\r
926 for (unsigned i = 0; i < length; i++)
\r
927 dest += (wchar_t)Get16(_buf + offset + i * 2);
\r
931 HRESULT CHandler::ReadTable(UInt32 offset, CRecordVector<CTableItem> &items)
\r
933 if ((offset & 3) != 0 || offset >= _buf.GetCapacity())
\r
935 size_t rem = _buf.GetCapacity() - offset;
\r
939 unsigned numNameItems = Get16(_buf + offset + 12);
\r
940 unsigned numIdItems = Get16(_buf + offset + 14);
\r
941 unsigned numItems = numNameItems + numIdItems;
\r
942 if ((rem - 16) / 8 < numItems)
\r
944 if (!_usedRes.SetRange(offset, 16 + numItems * 8))
\r
949 for (i = 0; i < numItems; i++)
\r
952 const Byte *buf = _buf + offset;
\r
954 item.ID = Get32(buf + 0);
\r
955 if (((item.ID & kFlag) != 0) != (i < numNameItems))
\r
957 item.Offset = Get32(buf + 4);
\r
963 static const UInt32 kFileSizeMax = (UInt32)1 << 30;
\r
964 static const int kNumResItemsMax = (UInt32)1 << 23;
\r
965 static const int kNumStringLangsMax = 128;
\r
967 // BITMAPINFOHEADER
\r
968 struct CBitmapInfoHeader
\r
970 // UInt32 HeaderSize;
\r
975 UInt32 Compression;
\r
978 bool Parse(const Byte *p, size_t size);
\r
981 static const UInt32 kBitmapInfoHeader_Size = 0x28;
\r
983 bool CBitmapInfoHeader::Parse(const Byte *p, size_t size)
\r
985 if (size < kBitmapInfoHeader_Size || Get32(p) != kBitmapInfoHeader_Size)
\r
987 XSize = Get32(p + 4);
\r
988 YSize = (Int32)Get32(p + 8);
\r
989 Planes = Get16(p + 12);
\r
990 BitCount = Get16(p + 14);
\r
991 Compression = Get32(p + 16);
\r
992 SizeImage = Get32(p + 20);
\r
996 static UInt32 GetImageSize(UInt32 xSize, UInt32 ySize, UInt32 bitCount)
\r
998 return ((xSize * bitCount + 7) / 8 + 3) / 4 * 4 * ySize;
\r
1001 static UInt32 SetBitmapHeader(Byte *dest, const Byte *src, UInt32 size)
\r
1003 CBitmapInfoHeader h;
\r
1004 if (!h.Parse(src, size))
\r
1007 h.YSize = -h.YSize;
\r
1008 if (h.XSize > (1 << 26) || h.YSize > (1 << 26) || h.Planes != 1 || h.BitCount > 32 ||
\r
1009 h.Compression != 0) // BI_RGB
\r
1011 if (h.SizeImage == 0)
\r
1012 h.SizeImage = GetImageSize(h.XSize, h.YSize, h.BitCount);
\r
1013 UInt32 totalSize = kBmpHeaderSize + size;
\r
1014 UInt32 offBits = totalSize - h.SizeImage;
\r
1015 // BITMAPFILEHEADER
\r
1016 SetUi16(dest, 0x4D42);
\r
1017 SetUi32(dest + 2, totalSize);
\r
1018 SetUi32(dest + 6, 0);
\r
1019 SetUi32(dest + 10, offBits);
\r
1020 return kBmpHeaderSize;
\r
1023 static UInt32 SetIconHeader(Byte *dest, const Byte *src, UInt32 size)
\r
1025 CBitmapInfoHeader h;
\r
1026 if (!h.Parse(src, size))
\r
1029 h.YSize = -h.YSize;
\r
1030 if (h.XSize > (1 << 26) || h.YSize > (1 << 26) || h.Planes != 1 ||
\r
1031 h.Compression != 0) // BI_RGB
\r
1034 UInt32 numBitCount = h.BitCount;
\r
1035 if (numBitCount != 1 &&
\r
1036 numBitCount != 4 &&
\r
1037 numBitCount != 8 &&
\r
1038 numBitCount != 24 &&
\r
1039 numBitCount != 32)
\r
1042 if ((h.YSize & 1) != 0)
\r
1045 if (h.XSize > 0x100 || h.YSize > 0x100)
\r
1049 // imageSize is not correct if AND mask array contains zeros
\r
1050 // in this case it is equal image1Size
\r
1052 // UInt32 imageSize = h.SizeImage;
\r
1053 // if (imageSize == 0)
\r
1055 UInt32 image1Size = GetImageSize(h.XSize, h.YSize, h.BitCount);
\r
1056 UInt32 image2Size = GetImageSize(h.XSize, h.YSize, 1);
\r
1057 imageSize = image1Size + image2Size;
\r
1059 UInt32 numColors = 0;
\r
1060 if (numBitCount < 16)
\r
1061 numColors = 1 << numBitCount;
\r
1063 SetUi16(dest, 0); // Reserved
\r
1064 SetUi16(dest + 2, 1); // RES_ICON
\r
1065 SetUi16(dest + 4, 1); // ResCount
\r
1067 dest[6] = (Byte)h.XSize; // Width
\r
1068 dest[7] = (Byte)h.YSize; // Height
\r
1069 dest[8] = (Byte)numColors; // ColorCount
\r
1070 dest[9] = 0; // Reserved
\r
1072 SetUi32(dest + 10, 0); // Reserved1 / Reserved2
\r
1074 UInt32 numQuadsBytes = numColors * 4;
\r
1075 UInt32 BytesInRes = kBitmapInfoHeader_Size + numQuadsBytes + imageSize;
\r
1076 SetUi32(dest + 14, BytesInRes);
\r
1077 SetUi32(dest + 18, kIconHeaderSize);
\r
1080 Description = DWORDToString(xSize) +
\r
1081 kDelimiterChar + DWORDToString(ySize) +
\r
1082 kDelimiterChar + DWORDToString(numBitCount);
\r
1084 return kIconHeaderSize;
\r
1087 bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size)
\r
1089 if ((size & 1) != 0)
\r
1093 for (i = 0; i < _strings.Size(); i++)
\r
1094 if (_strings[i].Lang == lang)
\r
1096 if (i == _strings.Size())
\r
1098 if (_strings.Size() >= kNumStringLangsMax)
\r
1103 i = _strings.Add(item);
\r
1106 CStringItem &item = _strings[i];
\r
1107 id = (id - 1) << 4;
\r
1109 for (i = 0; i < 16; i++)
\r
1111 if (size - pos < 2)
\r
1113 UInt32 len = Get16(src + pos);
\r
1117 if (size - pos < len * 2)
\r
1120 ConvertUInt32ToString(id + i, temp);
\r
1121 size_t tempLen = strlen(temp);
\r
1123 for (j = 0; j < tempLen; j++)
\r
1124 item.AddChar(temp[j]);
\r
1125 item.AddChar('\t');
\r
1126 for (j = 0; j < len; j++, pos += 2)
\r
1127 item.AddWChar(Get16(src + pos));
\r
1128 item.AddChar(0x0D);
\r
1129 item.AddChar(0x0A);
\r
1132 return (size == pos);
\r
1135 HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpenCallback *callback)
\r
1137 const CSection § = _sections[sectionIndex];
\r
1138 size_t fileSize = sect.PSize; // Maybe we need sect.VSize here !!!
\r
1139 if (fileSize > kFileSizeMax)
\r
1142 UInt64 fileSize64 = fileSize;
\r
1144 RINOK(callback->SetTotal(NULL, &fileSize64));
\r
1145 RINOK(stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL));
\r
1146 _buf.SetCapacity(fileSize);
\r
1147 for (size_t pos = 0; pos < fileSize;)
\r
1149 UInt64 offset64 = pos;
\r
1151 RINOK(callback->SetCompleted(NULL, &offset64))
\r
1152 size_t rem = MyMin(fileSize - pos, (size_t)(1 << 20));
\r
1153 RINOK(ReadStream_FALSE(stream, _buf + pos, rem));
\r
1158 _usedRes.Alloc(fileSize);
\r
1159 CRecordVector<CTableItem> specItems;
\r
1160 RINOK(ReadTable(0, specItems));
\r
1163 bool stringsOk = true;
\r
1164 size_t maxOffset = 0;
\r
1165 for (int i = 0; i < specItems.Size(); i++)
\r
1167 const CTableItem &item1 = specItems[i];
\r
1168 if ((item1.Offset & kFlag) == 0)
\r
1171 CRecordVector<CTableItem> specItems2;
\r
1172 RINOK(ReadTable(item1.Offset & kMask, specItems2));
\r
1174 for (int j = 0; j < specItems2.Size(); j++)
\r
1176 const CTableItem &item2 = specItems2[j];
\r
1177 if ((item2.Offset & kFlag) == 0)
\r
1180 CRecordVector<CTableItem> specItems3;
\r
1181 RINOK(ReadTable(item2.Offset & kMask, specItems3));
\r
1184 item.Type = item1.ID;
\r
1185 item.ID = item2.ID;
\r
1187 for (int k = 0; k < specItems3.Size(); k++)
\r
1189 if (_items.Size() >= kNumResItemsMax)
\r
1191 const CTableItem &item3 = specItems3[k];
\r
1192 if ((item3.Offset & kFlag) != 0)
\r
1194 if (item3.Offset >= _buf.GetCapacity() || _buf.GetCapacity() - item3.Offset < 16)
\r
1196 const Byte *buf = _buf + item3.Offset;
\r
1197 item.Lang = item3.ID;
\r
1198 item.Offset = Get32(buf + 0);
\r
1199 item.Size = Get32(buf + 4);
\r
1200 // UInt32 codePage = Get32(buf + 8);
\r
1201 if (Get32(buf + 12) != 0)
\r
1203 if (!_items.IsEmpty() && _oneLang && !item.IsNameEqual(_items.Back()))
\r
1206 item.HeaderSize = 0;
\r
1208 size_t offset = item.Offset - sect.Va;
\r
1209 if (offset > maxOffset)
\r
1210 maxOffset = offset;
\r
1211 if (offset + item.Size > maxOffset)
\r
1212 maxOffset = offset + item.Size;
\r
1214 if (CheckItem(sect, item, offset))
\r
1216 const Byte *data = _buf + offset;
\r
1218 item.HeaderSize = SetBitmapHeader(item.Header, data, item.Size);
\r
1219 else if (item.IsIcon())
\r
1220 item.HeaderSize = SetIconHeader(item.Header, data, item.Size);
\r
1221 else if (item.IsString())
\r
1224 stringsOk = ParseStringRes(item.ID, item.Lang, data, item.Size);
\r
1228 item.Enabled = true;
\r
1234 if (stringsOk && !_strings.IsEmpty())
\r
1237 for (i = 0; i < _items.Size(); i++)
\r
1239 CResItem &item = _items[i];
\r
1240 if (item.IsString())
\r
1241 item.Enabled = false;
\r
1243 for (i = 0; i < _strings.Size(); i++)
\r
1245 if (_strings[i].Size == 0)
\r
1248 mixItem.ResourceIndex = -1;
\r
1249 mixItem.StringIndex = i;
\r
1250 mixItem.SectionIndex = sectionIndex;
\r
1251 _mixItems.Add(mixItem);
\r
1257 int numBits = _optHeader.GetNumFileAlignBits();
\r
1260 UInt32 mask = (1 << numBits) - 1;
\r
1261 size_t end = ((maxOffset + mask) & ~mask);
\r
1262 if (end < sect.VSize && end <= sect.PSize)
\r
1267 // we skip Zeros to start of aligned block
\r
1269 for (i = maxOffset; i < end; i++)
\r
1275 sect2.Pa = sect.Pa + (UInt32)maxOffset;
\r
1276 sect2.Va = sect.Va + (UInt32)maxOffset;
\r
1277 sect2.PSize = sect.VSize - (UInt32)maxOffset;
\r
1278 sect2.VSize = sect2.PSize;
\r
1279 sect2.Name = ".rsrc_1";
\r
1281 sect2.IsAdditionalSection = true;
\r
1282 _sections.Add(sect2);
\r
1289 HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
\r
1291 const UInt32 kBufSize = 1 << 18;
\r
1292 const UInt32 kSigSize = 2;
\r
1294 _mainSubfile = -1;
\r
1296 CByteBuffer buffer;
\r
1297 buffer.SetCapacity(kBufSize);
\r
1298 Byte *buf = buffer;
\r
1300 size_t processed = kSigSize;
\r
1301 RINOK(ReadStream_FALSE(stream, buf, processed));
\r
1302 if (buf[0] != 'M' || buf[1] != 'Z')
\r
1304 processed = kBufSize - kSigSize;
\r
1305 RINOK(ReadStream(stream, buf + kSigSize, &processed));
\r
1306 processed += kSigSize;
\r
1307 if (!Parse(buf, (UInt32)processed))
\r
1309 bool thereISDebug;
\r
1310 RINOK(LoadDebugSections(stream, thereISDebug));
\r
1312 const CDirLink &certLink = _optHeader.DirItems[kDirLink_Certificate];
\r
1313 if (certLink.Size != 0)
\r
1316 sect.Name = "CERTIFICATE";
\r
1318 sect.Pa = certLink.Va;
\r
1319 sect.PSize = sect.VSize = certLink.Size;
\r
1320 sect.UpdateTotalSize(_totalSize);
\r
1321 _sections.Add(sect);
\r
1326 const UInt32 kAlign = 1 << 12;
\r
1327 UInt32 alignPos = _totalSize & (kAlign - 1);
\r
1328 if (alignPos != 0)
\r
1330 UInt32 size = kAlign - alignPos;
\r
1331 RINOK(stream->Seek(_totalSize, STREAM_SEEK_SET, NULL));
\r
1333 buffer.SetCapacity(kAlign);
\r
1334 Byte *buf = buffer;
\r
1335 size_t processed = size;
\r
1336 RINOK(ReadStream(stream, buf, &processed));
\r
1338 for (i = 0; i < processed; i++)
\r
1343 if (processed < size && processed < 100)
\r
1344 _totalSize += (UInt32)processed;
\r
1345 else if (((_totalSize + i) & 0x1FF) == 0 || processed < size)
\r
1346 _totalSize += (UInt32)i;
\r
1350 if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= 512)
\r
1352 if (_header.NumSymbols >= (1 << 24))
\r
1355 sect.Name = "COFF_SYMBOLS";
\r
1356 UInt32 size = _header.NumSymbols * 18;
\r
1357 RINOK(stream->Seek((UInt64)_header.PointerToSymbolTable + size, STREAM_SEEK_SET, NULL));
\r
1359 RINOK(ReadStream_FALSE(stream, buf, 4));
\r
1360 UInt32 size2 = Get32(buf);
\r
1361 if (size2 >= (1 << 28))
\r
1366 sect.Pa = _header.PointerToSymbolTable;
\r
1367 sect.PSize = sect.VSize = size;
\r
1368 sect.UpdateTotalSize(_totalSize);
\r
1369 _sections.Add(sect);
\r
1373 RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
\r
1374 if (fileSize > _totalSize)
\r
1376 _totalSizeLimited = (_totalSize < fileSize) ? _totalSize : (UInt32)fileSize;
\r
1379 CObjectVector<CSection> sections = _sections;
\r
1381 UInt32 limit = (1 << 12);
\r
1383 int numSections = sections.Size();
\r
1384 for (int i = 0; i < numSections; i++)
\r
1386 const CSection &s = sections[i];
\r
1390 s2.Pa = s2.Va = limit;
\r
1391 s2.PSize = s2.VSize = s.Pa - limit;
\r
1392 s2.IsAdditionalSection = true;
\r
1394 s2.Name += GetDecString(num++);
\r
1396 _sections.Add(s2);
\r
1399 UInt32 next = s.Pa + s.PSize;
\r
1402 if (next >= limit)
\r
1407 _parseResources = true;
\r
1409 UInt64 mainSize = 0, mainSize2 = 0;
\r
1411 for (i = 0; i < _sections.Size(); i++)
\r
1413 const CSection § = _sections[i];
\r
1415 mixItem.SectionIndex = i;
\r
1416 if (_parseResources && sect.Name == ".rsrc" && _items.IsEmpty())
\r
1418 HRESULT res = OpenResources(i, stream, callback);
\r
1421 _resourceFileName = GetUnicodeString(sect.Name);
\r
1422 for (int j = 0; j < _items.Size(); j++)
\r
1424 const CResItem &item = _items[j];
\r
1427 mixItem.ResourceIndex = j;
\r
1428 mixItem.StringIndex = -1;
\r
1429 if (item.IsRcDataOrUnknown())
\r
1431 if (item.Size >= mainSize)
\r
1433 mainSize2 = mainSize;
\r
1434 mainSize = item.Size;
\r
1435 _mainSubfile = _mixItems.Size();
\r
1437 else if (item.Size >= mainSize2)
\r
1438 mainSize2 = item.Size;
\r
1440 _mixItems.Add(mixItem);
\r
1443 if (sect.PSize > sect.VSize)
\r
1445 int numBits = _optHeader.GetNumFileAlignBits();
\r
1448 UInt32 mask = (1 << numBits) - 1;
\r
1449 UInt32 end = ((sect.VSize + mask) & ~mask);
\r
1451 if (sect.PSize > end)
\r
1455 sect2.Pa = sect.Pa + end;
\r
1456 sect2.Va = sect.Va + end;
\r
1457 sect2.PSize = sect.PSize - end;
\r
1458 sect2.VSize = sect2.PSize;
\r
1459 sect2.Name = ".rsrc_2";
\r
1461 sect2.IsAdditionalSection = true;
\r
1462 _sections.Add(sect2);
\r
1468 if (res != S_FALSE)
\r
1472 mixItem.StringIndex = -1;
\r
1473 mixItem.ResourceIndex = -1;
\r
1474 if (sect.IsAdditionalSection)
\r
1476 if (sect.PSize >= mainSize)
\r
1478 mainSize2 = mainSize;
\r
1479 mainSize = sect.PSize;
\r
1480 _mainSubfile = _mixItems.Size();
\r
1483 mainSize2 = sect.PSize;
\r
1485 _mixItems.Add(mixItem);
\r
1488 if (mainSize2 >= (1 << 20) && mainSize < mainSize2 * 2)
\r
1489 _mainSubfile = -1;
\r
1491 for (i = 0; i < _mixItems.Size(); i++)
\r
1493 const CMixItem &mixItem = _mixItems[i];
\r
1494 if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name == "_winzip_")
\r
1504 HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 excludePos, UInt32 &res)
\r
1507 const UInt32 kBufSize = 1 << 23;
\r
1508 CByteBuffer buffer;
\r
1509 buffer.SetCapacity(kBufSize);
\r
1510 Byte *buf = buffer;
\r
1516 UInt32 rem = size - pos;
\r
1517 if (rem > kBufSize)
\r
1521 size_t processed = rem;
\r
1522 RINOK(ReadStream(stream, buf, &processed));
\r
1525 for (; processed < rem; processed++)
\r
1526 buf[processed] = 0;
\r
1529 if ((processed & 1) != 0)
\r
1530 buf[processed] = 0;
\r
1532 for (int j = 0; j < 4; j++)
\r
1534 UInt32 p = excludePos + j;
\r
1535 if (pos <= p && p < pos + processed)
\r
1539 for (size_t i = 0; i < processed; i += 2)
\r
1541 sum += Get16(buf + i);
\r
1542 sum = (sum + (sum >> 16)) & 0xFFFF;
\r
1544 pos += (UInt32)processed;
\r
1545 if (rem != processed)
\r
1553 STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)
\r
1557 RINOK(Open2(inStream, callback));
\r
1558 _stream = inStream;
\r
1563 void CHandler::CloseResources()
\r
1568 _buf.SetCapacity(0);
\r
1571 STDMETHODIMP CHandler::Close()
\r
1573 _stream.Release();
\r
1574 _sections.Clear();
\r
1575 _mixItems.Clear();
\r
1580 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
\r
1582 *numItems = _mixItems.Size();
\r
1586 STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
\r
1587 Int32 testMode, IArchiveExtractCallback *extractCallback)
\r
1590 bool allFilesMode = (numItems == (UInt32)-1);
\r
1592 numItems = _mixItems.Size();
\r
1593 if (numItems == 0)
\r
1595 UInt64 totalSize = 0;
\r
1597 for (i = 0; i < numItems; i++)
\r
1599 const CMixItem &mixItem = _mixItems[allFilesMode ? i : indices[i]];
\r
1600 if (mixItem.StringIndex >= 0)
\r
1601 totalSize += _strings[mixItem.StringIndex].Size;
\r
1602 else if (mixItem.ResourceIndex < 0)
\r
1603 totalSize += _sections[mixItem.SectionIndex].GetPackSize();
\r
1605 totalSize += _items[mixItem.ResourceIndex].GetSize();
\r
1607 extractCallback->SetTotal(totalSize);
\r
1609 UInt64 currentTotalSize = 0;
\r
1610 UInt64 currentItemSize;
\r
1612 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
\r
1613 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
\r
1615 CLocalProgress *lps = new CLocalProgress;
\r
1616 CMyComPtr<ICompressProgressInfo> progress = lps;
\r
1617 lps->Init(extractCallback, false);
\r
1619 bool checkSumOK = true;
\r
1620 if (_optHeader.CheckSum != 0 && (int)numItems == _mixItems.Size())
\r
1622 UInt32 checkSum = 0;
\r
1623 RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
\r
1624 CalcCheckSum(_stream, _totalSizeLimited, _peOffset + kHeaderSize + 64, checkSum);
\r
1625 checkSumOK = (checkSum == _optHeader.CheckSum);
\r
1628 CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
\r
1629 CMyComPtr<ISequentialInStream> inStream(streamSpec);
\r
1630 streamSpec->SetStream(_stream);
\r
1632 for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
\r
1634 lps->InSize = lps->OutSize = currentTotalSize;
\r
1635 RINOK(lps->SetCur());
\r
1636 Int32 askMode = testMode ?
\r
1637 NExtract::NAskMode::kTest :
\r
1638 NExtract::NAskMode::kExtract;
\r
1639 UInt32 index = allFilesMode ? i : indices[i];
\r
1641 CMyComPtr<ISequentialOutStream> outStream;
\r
1642 RINOK(extractCallback->GetStream(index, &outStream, askMode));
\r
1643 const CMixItem &mixItem = _mixItems[index];
\r
1645 const CSection § = _sections[mixItem.SectionIndex];
\r
1647 if (mixItem.StringIndex >= 0)
\r
1649 const CStringItem &item = _strings[mixItem.StringIndex];
\r
1650 currentItemSize = item.Size;
\r
1651 if (!testMode && !outStream)
\r
1654 RINOK(extractCallback->PrepareOperation(askMode));
\r
1656 RINOK(WriteStream(outStream, item.Buf, item.Size));
\r
1658 else if (mixItem.ResourceIndex < 0)
\r
1660 currentItemSize = sect.GetPackSize();
\r
1661 if (!testMode && !outStream)
\r
1664 RINOK(extractCallback->PrepareOperation(askMode));
\r
1665 RINOK(_stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL));
\r
1666 streamSpec->Init(currentItemSize);
\r
1667 RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
\r
1668 isOk = (copyCoderSpec->TotalSize == currentItemSize);
\r
1672 const CResItem &item = _items[mixItem.ResourceIndex];
\r
1673 currentItemSize = item.GetSize();
\r
1674 if (!testMode && !outStream)
\r
1677 RINOK(extractCallback->PrepareOperation(askMode));
\r
1678 size_t offset = item.Offset - sect.Va;
\r
1679 if (!CheckItem(sect, item, offset))
\r
1681 else if (outStream)
\r
1683 if (item.HeaderSize != 0)
\r
1684 RINOK(WriteStream(outStream, item.Header, item.HeaderSize));
\r
1685 RINOK(WriteStream(outStream, _buf + offset, item.Size));
\r
1689 outStream.Release();
\r
1690 RINOK(extractCallback->SetOperationResult(isOk ?
\r
1692 NExtract::NOperationResult::kOK:
\r
1693 NExtract::NOperationResult::kCRCError:
\r
1694 NExtract::NOperationResult::kDataError));
\r
1700 STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
\r
1705 const CMixItem &mixItem = _mixItems[index];
\r
1706 const CSection § = _sections[mixItem.SectionIndex];
\r
1707 if (mixItem.IsSectionItem())
\r
1708 return CreateLimitedInStream(_stream, sect.Pa, sect.PSize, stream);
\r
1710 CBufInStream *inStreamSpec = new CBufInStream;
\r
1711 CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
\r
1712 CReferenceBuf *referenceBuf = new CReferenceBuf;
\r
1713 CMyComPtr<IUnknown> ref = referenceBuf;
\r
1714 if (mixItem.StringIndex >= 0)
\r
1716 const CStringItem &item = _strings[mixItem.StringIndex];
\r
1717 referenceBuf->Buf.SetCapacity(item.Size);
\r
1718 memcpy(referenceBuf->Buf, item.Buf, item.Size);
\r
1722 const CResItem &item = _items[mixItem.ResourceIndex];
\r
1723 size_t offset = item.Offset - sect.Va;
\r
1724 if (!CheckItem(sect, item, offset))
\r
1726 if (item.HeaderSize == 0)
\r
1728 CBufInStream *streamSpec = new CBufInStream;
\r
1729 CMyComPtr<IInStream> streamTemp2 = streamSpec;
\r
1730 streamSpec->Init(_buf + offset, item.Size, (IInArchive *)this);
\r
1731 *stream = streamTemp2.Detach();
\r
1734 referenceBuf->Buf.SetCapacity(item.HeaderSize + item.Size);
\r
1735 memcpy(referenceBuf->Buf, item.Header, item.HeaderSize);
\r
1736 memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size);
\r
1738 inStreamSpec->Init(referenceBuf);
\r
1740 *stream = streamTemp.Detach();
\r
1745 static IInArchive *CreateArc() { return new CHandler; }
\r
1747 static CArcInfo g_ArcInfo =
\r
1748 { L"PE", L"exe dll sys", 0, 0xDD, { 'P', 'E', 0, 0 }, 4, false, CreateArc, 0 };
\r