5 #include "../../../C/CpuArch.h"
\r
7 #include "Common/Buffer.h"
\r
8 #include "Common/ComTry.h"
\r
9 #include "Common/IntToString.h"
\r
11 #include "Windows/PropVariantUtils.h"
\r
13 #include "../Common/LimitedStreams.h"
\r
14 #include "../Common/ProgressUtils.h"
\r
15 #include "../Common/RegisterArc.h"
\r
16 #include "../Common/StreamUtils.h"
\r
18 #include "../Compress/CopyCoder.h"
\r
20 static UInt16 Get16(const Byte *p, int be) { if (be) return GetBe16(p); return GetUi16(p); }
\r
21 static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); }
\r
22 static UInt64 Get64(const Byte *p, int be) { if (be) return GetBe64(p); return GetUi64(p); }
\r
24 using namespace NWindows;
\r
26 namespace NArchive {
\r
29 #define ELF_CLASS_32 1
\r
30 #define ELF_CLASS_64 2
\r
32 #define ELF_DATA_2LSB 1
\r
33 #define ELF_DATA_2MSB 2
\r
35 #define NUM_SCAN_SECTIONS_MAX (1 << 6)
\r
52 UInt16 ElfHeaderSize;
\r
53 UInt16 SegmentEntrySize;
\r
55 UInt16 SectEntrySize;
\r
57 // UInt16 SectNameStringTableIndex;
\r
59 bool Parse(const Byte *buf);
\r
61 bool CheckSegmentEntrySize() const
\r
63 return (Mode64 && SegmentEntrySize == 0x38) || (!Mode64 && SegmentEntrySize == 0x20);
\r
66 UInt64 GetHeadersSize() const
\r
67 { return ElfHeaderSize +
\r
68 (UInt64)SegmentEntrySize * NumSegments +
\r
69 (UInt64)SectEntrySize * NumSections; }
\r
73 bool CHeader::Parse(const Byte *p)
\r
77 case ELF_CLASS_32: Mode64 = false; break;
\r
78 case ELF_CLASS_64: Mode64 = true; break;
\r
79 default: return false;
\r
84 case ELF_DATA_2LSB: be = false; break;
\r
85 case ELF_DATA_2MSB: be = true; break;
\r
86 default: return false;
\r
89 if (p[6] != 1) // Version
\r
93 for (int i = 9; i < 16; i++)
\r
97 Type = Get16(p + 0x10, be);
\r
98 Machine = Get16(p + 0x12, be);
\r
99 if (Get32(p + 0x14, be) != 1) // Version
\r
104 // EntryVa = Get64(p + 0x18, be);
\r
105 ProgOffset = Get64(p + 0x20, be);
\r
106 SectOffset = Get64(p + 0x28, be);
\r
111 // EntryVa = Get32(p + 0x18, be);
\r
112 ProgOffset = Get32(p + 0x1C, be);
\r
113 SectOffset = Get32(p + 0x20, be);
\r
117 Flags = Get32(p + 0, be);
\r
118 ElfHeaderSize = Get16(p + 4, be);
\r
119 SegmentEntrySize = Get16(p + 6, be);
\r
120 NumSegments = Get16(p + 8, be);
\r
121 SectEntrySize = Get16(p + 10, be);
\r
122 NumSections = Get16(p + 12, be);
\r
123 // SectNameStringTableIndex = Get16(p + 14, be);
\r
124 return CheckSegmentEntrySize();
\r
138 void UpdateTotalSize(UInt64 &totalSize)
\r
140 UInt64 t = Offset + PSize;
\r
144 void Parse(const Byte *p, bool mode64, bool be);
\r
147 void CSegment::Parse(const Byte *p, bool mode64, bool be)
\r
149 Type = Get32(p, be);
\r
152 Flags = Get32(p + 4, be);
\r
153 Offset = Get64(p + 8, be);
\r
154 Va = Get64(p + 0x10, be);
\r
155 // Pa = Get64(p + 0x18, be);
\r
156 PSize = Get64(p + 0x20, be);
\r
157 VSize = Get64(p + 0x28, be);
\r
158 // Align = Get64(p + 0x30, be);
\r
162 Offset = Get32(p + 4, be);
\r
163 Va = Get32(p + 8, be);
\r
164 // Pa = Get32(p + 12, be);
\r
165 PSize = Get32(p + 16, be);
\r
166 VSize = Get32(p + 20, be);
\r
167 Flags = Get32(p + 24, be);
\r
168 // Align = Get32(p + 28, be);
\r
172 static const CUInt32PCharPair g_MachinePairs[] =
\r
175 { 1, "AT&T WE 32100" },
\r
177 { 3, "Intel 386" },
\r
178 { 4, "Motorola 68000" },
\r
179 { 5, "Motorola 88000" },
\r
180 { 6, "Intel 486" },
\r
181 { 7, "Intel i860" },
\r
183 { 9, "IBM S/370" },
\r
184 { 10, "MIPS RS3000 LE" },
\r
189 { 17, "Fujitsu VPP500" },
\r
190 { 18, "SPARC 32+" },
\r
191 { 19, "Intel i960" },
\r
193 { 21, "PowerPC 64-bit" },
\r
194 { 22, "IBM S/390" },
\r
196 { 36, "NEX v800" },
\r
197 { 37, "Fujitsu FR20" },
\r
198 { 38, "TRW RH-32" },
\r
199 { 39, "Motorola RCE" },
\r
202 { 42, "Hitachi SH" },
\r
203 { 43, "SPARC-V9" },
\r
204 { 44, "Siemens Tricore" },
\r
211 { 51, "Stanford MIPS-X" },
\r
212 { 52, "Motorola ColdFire" },
\r
214 { 54, "Fujitsu MMA" },
\r
215 { 55, "Siemens PCP" },
\r
216 { 56, "Sony nCPU" },
\r
217 { 57, "Denso NDR1" },
\r
218 { 58, "Motorola StarCore" },
\r
219 { 59, "Toyota ME16" },
\r
221 { 61, "Advanced Logic TinyJ" },
\r
223 { 63, "Sony DSP" },
\r
225 { 66, "Siemens FX66" },
\r
228 { 69, "MC68HC16" },
\r
229 { 70, "MC68HC11" },
\r
230 { 71, "MC68HC08" },
\r
231 { 72, "MC68HC05" },
\r
232 { 73, "Silicon Graphics SVx" },
\r
234 { 75, "Digital VAX" },
\r
235 { 76, "Axis CRIS" },
\r
236 { 77, "Infineon JAVELIN" },
\r
237 { 78, "Element 14 FirePath" },
\r
241 { 82, "SiTera Prism" },
\r
242 { 83, "Atmel AVR" },
\r
243 { 84, "Fujitsu FR30" },
\r
244 { 85, "Mitsubishi D10V" },
\r
245 { 86, "Mitsubishi D30V" },
\r
246 { 87, "NEC v850" },
\r
247 { 88, "Mitsubishi M32R" },
\r
248 { 89, "Matsushita MN10300" },
\r
249 { 90, "Matsushita MN10200" },
\r
250 { 91, "picoJava" },
\r
251 { 92, "OpenRISC" },
\r
252 { 93, "ARC Tangent-A5" },
\r
253 { 94, "Tensilica Xtensa" },
\r
254 { 0x9026, "Alpha" }
\r
257 static const CUInt32PCharPair g_AbiOS[] =
\r
269 { 11, "Novell Modesto" },
\r
275 { 255, "Standalone" }
\r
278 static const CUInt32PCharPair g_SegmentFlags[] =
\r
285 static const char *g_Types[] =
\r
288 "Relocatable file",
\r
290 "Shared object file",
\r
294 static const char *g_SegnmentTypes[] =
\r
297 "Loadable segment",
\r
298 "Dynamic linking tables",
\r
299 "Program interpreter path name",
\r
302 "Program header table",
\r
308 public CMyUnknownImp
\r
310 CMyComPtr<IInStream> _inStream;
\r
311 CObjectVector<CSegment> _sections;
\r
315 HRESULT Open2(IInStream *stream);
\r
316 bool Parse(const Byte *buf, UInt32 size);
\r
318 MY_UNKNOWN_IMP1(IInArchive)
\r
319 INTERFACE_IInArchive(;)
\r
322 #define ELF_PT_PHDR 6
\r
324 bool CHandler::Parse(const Byte *buf, UInt32 size)
\r
328 if (!_header.Parse(buf))
\r
330 if (_header.ProgOffset > size ||
\r
331 _header.ProgOffset + (UInt64)_header.SegmentEntrySize * _header.NumSegments > size ||
\r
332 _header.NumSegments > NUM_SCAN_SECTIONS_MAX)
\r
334 const Byte *p = buf + _header.ProgOffset;
\r
335 _totalSize = _header.ProgOffset;
\r
337 for (int i = 0; i < _header.NumSegments; i++, p += _header.SegmentEntrySize)
\r
340 sect.Parse(p, _header.Mode64, _header.Be);
\r
341 sect.UpdateTotalSize(_totalSize);
\r
342 if (sect.Type != ELF_PT_PHDR)
\r
343 _sections.Add(sect);
\r
345 UInt64 total2 = _header.SectOffset + (UInt64)_header.SectEntrySize * _header.NumSections;
\r
346 if (total2 > _totalSize)
\r
347 _totalSize = total2;
\r
351 STATPROPSTG kArcProps[] =
\r
353 { NULL, kpidCpu, VT_BSTR},
\r
354 { NULL, kpidBit64, VT_BOOL},
\r
355 { NULL, kpidBigEndian, VT_BOOL},
\r
356 { NULL, kpidHostOS, VT_BSTR},
\r
357 { NULL, kpidCharacts, VT_BSTR},
\r
358 { NULL, kpidPhySize, VT_UI8},
\r
359 { NULL, kpidHeadersSize, VT_UI8}
\r
362 STATPROPSTG kProps[] =
\r
364 { NULL, kpidPath, VT_BSTR},
\r
365 { NULL, kpidSize, VT_UI8},
\r
366 { NULL, kpidPackSize, VT_UI8},
\r
367 { NULL, kpidType, VT_BSTR},
\r
368 { NULL, kpidCharacts, VT_BSTR},
\r
369 { NULL, kpidOffset, VT_UI8},
\r
370 { NULL, kpidVa, VT_UI8}
\r
373 IMP_IInArchive_Props
\r
374 IMP_IInArchive_ArcProps
\r
376 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
\r
379 NCOM::CPropVariant prop;
\r
382 case kpidPhySize: prop = _totalSize; break;
\r
383 case kpidHeadersSize: prop = _header.GetHeadersSize(); break;
\r
384 case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break;
\r
385 case kpidBigEndian: if (_header.Be) prop = _header.Be; break;
\r
386 case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
\r
387 case kpidHostOS: PAIR_TO_PROP(g_AbiOS, _header.Os, prop); break;
\r
388 case kpidCharacts: TYPE_TO_PROP(g_Types, _header.Type, prop); break;
\r
390 prop.Detach(value);
\r
395 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
\r
398 NCOM::CPropVariant prop;
\r
399 const CSegment &item = _sections[index];
\r
405 ConvertUInt64ToString(index, sz);
\r
409 case kpidSize: prop = (UInt64)item.VSize; break;
\r
410 case kpidPackSize: prop = (UInt64)item.PSize; break;
\r
411 case kpidOffset: prop = item.Offset; break;
\r
412 case kpidVa: prop = item.Va; break;
\r
413 case kpidType: TYPE_TO_PROP(g_SegnmentTypes, item.Type, prop); break;
\r
414 case kpidCharacts: FLAGS_TO_PROP(g_SegmentFlags, item.Flags, prop); break;
\r
416 prop.Detach(value);
\r
421 HRESULT CHandler::Open2(IInStream *stream)
\r
423 const UInt32 kBufSize = 1 << 18;
\r
424 const UInt32 kSigSize = 4;
\r
426 CByteBuffer buffer;
\r
427 buffer.SetCapacity(kBufSize);
\r
428 Byte *buf = buffer;
\r
430 size_t processed = kSigSize;
\r
431 RINOK(ReadStream_FALSE(stream, buf, processed));
\r
432 if (buf[0] != 0x7F || buf[1] != 'E' || buf[2] != 'L' || buf[3] != 'F')
\r
434 processed = kBufSize - kSigSize;
\r
435 RINOK(ReadStream(stream, buf + kSigSize, &processed));
\r
436 processed += kSigSize;
\r
437 if (!Parse(buf, (UInt32)processed))
\r
440 RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
\r
441 return (fileSize == _totalSize) ? S_OK : S_FALSE;
\r
444 STDMETHODIMP CHandler::Open(IInStream *inStream,
\r
445 const UInt64 * /* maxCheckStartPosition */,
\r
446 IArchiveOpenCallback * /* openArchiveCallback */)
\r
450 RINOK(Open2(inStream));
\r
451 _inStream = inStream;
\r
456 STDMETHODIMP CHandler::Close()
\r
458 _inStream.Release();
\r
463 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
\r
465 *numItems = _sections.Size();
\r
469 STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
\r
470 Int32 testMode, IArchiveExtractCallback *extractCallback)
\r
473 bool allFilesMode = (numItems == (UInt32)-1);
\r
475 numItems = _sections.Size();
\r
478 UInt64 totalSize = 0;
\r
480 for (i = 0; i < numItems; i++)
\r
481 totalSize += _sections[allFilesMode ? i : indices[i]].PSize;
\r
482 extractCallback->SetTotal(totalSize);
\r
484 UInt64 currentTotalSize = 0;
\r
485 UInt64 currentItemSize;
\r
487 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
\r
488 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
\r
490 CLocalProgress *lps = new CLocalProgress;
\r
491 CMyComPtr<ICompressProgressInfo> progress = lps;
\r
492 lps->Init(extractCallback, false);
\r
494 CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
\r
495 CMyComPtr<ISequentialInStream> inStream(streamSpec);
\r
496 streamSpec->SetStream(_inStream);
\r
498 for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
\r
500 lps->InSize = lps->OutSize = currentTotalSize;
\r
501 RINOK(lps->SetCur());
\r
502 Int32 askMode = testMode ?
\r
503 NExtract::NAskMode::kTest :
\r
504 NExtract::NAskMode::kExtract;
\r
505 UInt32 index = allFilesMode ? i : indices[i];
\r
506 const CSegment &item = _sections[index];
\r
507 currentItemSize = item.PSize;
\r
509 CMyComPtr<ISequentialOutStream> outStream;
\r
510 RINOK(extractCallback->GetStream(index, &outStream, askMode));
\r
511 if (!testMode && !outStream)
\r
514 RINOK(extractCallback->PrepareOperation(askMode));
\r
515 RINOK(_inStream->Seek(item.Offset, STREAM_SEEK_SET, NULL));
\r
516 streamSpec->Init(currentItemSize);
\r
517 RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
\r
518 outStream.Release();
\r
519 RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ?
\r
520 NExtract::NOperationResult::kOK:
\r
521 NExtract::NOperationResult::kDataError));
\r
527 static IInArchive *CreateArc() { return new CHandler; }
\r
529 static CArcInfo g_ArcInfo =
\r
530 { L"ELF", L"", 0, 0xDE, { 0 }, 0, false, CreateArc, 0 };
\r