diff options
Diffstat (limited to 'src/libs/7zip/unix/CPP/7zip/Archive/DebHandler.cpp')
-rw-r--r-- | src/libs/7zip/unix/CPP/7zip/Archive/DebHandler.cpp | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/DebHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/DebHandler.cpp new file mode 100644 index 000000000..82d2cde88 --- /dev/null +++ b/src/libs/7zip/unix/CPP/7zip/Archive/DebHandler.cpp @@ -0,0 +1,413 @@ +// DebHandler.cpp + +#include "StdAfx.h" + +#include "Common/ComTry.h" +#include "Common/StringConvert.h" +#include "Common/StringToInt.h" + +#include "Windows/PropVariant.h" +#include "Windows/Time.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#include "Common/ItemNameUtils.h" + +using namespace NWindows; +using namespace NTime; + +namespace NArchive { +namespace NDeb { + +namespace NHeader +{ + const int kSignatureLen = 8; + + const char *kSignature = "!<arch>\n"; + + const int kNameSize = 16; + const int kTimeSize = 12; + const int kModeSize = 8; + const int kSizeSize = 10; + + /* + struct CHeader + { + char Name[kNameSize]; + char MTime[kTimeSize]; + char Number0[6]; + char Number1[6]; + char Mode[kModeSize]; + char Size[kSizeSize]; + char Quote; + char NewLine; + }; + */ + const int kHeaderSize = kNameSize + kTimeSize + 6 + 6 + kModeSize + kSizeSize + 1 + 1; +} + +struct CItem +{ + AString Name; + UInt64 Size; + UInt32 MTime; + UInt32 Mode; + + UInt64 HeaderPos; + UInt64 GetDataPos() const { return HeaderPos + NHeader::kHeaderSize; }; + // UInt64 GetFullSize() const { return NFileHeader::kRecordSize + Size; }; +}; + +class CInArchive +{ + CMyComPtr<IInStream> m_Stream; + + HRESULT GetNextItemReal(bool &filled, CItem &itemInfo); +public: + UInt64 m_Position; + HRESULT Open(IInStream *inStream); + HRESULT GetNextItem(bool &filled, CItem &itemInfo); + HRESULT SkipData(UInt64 dataSize); +}; + +HRESULT CInArchive::Open(IInStream *inStream) +{ + RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position)); + char signature[NHeader::kSignatureLen]; + RINOK(ReadStream_FALSE(inStream, signature, NHeader::kSignatureLen)); + m_Position += NHeader::kSignatureLen; + if (memcmp(signature, NHeader::kSignature, NHeader::kSignatureLen) != 0) + return S_FALSE; + m_Stream = inStream; + return S_OK; +} + +static void MyStrNCpy(char *dest, const char *src, int size) +{ + for (int i = 0; i < size; i++) + { + char c = src[i]; + dest[i] = c; + if (c == 0) + break; + } +} + +static bool OctalToNumber(const char *s, int size, UInt64 &res) +{ + char sz[32]; + MyStrNCpy(sz, s, size); + sz[size] = 0; + const char *end; + int i; + for (i = 0; sz[i] == ' '; i++); + res = ConvertOctStringToUInt64(sz + i, &end); + return (*end == ' ' || *end == 0); +} + +static bool OctalToNumber32(const char *s, int size, UInt32 &res) +{ + UInt64 res64; + if (!OctalToNumber(s, size, res64)) + return false; + res = (UInt32)res64; + return (res64 <= 0xFFFFFFFF); +} + +static bool DecimalToNumber(const char *s, int size, UInt64 &res) +{ + char sz[32]; + MyStrNCpy(sz, s, size); + sz[size] = 0; + const char *end; + int i; + for (i = 0; sz[i] == ' '; i++); + res = ConvertStringToUInt64(sz + i, &end); + return (*end == ' ' || *end == 0); +} + +static bool DecimalToNumber32(const char *s, int size, UInt32 &res) +{ + UInt64 res64; + if (!DecimalToNumber(s, size, res64)) + return false; + res = (UInt32)res64; + return (res64 <= 0xFFFFFFFF); +} + +#define RIF(x) { if (!(x)) return S_FALSE; } + + +HRESULT CInArchive::GetNextItemReal(bool &filled, CItem &item) +{ + filled = false; + + char header[NHeader::kHeaderSize]; + const char *cur = header; + + size_t processedSize = sizeof(header); + item.HeaderPos = m_Position; + RINOK(ReadStream(m_Stream, header, &processedSize)); + if (processedSize != sizeof(header)) + return S_OK; + m_Position += processedSize; + + char tempString[NHeader::kNameSize + 1]; + MyStrNCpy(tempString, cur, NHeader::kNameSize); + cur += NHeader::kNameSize; + tempString[NHeader::kNameSize] = '\0'; + item.Name = tempString; + item.Name.Trim(); + + for (int i = 0; i < item.Name.Length(); i++) + if (((Byte)item.Name[i]) < 0x20) + return S_FALSE; + + RIF(DecimalToNumber32(cur, NHeader::kTimeSize, item.MTime)); + cur += NHeader::kTimeSize; + + cur += 6 + 6; + + RIF(OctalToNumber32(cur, NHeader::kModeSize, item.Mode)); + cur += NHeader::kModeSize; + + RIF(DecimalToNumber(cur, NHeader::kSizeSize, item.Size)); + cur += NHeader::kSizeSize; + + filled = true; + return S_OK; +} + +HRESULT CInArchive::GetNextItem(bool &filled, CItem &item) +{ + for (;;) + { + RINOK(GetNextItemReal(filled, item)); + if (!filled) + return S_OK; + if (item.Name.Compare("debian-binary") != 0) + return S_OK; + if (item.Size != 4) + return S_OK; + SkipData(item.Size); + } +} + +HRESULT CInArchive::SkipData(UInt64 dataSize) +{ + return m_Stream->Seek((dataSize + 1) & (~((UInt64)0x1)), STREAM_SEEK_CUR, &m_Position); +} + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CObjectVector<CItem> _items; + CMyComPtr<IInStream> _stream; + Int32 _mainSubfile; + UInt64 _phySize; +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +static STATPROPSTG kArcProps[] = +{ + { NULL, kpidPhySize, VT_UI8} +}; + +static STATPROPSTG kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidMTime, VT_FILETIME} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback *openArchiveCallback) +{ + COM_TRY_BEGIN + { + _mainSubfile = -1; + CInArchive archive; + if (archive.Open(stream) != S_OK) + return S_FALSE; + _items.Clear(); + + if (openArchiveCallback != NULL) + { + RINOK(openArchiveCallback->SetTotal(NULL, NULL)); + UInt64 numFiles = _items.Size(); + RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL)); + } + + for (;;) + { + CItem item; + bool filled; + HRESULT result = archive.GetNextItem(filled, item); + if (result == S_FALSE) + return S_FALSE; + if (result != S_OK) + return S_FALSE; + if (!filled) + break; + if (item.Name.Left(5) == "data.") + _mainSubfile = _items.Size(); + _items.Add(item); + archive.SkipData(item.Size); + if (openArchiveCallback != NULL) + { + UInt64 numFiles = _items.Size(); + RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL)); + } + } + _stream = stream; + _phySize = archive.m_Position; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _stream.Release(); + _items.Clear(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + NCOM::CPropVariant prop; + switch(propID) + { + case kpidPhySize: prop = _phySize; break; + case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; + } + prop.Detach(value); + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem &item = _items[index]; + + switch(propID) + { + case kpidPath: prop = (const wchar_t *)NItemName::GetOSName2(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break; + case kpidSize: + case kpidPackSize: + prop = item.Size; + break; + case kpidMTime: + { + if (item.MTime != 0) + { + FILETIME fileTime; + NTime::UnixTimeToFileTime(item.MTime, fileTime); + prop = fileTime; + } + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _items[allFilesMode ? i : indices[i]].Size; + extractCallback->SetTotal(totalSize); + + UInt64 currentTotalSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream(streamSpec); + streamSpec->SetStream(_stream); + + for (i = 0; i < numItems; i++) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + CMyComPtr<ISequentialOutStream> realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + currentTotalSize += item.Size; + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + if (testMode) + { + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + RINOK(_stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL)); + streamSpec->Init(item.Size); + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + const CItem &item = _items[index]; + return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream); + COM_TRY_END +} + +static IInArchive *CreateArc() { return new NArchive::NDeb::CHandler; } + +static CArcInfo g_ArcInfo = + { L"Deb", L"deb", 0, 0xEC, { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' }, 8, false, CreateArc, 0 }; + +REGISTER_ARC(Deb) + +}} |