diff options
Diffstat (limited to 'CPP/7zip/Archive/RpmHandler.cpp')
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/RpmHandler.cpp | 821 |
1 files changed, 660 insertions, 161 deletions
diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp index 1d31d451..220bc650 100755..100644 --- a/CPP/7zip/Archive/RpmHandler.cpp +++ b/CPP/7zip/Archive/RpmHandler.cpp @@ -4,10 +4,14 @@ #include "../../../C/CpuArch.h" -#include "Common/ComTry.h" -#include "Common/MyString.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyString.h" +#include "../../Common/StringConvert.h" +#include "../../Common/UTFConvert.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -16,6 +20,8 @@ #include "../Compress/CopyCoder.h" +// #define _SHOW_RPM_METADATA + using namespace NWindows; #define Get16(p) GetBe16(p) @@ -24,130 +30,144 @@ using namespace NWindows; namespace NArchive { namespace NRpm { -/* Reference: lib/signature.h of rpm package */ -#define RPMSIG_NONE 0 /* Do not change! */ -/* The following types are no longer generated */ -#define RPMSIG_PGP262_1024 1 /* No longer generated */ /* 256 byte */ -/* These are the new-style signatures. They are Header structures. */ -/* Inside them we can put any number of any type of signature we like. */ +static const unsigned kNameSize = 66; +static const unsigned kLeadSize = kNameSize + 30; +static const unsigned k_HeaderSig_Size = 16; +static const unsigned k_Entry_Size = 16; -#define RPMSIG_HEADERSIG 5 /* New Header style signature */ +#define RPMSIG_NONE 0 // Old signature +#define RPMSIG_PGP262_1024 1 // Old signature +#define RPMSIG_HEADERSIG 5 // New signature -const UInt32 kLeadSize = 96; -struct CLead +enum { - unsigned char Magic[4]; - unsigned char Major; // not supported ver1, only support 2,3 and lator - unsigned char Minor; - UInt16 Type; - UInt16 ArchNum; - char Name[66]; - UInt16 OSNum; - UInt16 SignatureType; - char Reserved[16]; // pad to 96 bytes -- 8 byte aligned - bool MagicCheck() const - { return Magic[0] == 0xed && Magic[1] == 0xab && Magic[2] == 0xee && Magic[3] == 0xdb; }; + kRpmType_Bin = 0, + kRpmType_Src = 1 }; - -const UInt32 kEntryInfoSize = 16; -/* -struct CEntryInfo + +// There are two sets of TAGs: signature tags and header tags + +// ----- Signature TAGs ----- + +#define RPMSIGTAG_SIZE 1000 // Header + Payload size (32bit) + +// ----- Header TAGs ----- + +#define RPMTAG_NAME 1000 +#define RPMTAG_VERSION 1001 +#define RPMTAG_RELEASE 1002 +#define RPMTAG_BUILDTIME 1006 +#define RPMTAG_OS 1021 // string (old version used int?) +#define RPMTAG_ARCH 1022 // string (old version used int?) +#define RPMTAG_PAYLOADFORMAT 1124 +#define RPMTAG_PAYLOADCOMPRESSOR 1125 +// #define RPMTAG_PAYLOADFLAGS 1126 + +enum { - int Tag; - int Type; - int Offset; // Offset from beginning of data segment, only defined on disk - int Count; + k_EntryType_NULL, + k_EntryType_CHAR, + k_EntryType_INT8, + k_EntryType_INT16, + k_EntryType_INT32, + k_EntryType_INT64, + k_EntryType_STRING, + k_EntryType_BIN, + k_EntryType_STRING_ARRAY, + k_EntryType_I18NSTRING }; -*/ -// case: SignatureType == RPMSIG_HEADERSIG -const UInt32 kCSigHeaderSigSize = 16; -struct CSigHeaderSig +static const char *k_CPUs[] = { - unsigned char Magic[4]; - UInt32 Reserved; - UInt32 IndexLen; // count of index entries - UInt32 DataLen; // number of bytes - bool MagicCheck() - { return Magic[0] == 0x8e && Magic[1] == 0xad && Magic[2] == 0xe8 && Magic[3] == 0x01; }; - UInt32 GetLostHeaderLen() - { return IndexLen * kEntryInfoSize + DataLen; }; + "noarch" + , "i386" + , "alpha" + , "sparc" + , "mips" + , "ppc" + , "m68k" + , "sgi" + , "rs6000" + , "ia64" + , "sparc64" // 10 ??? + , "mipsel" + , "arm" + , "m68kmint" + , "s390" + , "s390x" + , "ppc64" + , "sh" + , "xtensa" + , "aarch64" // 19 }; -static HRESULT RedSigHeaderSig(IInStream *inStream, CSigHeaderSig &h) +static const char *k_OS[] = { - char dat[kCSigHeaderSigSize]; - char *cur = dat; - RINOK(ReadStream_FALSE(inStream, dat, kCSigHeaderSigSize)); - memcpy(h.Magic, cur, 4); - cur += 4; - cur += 4; - h.IndexLen = Get32(cur); - cur += 4; - h.DataLen = Get32(cur); - return S_OK; -} + "0" + , "Linux" + , "Irix" + , "solaris" + , "SunOS" + , "AmigaOS" // AIX + , "HP-UX" + , "osf" + , "FreeBSD" + , "SCO_SV" + , "Irix64" + , "NextStep" + , "bsdi" + , "machten" + , "cygwin32-NT" + , "cygwin32-95" + , "MP_RAS" + , "MiNT" + , "OS/390" + , "VM/ESA" + , "Linux/390" // "Linux/ESA" + , "Darwin" // "MacOSX" 21 +}; -HRESULT OpenArchive(IInStream *inStream) +struct CLead { - UInt64 pos; - char leadData[kLeadSize]; - char *cur = leadData; - CLead lead; - RINOK(ReadStream_FALSE(inStream, leadData, kLeadSize)); - memcpy(lead.Magic, cur, 4); - cur += 4; - lead.Major = *cur++; - lead.Minor = *cur++; - lead.Type = Get16(cur); - cur += 2; - lead.ArchNum = Get16(cur); - cur += 2; - memcpy(lead.Name, cur, sizeof(lead.Name)); - cur += sizeof(lead.Name); - lead.OSNum = Get16(cur); - cur += 2; - lead.SignatureType = Get16(cur); - cur += 2; - - if (!lead.MagicCheck() || lead.Major < 3) - return S_FALSE; + unsigned char Major; + unsigned char Minor; + UInt16 Type; + UInt16 Cpu; + UInt16 Os; + UInt16 SignatureType; + char Name[kNameSize]; + // char Reserved[16]; - CSigHeaderSig sigHeader, header; - if (lead.SignatureType == RPMSIG_NONE) - { - ; - } - else if (lead.SignatureType == RPMSIG_PGP262_1024) + void Parse(const Byte *p) { - UInt64 pos; - RINOK(inStream->Seek(256, STREAM_SEEK_CUR, &pos)); + Major = p[4]; + Minor = p[5]; + Type = Get16(p + 6); + Cpu= Get16(p + 8); + memcpy(Name, p + 10, kNameSize); + p += 10 + kNameSize; + Os = Get16(p); + SignatureType = Get16(p + 2); } - else if (lead.SignatureType == RPMSIG_HEADERSIG) + + bool IsSupported() const { return Major >= 3 && Type <= 1; } +}; + +struct CEntry +{ + UInt32 Tag; + UInt32 Type; + UInt32 Offset; + UInt32 Count; + + void Parse(const Byte *p) { - RINOK(RedSigHeaderSig(inStream, sigHeader)); - if (!sigHeader.MagicCheck()) - return S_FALSE; - UInt32 len = sigHeader.GetLostHeaderLen(); - RINOK(inStream->Seek(len, STREAM_SEEK_CUR, &pos)); - if ((pos % 8) != 0) - { - RINOK(inStream->Seek((pos / 8 + 1) * 8 - pos, - STREAM_SEEK_CUR, &pos)); - } + Tag = Get32(p + 0); + Type = Get32(p + 4); + Offset = Get32(p + 8); + Count = Get32(p + 12); } - else - return S_FALSE; - - RINOK(RedSigHeaderSig(inStream, header)); - if (!header.MagicCheck()) - return S_FALSE; - int headerLen = header.GetLostHeaderLen(); - if (headerLen == -1) - return S_FALSE; - RINOK(inStream->Seek(headerLen, STREAM_SEEK_CUR, &pos)); - return S_OK; -} +}; class CHandler: public IInArchive, @@ -155,104 +175,575 @@ class CHandler: public CMyUnknownImp { CMyComPtr<IInStream> _stream; - UInt64 _pos; + + UInt64 _headersSize; // is equal to start offset of payload data + UInt64 _payloadSize; UInt64 _size; - Byte _sig[4]; + // _size = _payloadSize, if (_payloadSize_Defined) + // _size = (fileSize - _headersSize), if (!_payloadSize_Defined) + UInt64 _phySize; // _headersSize + _payloadSize, if (_phySize_Defined) + UInt32 _headerPlusPayload_Size; + UInt32 _buildTime; + + bool _payloadSize_Defined; + bool _phySize_Defined; + bool _headerPlusPayload_Size_Defined; + bool _time_Defined; + + Byte _payloadSig[6]; // start data of payload + + AString _name; // p7zip + AString _version; // 9.20.1 + AString _release; // 8.1.1 + AString _arch; // x86_64 + AString _os; // linux + + AString _format; // cpio + AString _compressor; // xz, gzip, bzip2 + + CLead _lead; + + #ifdef _SHOW_RPM_METADATA + AString _metadata; + #endif + + void SetTime(NCOM::CPropVariant &prop) const + { + if (_time_Defined && _buildTime != 0) + { + FILETIME ft; + if (NTime::UnixTime64ToFileTime(_buildTime, ft)) + prop = ft; + } + } + + void SetStringProp(const AString &s, NCOM::CPropVariant &prop) const + { + UString us; + if (!ConvertUTF8ToUnicode(s, us)) + us = GetUnicodeString(s); + if (!us.IsEmpty()) + prop = us; + } + + void AddCPU(AString &s) const; + AString GetBaseName() const; + void AddSubFileExtension(AString &res) const; + + HRESULT ReadHeader(ISequentialInStream *stream, bool isMainHeader); + HRESULT Open2(ISequentialInStream *stream); public: MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; -STATPROPSTG kProps[] = +static const Byte kArcProps[] = { - { NULL, kpidSize, VT_UI8} + kpidHeadersSize, + kpidCpu, + kpidHostOS, + kpidCTime + #ifdef _SHOW_RPM_METADATA + , kpidComment + #endif +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidCTime }; IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table +IMP_IInArchive_ArcProps -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +void CHandler::AddCPU(AString &s) const { - NCOM::CPropVariant prop; - switch(propID) { case kpidMainSubfile: prop = (UInt32)0; break; } - prop.Detach(value); - return S_OK; + if (!_arch.IsEmpty()) + s += _arch; + else + { + if (_lead.Type == kRpmType_Bin) + { + char temp[16]; + const char *p; + if (_lead.Cpu < ARRAY_SIZE(k_CPUs)) + p = k_CPUs[_lead.Cpu]; + else + { + ConvertUInt32ToString(_lead.Cpu, temp); + p = temp; + } + s += p; + } + } } -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) +AString CHandler::GetBaseName() const { - COM_TRY_BEGIN - try + AString s; + if (!_name.IsEmpty()) { - Close(); - if (OpenArchive(inStream) != S_OK) - return S_FALSE; - RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_pos)); - RINOK(ReadStream_FALSE(inStream, _sig, sizeof(_sig) / sizeof(_sig[0]))); - UInt64 endPosition; - RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPosition)); - _size = endPosition - _pos; - _stream = inStream; - return S_OK; + s = _name; + if (!_version.IsEmpty()) + { + s += '-'; + s += _version; + } + if (!_release.IsEmpty()) + { + s += '-'; + s += _release; + } } - catch(...) { return S_FALSE; } - COM_TRY_END + else + { + char *p = s.GetBuffer(kNameSize); + memcpy(p, _lead.Name, kNameSize); + p[kNameSize] = 0; + s.ReleaseBuffer(); + } + + s += '.'; + if (_lead.Type == kRpmType_Src) + s += "src"; + else + AddCPU(s); + return s; } -STDMETHODIMP CHandler::Close() +void CHandler::AddSubFileExtension(AString &res) const { - _stream.Release(); - return S_OK; + if (!_format.IsEmpty()) + res += _format; + else + res += "cpio"; + res += '.'; + + const char *s; + + if (!_compressor.IsEmpty()) + { + s = _compressor; + if (_compressor == "bzip2") + s = "bz2"; + else if (_compressor == "gzip") + s = "gz"; + } + else + { + const Byte *p = _payloadSig; + if (p[0] == 0x1F && p[1] == 0x8B) + s = "gz"; + else if (p[0] == 0xFD && p[1] == '7' && p[2] == 'z' && p[3] == 'X' && p[4] == 'Z' && p[5] == 0) + s = "xz"; + else if (p[0] == 'B' && p[1] == 'Z' && p[2] == 'h' && p[3] >= '1' && p[3] <= '9') + s = "bz2"; + else + s = "lzma"; + } + + res += s; } -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { - *numItems = 1; + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + + case kpidHeadersSize: prop = _headersSize; break; + case kpidPhySize: if (_phySize_Defined) prop = _phySize; break; + + case kpidMTime: + case kpidCTime: + SetTime(prop); + break; + + case kpidCpu: + { + AString s; + AddCPU(s); + /* + if (_lead.Type == kRpmType_Src) + s = "src"; + */ + SetStringProp(s, prop); + break; + } + + case kpidHostOS: + { + if (!_os.IsEmpty()) + SetStringProp(_os, prop); + else + { + char temp[16]; + const char *p; + if (_lead.Os < ARRAY_SIZE(k_OS)) + p = k_OS[_lead.Os]; + else + { + ConvertUInt32ToString(_lead.Os, temp); + p = temp; + } + prop = p; + } + break; + } + + #ifdef _SHOW_RPM_METADATA + case kpidComment: SetStringProp(_metadata, prop); break; + #endif + + case kpidName: + { + AString s = GetBaseName(); + s += ".rpm"; + SetStringProp(s, prop); + break; + } + } + prop.Detach(value); return S_OK; + COM_TRY_END } + STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { NWindows::NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidSize: case kpidPackSize: prop = _size; break; + + case kpidMTime: + case kpidCTime: + SetTime(prop); + break; + + case kpidPath: + { + AString s = GetBaseName(); + s += '.'; + AddSubFileExtension(s); + SetStringProp(s, prop); + break; + } + + /* case kpidExtension: { - char s[32]; - MyStringCopy(s, "cpio."); - const char *ext; - if (_sig[0] == 0x1F && _sig[1] == 0x8B) - ext = "gz"; - else if (_sig[0] == 'B' && _sig[1] == 'Z' && _sig[2] == 'h') - ext = "bz2"; - else - ext = "lzma"; - MyStringCopy(s + MyStringLen(s), ext); - prop = s; + prop = GetSubFileExtension(); break; } + */ } prop.Detach(value); return S_OK; } +#ifdef _SHOW_RPM_METADATA +static inline char GetHex(unsigned value) +{ + return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); +} +#endif + +HRESULT CHandler::ReadHeader(ISequentialInStream *stream, bool isMainHeader) +{ + UInt32 numEntries; + UInt32 dataLen; + { + char buf[k_HeaderSig_Size]; + RINOK(ReadStream_FALSE(stream, buf, k_HeaderSig_Size)); + if (Get32(buf) != 0x8EADE801) // buf[3] = 0x01 - is version + return S_FALSE; + // reserved = Get32(buf + 4); + numEntries = Get32(buf + 8); + dataLen = Get32(buf + 12); + if (numEntries >= 1 << 24) + return S_FALSE; + } + size_t indexSize = (size_t)numEntries * k_Entry_Size; + size_t headerSize = indexSize + dataLen; + if (headerSize < dataLen) + return S_FALSE; + CByteBuffer buffer(headerSize); + RINOK(ReadStream_FALSE(stream, buffer, headerSize)); + + for (UInt32 i = 0; i < numEntries; i++) + { + CEntry entry; + + entry.Parse(buffer + (size_t)i * k_Entry_Size); + if (entry.Offset > dataLen) + return S_FALSE; + + const Byte *p = buffer + indexSize + entry.Offset; + size_t rem = dataLen - entry.Offset; + + if (!isMainHeader) + { + if (entry.Tag == RPMSIGTAG_SIZE && + entry.Type == k_EntryType_INT32) + { + if (rem < 4 || entry.Count != 1) + return S_FALSE; + _headerPlusPayload_Size = Get32(p); + _headerPlusPayload_Size_Defined = true; + } + } + else + { + #ifdef _SHOW_RPM_METADATA + { + char temp[16]; + ConvertUInt32ToString(entry.Tag, temp); + + _metadata += temp; + _metadata += ": "; + } + #endif + + if (entry.Type == k_EntryType_STRING) + { + if (entry.Count != 1) + return S_FALSE; + size_t j; + for (j = 0; j < rem && p[j] != 0; j++); + if (j == rem) + return S_FALSE; + AString s = (const char *)p; + switch (entry.Tag) + { + case RPMTAG_NAME: _name = s; break; + case RPMTAG_VERSION: _version = s; break; + case RPMTAG_RELEASE: _release = s; break; + case RPMTAG_ARCH: _arch = s; break; + case RPMTAG_OS: _os = s; break; + case RPMTAG_PAYLOADFORMAT: _format = s; break; + case RPMTAG_PAYLOADCOMPRESSOR: _compressor = s; break; + } + + #ifdef _SHOW_RPM_METADATA + _metadata += s; + #endif + } + else if (entry.Type == k_EntryType_INT32) + { + if (rem / 4 < entry.Count) + return S_FALSE; + if (entry.Tag == RPMTAG_BUILDTIME) + { + if (entry.Count != 1) + return S_FALSE; + _buildTime = Get32(p); + _time_Defined = true; + } + + #ifdef _SHOW_RPM_METADATA + for (UInt32 t = 0; t < entry.Count; t++) + { + if (t != 0) + _metadata += ' '; + char temp[16]; + ConvertUInt32ToString(Get32(p + t * 4), temp); + _metadata += temp; + } + #endif + } + + #ifdef _SHOW_RPM_METADATA + + else if ( + entry.Type == k_EntryType_STRING_ARRAY || + entry.Type == k_EntryType_I18NSTRING) + { + const Byte *p2 = p; + size_t rem2 = rem; + for (UInt32 t = 0; t < entry.Count; t++) + { + if (rem2 == 0) + return S_FALSE; + if (t != 0) + _metadata += '\n'; + size_t j; + for (j = 0; j < rem2 && p2[j] != 0; j++); + if (j == rem2) + return S_FALSE; + _metadata += (const char *)p2; + j++; + p2 += j; + rem2 -= j; + } + } + else if (entry.Type == k_EntryType_INT16) + { + if (rem / 2 < entry.Count) + return S_FALSE; + for (UInt32 t = 0; t < entry.Count; t++) + { + if (t != 0) + _metadata += ' '; + char temp[16]; + ConvertUInt32ToString(Get16(p + t * 2), temp); + _metadata += temp; + } + } + else if (entry.Type == k_EntryType_BIN) + { + if (rem < entry.Count) + return S_FALSE; + for (UInt32 t = 0; t < entry.Count; t++) + { + const unsigned b = p[t]; + _metadata += GetHex((b >> 4) & 0xF); + _metadata += GetHex(b & 0xF); + } + } + else + { + // p = p; + } + _metadata += '\n'; + #endif + } + } + + headerSize += k_HeaderSig_Size; + _headersSize += headerSize; + if (isMainHeader && _headerPlusPayload_Size_Defined) + { + if (_headerPlusPayload_Size < headerSize) + return S_FALSE; + _payloadSize = _headerPlusPayload_Size - headerSize; + _size = _payloadSize; + _phySize = _headersSize + _payloadSize; + _payloadSize_Defined = true; + _phySize_Defined = true; + } + return S_OK; +} + +HRESULT CHandler::Open2(ISequentialInStream *stream) +{ + { + Byte buf[kLeadSize]; + RINOK(ReadStream_FALSE(stream, buf, kLeadSize)); + if (Get32(buf) != 0xEDABEEDB) + return S_FALSE; + _lead.Parse(buf); + if (!_lead.IsSupported()) + return S_FALSE; + } + + _headersSize = kLeadSize; + + if (_lead.SignatureType == RPMSIG_NONE) + { + ; + } + else if (_lead.SignatureType == RPMSIG_PGP262_1024) + { + Byte temp[256]; + RINOK(ReadStream_FALSE(stream, temp, sizeof(temp))); + } + else if (_lead.SignatureType == RPMSIG_HEADERSIG) + { + RINOK(ReadHeader(stream, false)); + unsigned pos = (unsigned)_headersSize & 7; + if (pos != 0) + { + Byte temp[8]; + unsigned num = 8 - pos; + RINOK(ReadStream_FALSE(stream, temp, num)); + _headersSize += num; + } + } + else + return S_FALSE; + + return ReadHeader(stream, true); +} + + +STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *) +{ + COM_TRY_BEGIN + { + Close(); + RINOK(Open2(inStream)); + + // start of payload is allowed to be unaligned + RINOK(ReadStream_FALSE(inStream, _payloadSig, sizeof(_payloadSig))); + + if (!_payloadSize_Defined) + { + UInt64 endPos; + RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); + _size = endPos - _headersSize; + } + _stream = inStream; + return S_OK; + } + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _headersSize = 0; + _payloadSize = 0; + _size = 0; + _phySize = 0; + _headerPlusPayload_Size = 0; + + _payloadSize_Defined = false; + _phySize_Defined = false; + _headerPlusPayload_Size_Defined = false; + _time_Defined = false; + + _name.Empty(); + _version.Empty(); + _release.Empty(); + _arch.Empty(); + _os.Empty(); + + _format.Empty(); + _compressor.Empty(); + + #ifdef _SHOW_RPM_METADATA + _metadata.Empty(); + #endif + + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN if (numItems == 0) return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; RINOK(extractCallback->SetTotal(_size)); + CMyComPtr<ISequentialOutStream> outStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : @@ -262,30 +753,38 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, return S_OK; RINOK(extractCallback->PrepareOperation(askMode)); - CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder; + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); - RINOK(_stream->Seek(_pos, STREAM_SEEK_SET, NULL)); - RINOK(copyCoder->Code(_stream, outStream, NULL, NULL, progress)); + RINOK(_stream->Seek(_headersSize, STREAM_SEEK_SET, NULL)); + RINOK(copyCoder->Code(_stream, outStream, NULL, &_size, progress)); outStream.Release(); - return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK); + Int32 opRes = NExtract::NOperationResult::kOK; + if (copyCoderSpec->TotalSize < _size) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + return extractCallback->SetOperationResult(opRes); COM_TRY_END } STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) { COM_TRY_BEGIN - return CreateLimitedInStream(_stream, _pos, _size, stream); + return CreateLimitedInStream(_stream, _headersSize, _size, stream); COM_TRY_END } -static IInArchive *CreateArc() { return new NArchive::NRpm::CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"Rpm", L"rpm", 0, 0xEB, { 0xED, 0xAB, 0xEE, 0xDB}, 4, false, CreateArc, 0 }; + { "Rpm", "rpm", 0, 0xEB, + 4, { 0xED, 0xAB, 0xEE, 0xDB}, + 0, + 0, + CreateArc }; REGISTER_ARC(Rpm) |