diff options
Diffstat (limited to 'src/libs/7zip/unix/CPP/7zip/Archive/CramfsHandler.cpp')
-rw-r--r-- | src/libs/7zip/unix/CPP/7zip/Archive/CramfsHandler.cpp | 644 |
1 files changed, 0 insertions, 644 deletions
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/CramfsHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/CramfsHandler.cpp deleted file mode 100644 index a55e3743d..000000000 --- a/src/libs/7zip/unix/CPP/7zip/Archive/CramfsHandler.cpp +++ /dev/null @@ -1,644 +0,0 @@ -// CramfsHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/7zCrc.h" -#include "../../../C/CpuArch.h" -#include "../../../C/Alloc.h" - -#include "Common/ComTry.h" -#include "Common/StringConvert.h" - -#include "Windows/PropVariantUtils.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" -#include "../Compress/ZlibDecoder.h" - -namespace NArchive { -namespace NCramfs { - -#define SIGNATURE { 'C','o','m','p','r','e','s','s','e','d',' ','R','O','M','F','S' } - -static const UInt32 kSignatureSize = 16; -static const char kSignature[kSignatureSize] = SIGNATURE; - -static const UInt32 kArcSizeMax = (256 + 16) << 20; -static const UInt32 kNumFilesMax = (1 << 19); -static const unsigned kNumDirLevelsMax = (1 << 8); - -static const UInt32 kHeaderSize = 0x40; -static const unsigned kHeaderNameSize = 16; -static const UInt32 kNodeSize = 12; - -static const UInt32 kFlag_FsVer2 = (1 << 0); - -static const CUInt32PCharPair k_Flags[] = -{ - { 0, "Ver2" }, - { 1, "SortedDirs" }, - { 8, "Holes" }, - { 9, "WrongSignature" }, - { 10, "ShiftedRootOffset" } -}; - -static const unsigned kBlockSizeLog = 12; -static const UInt32 kBlockSize = 1 << kBlockSizeLog; - -/* -struct CNode -{ - UInt16 Mode; - UInt16 Uid; - UInt32 Size; - Byte Gid; - UInt32 NameLen; - UInt32 Offset; - - void Parse(const Byte *p) - { - Mode = GetUi16(p); - Uid = GetUi16(p + 2); - Size = Get32(p + 4) & 0xFFFFFF; - Gid = p[7]; - NameLen = p[8] & 0x3F; - Offset = Get32(p + 8) >> 6; - } -}; -*/ - -#define Get32(p) (be ? GetBe32(p) : GetUi32(p)) - -static UInt32 GetMode(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); } -static bool IsDir(const Byte *p, bool be) { return (GetMode(p, be) & 0xF000) == 0x4000; } - -static UInt32 GetSize(const Byte *p, bool be) -{ - if (be) - return GetBe32(p + 4) >> 8; - else - return GetUi32(p + 4) & 0xFFFFFF; -} - -static UInt32 GetNameLen(const Byte *p, bool be) -{ - if (be) - return (p[8] & 0xFC); - else - return (p[8] & 0x3F) << 2; -} - -static UInt32 GetOffset(const Byte *p, bool be) -{ - if (be) - return (GetBe32(p + 8) & 0x03FFFFFF) << 2; - else - return GetUi32(p + 8) >> 6 << 2; -} - -struct CItem -{ - UInt32 Offset; - int Parent; -}; - -struct CHeader -{ - bool be; - UInt32 Size; - UInt32 Flags; - // UInt32 Future; - UInt32 Crc; - // UInt32 Edition; - UInt32 NumBlocks; - UInt32 NumFiles; - char Name[kHeaderNameSize]; - - bool Parse(const Byte *p) - { - if (memcmp(p + 16, kSignature, kSignatureSize) != 0) - return false; - switch(GetUi32(p)) - { - case 0x28CD3D45: be = false; break; - case 0x453DCD28: be = true; break; - default: return false; - } - Size = Get32(p + 4); - Flags = Get32(p + 8); - // Future = Get32(p + 0xC); - Crc = Get32(p + 0x20); - // Edition = Get32(p + 0x24); - NumBlocks = Get32(p + 0x28); - NumFiles = Get32(p + 0x2C); - memcpy(Name, p + 0x30, kHeaderNameSize); - return true; - } - - bool IsVer2() const { return (Flags & kFlag_FsVer2) != 0; } -}; - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CRecordVector<CItem> _items; - CMyComPtr<IInStream> _stream; - Byte *_data; - UInt32 _size; - UInt32 _headersSize; - AString _errorMessage; - CHeader _h; - - // Current file - - NCompress::NZlib::CDecoder *_zlibDecoderSpec; - CMyComPtr<ICompressCoder> _zlibDecoder; - - CBufInStream *_inStreamSpec; - CMyComPtr<ISequentialInStream> _inStream; - - CBufPtrSeqOutStream *_outStreamSpec; - CMyComPtr<ISequentialOutStream> _outStream; - - UInt32 _curBlocksOffset; - UInt32 _curNumBlocks; - - HRESULT OpenDir(int parent, UInt32 baseOffsetBase, unsigned level); - HRESULT Open2(IInStream *inStream); - AString GetPath(int index) const; - bool GetPackSize(int index, UInt32 &res) const; - void Free(); -public: - CHandler(): _data(0) {} - ~CHandler() { Free(); } - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); -}; - -static const STATPROPSTG kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI4}, - { NULL, kpidPackSize, VT_UI4}, - { NULL, kpidPosixAttrib, VT_UI4} - // { NULL, kpidOffset, VT_UI4} -}; - -static const STATPROPSTG kArcProps[] = -{ - { NULL, kpidName, VT_BSTR}, - { NULL, kpidBigEndian, VT_BOOL}, - { NULL, kpidCharacts, VT_BSTR}, - { NULL, kpidPhySize, VT_UI4}, - { NULL, kpidHeadersSize, VT_UI4}, - { NULL, kpidNumSubFiles, VT_UI4}, - { NULL, kpidNumBlocks, VT_UI4} -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level) -{ - const Byte *p = _data + baseOffset; - bool be = _h.be; - if (!IsDir(p, be)) - return S_OK; - UInt32 offset = GetOffset(p, be); - UInt32 size = GetSize(p, be); - if (offset == 0 && size == 0) - return S_OK; - UInt32 end = offset + size; - if (offset < kHeaderSize || end > _size || level > kNumDirLevelsMax) - return S_FALSE; - if (end > _headersSize) - _headersSize = end; - - int startIndex = _items.Size(); - - while (size != 0) - { - if (size < kNodeSize || (UInt32)_items.Size() >= kNumFilesMax) - return S_FALSE; - CItem item; - item.Parent = parent; - item.Offset = offset; - _items.Add(item); - UInt32 nodeLen = kNodeSize + GetNameLen(_data + offset, be); - if (size < nodeLen) - return S_FALSE; - offset += nodeLen; - size -= nodeLen; - } - - int endIndex = _items.Size(); - for (int i = startIndex; i < endIndex; i++) - { - RINOK(OpenDir(i, _items[i].Offset, level + 1)); - } - return S_OK; -} - -HRESULT CHandler::Open2(IInStream *inStream) -{ - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)); - if (!_h.Parse(buf)) - return S_FALSE; - if (_h.IsVer2()) - { - if (_h.Size < kHeaderSize || _h.Size > kArcSizeMax || _h.NumFiles > kNumFilesMax) - return S_FALSE; - } - else - { - UInt64 size; - RINOK(inStream->Seek(0, STREAM_SEEK_END, &size)); - if (size > kArcSizeMax) - return S_FALSE; - _h.Size = (UInt32)size; - RINOK(inStream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL)); - } - _data = (Byte *)MidAlloc(_h.Size); - if (_data == 0) - return E_OUTOFMEMORY; - memcpy(_data, buf, kHeaderSize); - size_t processed = _h.Size - kHeaderSize; - RINOK(ReadStream(inStream, _data + kHeaderSize, &processed)); - if (processed < kNodeSize) - return S_FALSE; - _size = kHeaderSize + (UInt32)processed; - if (_size != _h.Size) - _errorMessage = "Unexpected end of archive"; - else - { - SetUi32(_data + 0x20, 0); - if (_h.IsVer2()) - if (CrcCalc(_data, _h.Size) != _h.Crc) - _errorMessage = "CRC error"; - } - if (_h.IsVer2()) - _items.Reserve(_h.NumFiles - 1); - return OpenDir(-1, kHeaderSize, 0); -} - -AString CHandler::GetPath(int index) const -{ - unsigned len = 0; - int indexMem = index; - do - { - const CItem &item = _items[index]; - index = item.Parent; - const Byte *p = _data + item.Offset; - unsigned size = GetNameLen(p, _h.be); - p += kNodeSize; - unsigned i; - for (i = 0; i < size && p[i]; i++); - len += i + 1; - } - while (index >= 0); - len--; - - AString path; - char *dest = path.GetBuffer(len) + len; - index = indexMem; - for (;;) - { - const CItem &item = _items[index]; - index = item.Parent; - const Byte *p = _data + item.Offset; - unsigned size = GetNameLen(p, _h.be); - p += kNodeSize; - unsigned i; - for (i = 0; i < size && p[i]; i++); - dest -= i; - memcpy(dest, p, i); - if (index < 0) - break; - *(--dest) = CHAR_PATH_SEPARATOR; - } - path.ReleaseBuffer(len); - return path; -} - -bool CHandler::GetPackSize(int index, UInt32 &res) const -{ - const CItem &item = _items[index]; - const Byte *p = _data + item.Offset; - bool be = _h.be; - UInt32 offset = GetOffset(p, be); - if (offset < kHeaderSize) - return false; - UInt32 numBlocks = (GetSize(p, be) + kBlockSize - 1) >> kBlockSizeLog; - UInt32 start = offset + numBlocks * 4; - if (start > _size) - return false; - UInt32 end = Get32(_data + start - 4); - if (end < start) - return false; - res = end - start; - return true; -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */) -{ - COM_TRY_BEGIN - { - Close(); - RINOK(Open2(stream)); - _stream = stream; - } - return S_OK; - COM_TRY_END -} - -void CHandler::Free() -{ - MidFree(_data); - _data = 0; -} - -STDMETHODIMP CHandler::Close() -{ - _headersSize = 0; - _items.Clear(); - _stream.Release(); - _errorMessage.Empty(); - Free(); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) - { - case kpidName: - { - char dest[kHeaderNameSize + 4]; - memcpy(dest, _h.Name, kHeaderNameSize); - dest[kHeaderNameSize] = 0; - prop = dest; - break; - } - case kpidBigEndian: prop = _h.be; break; - case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break; - case kpidNumBlocks: if (_h.IsVer2()) prop = _h.NumBlocks; break; - case kpidNumSubFiles: if (_h.IsVer2()) prop = _h.NumFiles; break; - case kpidPhySize: if (_h.IsVer2()) prop = _h.Size; break; - case kpidHeadersSize: prop = _headersSize; break; - case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = _items[index]; - const Byte *p = _data + item.Offset; - bool be = _h.be; - bool isDir = IsDir(p, be); - switch(propID) - { - case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break; - case kpidIsDir: prop = isDir; break; - // case kpidOffset: prop = (UInt32)GetOffset(p, be); break; - case kpidSize: if (!isDir) prop = GetSize(p, be); break; - case kpidPackSize: - if (!isDir) - { - UInt32 size; - if (GetPackSize(index, size)) - prop = size; - } - break; - case kpidPosixAttrib: prop = (UInt32)GetMode(p, be); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -class CCramfsInStream: public CCachedInStream -{ - HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); -public: - CHandler *Handler; -}; - -HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) -{ - return Handler->ReadBlock(blockIndex, dest, blockSize); -} - -HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) -{ - if (!_zlibDecoder) - { - _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); - _zlibDecoder = _zlibDecoderSpec; - } - if (!_inStream) - { - _inStreamSpec = new CBufInStream(); - _inStream = _inStreamSpec; - } - if (!_outStream) - { - _outStreamSpec = new CBufPtrSeqOutStream(); - _outStream = _outStreamSpec; - } - bool be = _h.be; - const Byte *p = _data + (_curBlocksOffset + (UInt32)blockIndex * 4); - UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p - 4)); - UInt32 end = Get32(p); - if (end < start || end > _size) - return S_FALSE; - UInt32 inSize = end - start; - _inStreamSpec->Init(_data + start, inSize); - _outStreamSpec->Init(dest, blockSize); - RINOK(_zlibDecoder->Code(_inStream, _outStream, NULL, NULL, NULL)); - return (_zlibDecoderSpec->GetInputProcessedSize() == inSize && - _outStreamSpec->GetPos() == blockSize) ? S_OK : S_FALSE; -} - -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; - bool be = _h.be; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const Byte *p = _data + _items[allFilesMode ? i : indices[i]].Offset; - if (!IsDir(p, be)) - totalSize += GetSize(p, be); - } - extractCallback->SetTotal(totalSize); - - UInt64 totalPackSize; - totalSize = totalPackSize = 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 = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - CMyComPtr<ISequentialOutStream> outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - RINOK(extractCallback->GetStream(index, &outStream, askMode)); - const Byte *p = _data + item.Offset; - - if (IsDir(p, be)) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - UInt32 curSize = GetSize(p, be); - totalSize += curSize; - UInt32 packSize; - if (GetPackSize(index, packSize)) - totalPackSize += packSize; - - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - - UInt32 offset = GetOffset(p, be); - if (offset < kHeaderSize) - curSize = 0; - - int res = NExtract::NOperationResult::kDataError; - { - CMyComPtr<ISequentialInStream> inSeqStream; - CMyComPtr<IInStream> inStream; - HRESULT hres = GetStream(index, &inSeqStream); - if (inSeqStream) - inSeqStream.QueryInterface(IID_IInStream, &inStream); - if (hres == E_OUTOFMEMORY) - return E_OUTOFMEMORY; - if (hres == S_FALSE || !inStream) - res = NExtract::NOperationResult::kUnSupportedMethod; - else - { - RINOK(hres); - if (inStream) - { - HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress); - if (hres != S_OK && hres != S_FALSE) - { - RINOK(hres); - } - if (copyCoderSpec->TotalSize == curSize && hres == S_OK) - res = NExtract::NOperationResult::kOK; - } - } - } - RINOK(extractCallback->SetOperationResult(res)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - - const CItem &item = _items[index]; - const Byte *p = _data + item.Offset; - - bool be = _h.be; - if (IsDir(p, be)) - return E_FAIL; - - UInt32 size = GetSize(p, be); - UInt32 numBlocks = (size + kBlockSize - 1) >> kBlockSizeLog; - UInt32 offset = GetOffset(p, be); - if (offset < kHeaderSize) - { - if (offset != 0) - return S_FALSE; - CBufInStream *streamSpec = new CBufInStream; - CMyComPtr<IInStream> streamTemp = streamSpec; - streamSpec->Init(NULL, 0); - *stream = streamTemp.Detach(); - return S_OK; - } - - if (offset + numBlocks * 4 > _size) - return S_FALSE; - UInt32 prev = offset; - for (UInt32 i = 0; i < numBlocks; i++) - { - UInt32 next = Get32(_data + offset + i * 4); - if (next < prev || next > _size) - return S_FALSE; - prev = next; - } - - CCramfsInStream *streamSpec = new CCramfsInStream; - CMyComPtr<IInStream> streamTemp = streamSpec; - _curNumBlocks = numBlocks; - _curBlocksOffset = offset; - streamSpec->Handler = this; - if (!streamSpec->Alloc(kBlockSizeLog, 21 - kBlockSizeLog)) - return E_OUTOFMEMORY; - streamSpec->Init(size); - *stream = streamTemp.Detach(); - - return S_OK; - COM_TRY_END -} - -static IInArchive *CreateArc() { return new NArchive::NCramfs::CHandler; } - -static CArcInfo g_ArcInfo = - { L"CramFS", L"cramfs", 0, 0xD3, SIGNATURE, kSignatureSize, false, CreateArc, 0 }; - -REGISTER_ARC(Cramfs) - -}} |