diff options
Diffstat (limited to 'CPP/7zip/Archive/SquashfsHandler.cpp')
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/SquashfsHandler.cpp | 240 |
1 files changed, 138 insertions, 102 deletions
diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp index efaffed1..617a1d66 100755..100644 --- a/CPP/7zip/Archive/SquashfsHandler.cpp +++ b/CPP/7zip/Archive/SquashfsHandler.cpp @@ -7,12 +7,12 @@ #include "../../../C/CpuArch.h" #include "../../../C/Xz.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/StringConvert.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/StringConvert.h" -#include "Windows/PropVariantUtils.h" -#include "Windows/Time.h" +#include "../../Windows/PropVariantUtils.h" +#include "../../Windows/TimeUtils.h" #include "../Common/CWrappers.h" #include "../Common/LimitedStreams.h" @@ -59,8 +59,6 @@ UInt64 Get64b(const Byte *p, bool be) { return be ? GetBe64(p) : GetUi64(p); } #define GET_32(offs, dest) dest = Get32(p + (offs)); #define GET_64(offs, dest) dest = Get64(p + (offs)); -static const UInt32 kSignatureSize = 4; -#define SIGNATURE { 'h', 's', 'q', 's' } static const UInt32 kSignature32_LE = 0x73717368; static const UInt32 kSignature32_BE = 0x68737173; static const UInt32 kSignature32_LZ = 0x71736873; @@ -72,11 +70,11 @@ static const UInt32 kSignature32_LZ = 0x71736873; static const char *k_Methods[] = { - "Unknown", - "ZLIB", - "LZMA", - "LZO", - "XZ" + "Unknown" + , "ZLIB" + , "LZMA" + , "LZO" + , "XZ" }; static const UInt32 kMetadataBlockSizeLog = 13; @@ -315,17 +313,17 @@ UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h) UInt16 t = Get16(p); if (be) { - Type = t >> 12; - Mode = t & 0xFFF; - Uid = p[2] >> 4; - Gid = p[2] & 0xF; + Type = (UInt16)(t >> 12); + Mode = (UInt16)(t & 0xFFF); + Uid = (UInt16)(p[2] >> 4); + Gid = (UInt16)(p[2] & 0xF); } else { - Type = t & 0xF; - Mode = t >> 4; - Uid = p[2] & 0xF; - Gid = p[2] >> 4; + Type = (UInt16)(t & 0xF); + Mode = (UInt16)(t >> 4); + Uid = (UInt16)(p[2] & 0xF); + Gid = (UInt16)(p[2] >> 4); } // Xattr = kXattr_Empty; @@ -339,20 +337,20 @@ UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h) Byte t = p[3]; if (be) { - Type = t >> 4; - Offset = t & 0xF; + Type = (UInt16)(t >> 4); + Offset = (UInt16)(t & 0xF); } else { - Type = t & 0xF; - Offset = t >> 4; + Type = (UInt16)(t & 0xF); + Offset = (UInt16)(t >> 4); } return (Type == kType_FIFO || Type == kType_SOCK) ? 4 : 0; } Type--; - Uid += (Type / 5) * 16; - Type = (Type % 5) + 1; + Uid = (UInt16)(Uid + (Type / 5) * 16); + Type = (UInt16)((Type % 5) + 1); if (Type == kType_FILE) { @@ -418,13 +416,13 @@ UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h) UInt16 t = Get16(p); if (be) { - Type = t >> 12; - Mode = t & 0xFFF; + Type = (UInt16)(t >> 12); + Mode = (UInt16)(t & 0xFFF); } else { - Type = t & 0xF; - Mode = t >> 4; + Type = (UInt16)(t & 0xF); + Mode = (UInt16)(t >> 4); } Uid = p[2]; Gid = p[3]; @@ -548,13 +546,13 @@ UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h) UInt16 t = Get16(p); if (be) { - Type = t >> 12; - Mode = t & 0xFFF; + Type = (UInt16)(t >> 12); + Mode = (UInt16)(t & 0xFFF); } else { - Type = t & 0xF; - Mode = t >> 4; + Type = (UInt16)(t & 0xF); + Mode = (UInt16)(t >> 4); } Uid = p[2]; Gid = p[3]; @@ -841,6 +839,8 @@ class CHandler: // CByteBuffer _uids; // CByteBuffer _gids; CHeader _h; + bool _noPropsLZMA; + bool _needCheckLzma; CMyComPtr<IInStream> _stream; UInt64 _sizeCalculated; @@ -922,31 +922,30 @@ CHandler::CHandler() _dynOutStream = _dynOutStreamSpec; } -static const STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidPosixAttrib, VT_UI4} - // { NULL, kpidUser, VT_BSTR}, - // { NULL, kpidGroup, VT_BSTR}, - // { NULL, kpidLinks, VT_UI4}, - // { NULL, kpidOffset, VT_UI4} + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidPosixAttrib + // kpidUser, + // kpidGroup, + // kpidLinks, + // kpidOffset }; -static const STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidFileSystem, VT_BSTR}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidBlock, VT_UI4}, - { NULL, kpidPhySize, VT_UI8}, - { NULL, kpidHeadersSize, VT_UI8}, - { NULL, kpidBigEndian, VT_BOOL}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidCharacts, VT_BSTR} - // { NULL, kpidNumBlocks, VT_UI4} + kpidHeadersSize, + kpidFileSystem, + kpidMethod, + kpidBlock, + kpidBigEndian, + kpidCTime, + kpidCharacts + // kpidNumBlocks }; IMP_IInArchive_Props @@ -1115,12 +1114,25 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool UInt32 method = _h.Method; if (_h.SeveralMethods) { - Byte props[1]; - RINOK(ReadStream_FALSE(_stream, props, 1)); - method = (props[0] == 0x5D ? kMethod_LZMA : kMethod_ZLIB); + Byte b; + RINOK(ReadStream_FALSE(_stream, &b, 1)); RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL)); + method = (b == 0x5D ? kMethod_LZMA : kMethod_ZLIB); } + if (method == kMethod_ZLIB && _needCheckLzma) + { + Byte b; + RINOK(ReadStream_FALSE(_stream, &b, 1)); + RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL)); + if (b == 0) + { + _noPropsLZMA = true; + method = _h.Method = kMethod_LZMA; + } + _needCheckLzma = false; + } + if (method == kMethod_ZLIB) { if (!_zlibDecoder) @@ -1140,24 +1152,34 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool _lzmaDecoderSpec->FinishStream = true; _lzmaDecoder = _lzmaDecoderSpec; } - const UInt32 kPropsSize = 5 + 8; + const UInt32 kPropsSize = LZMA_PROPS_SIZE + 8; Byte props[kPropsSize]; - ReadStream_FALSE(_limitedInStream, props, kPropsSize); - RINOK(_lzmaDecoderSpec->SetDecoderProperties2(props, 5)); - UInt64 outSize = GetUi64(props + 5); - if (outSize > outSizeMax) - return S_FALSE; + UInt32 propsSize; + UInt64 outSize; + if (_noPropsLZMA) + { + props[0] = 0x5D; + SetUi32(&props[1], _h.BlockSize); + propsSize = 0; + outSize = outSizeMax; + } + else + { + RINOK(ReadStream_FALSE(_limitedInStream, props, kPropsSize)); + propsSize = kPropsSize; + outSize = GetUi64(&props[LZMA_PROPS_SIZE]); + if (outSize > outSizeMax) + return S_FALSE; + } + RINOK(_lzmaDecoderSpec->SetDecoderProperties2(props, LZMA_PROPS_SIZE)); RINOK(_lzmaDecoder->Code(_limitedInStream, outStream, NULL, &outSize, NULL)); - if (inSize != kPropsSize + _lzmaDecoderSpec->GetInputProcessedSize()) + if (inSize != propsSize + _lzmaDecoderSpec->GetInputProcessedSize()) return S_FALSE; } else { - if (_inputBuffer.GetCapacity() < inSize) - { - _inputBuffer.Free(); - _inputBuffer.SetCapacity(inSize); - } + if (_inputBuffer.Size() < inSize) + _inputBuffer.Alloc(inSize); RINOK(ReadStream_FALSE(_stream, _inputBuffer, inSize)); Byte *dest = outBuf; @@ -1287,22 +1309,23 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned if (blockIndex < 0) return S_FALSE; unpackPos = _dirs.UnpackPos[blockIndex] + n.Offset; - if (unpackPos < n.Offset || unpackPos > _dirs.Data.GetCapacity()) + if (unpackPos < n.Offset || unpackPos > _dirs.Data.Size()) return S_FALSE; - UInt32 rem = (UInt32)_dirs.Data.GetCapacity() - unpackPos; + UInt32 rem = (UInt32)_dirs.Data.Size() - unpackPos; const Byte *p = _dirs.Data + unpackPos; UInt32 fileSize = (UInt32)n.FileSize; - if (fileSize > rem) - return S_FALSE; - rem = fileSize; + // for some squashfs files: fileSize = rem + 3 !!! if (_h.Major >= 3) { - if (rem < 3) + if (fileSize < 3) return S_FALSE; - rem -= 3; + fileSize -= 3; } + if (fileSize > rem) + return S_FALSE; + rem = fileSize; CRecordVector<CTempItem> tempItems; while (rem != 0) @@ -1412,7 +1435,7 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned } int startItemIndex = _items.Size() - tempItems.Size(); - for (int i = 0; i < tempItems.Size(); i++) + FOR_VECTOR (i, tempItems) { const CTempItem &tempItem = tempItems[i]; int index = startItemIndex + i; @@ -1443,9 +1466,11 @@ HRESULT CHandler::Open2(IInStream *inStream) if (!_h.IsSupported()) return E_NOTIMPL; + _noPropsLZMA = false; + _needCheckLzma = false; switch (_h.Method) { - case kMethod_ZLIB: + case kMethod_ZLIB: _needCheckLzma = true; break; case kMethod_LZMA: case kMethod_LZO: case kMethod_XZ: @@ -1461,14 +1486,13 @@ HRESULT CHandler::Open2(IInStream *inStream) { if (_h.NumFrags > kNumFilesMax) return S_FALSE; - _frags.Reserve(_h.NumFrags); - CByteBuffer data; + _frags.ClearAndReserve(_h.NumFrags); unsigned bigFrag = (_h.Major > 2); unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag); UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog; size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag); - data.SetCapacity(numBlocksBytes); + CByteBuffer data(numBlocksBytes); RINOK(inStream->Seek(_h.FragTable, STREAM_SEEK_SET, NULL)); RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); bool be = _h.be; @@ -1518,11 +1542,11 @@ HRESULT CHandler::Open2(IInStream *inStream) return S_FALSE; { UInt32 pos = 0; - UInt32 totalSize = (UInt32)_inodesData.Data.GetCapacity(); - _nodesPos.Reserve(_h.NumInodes); - _nodes.Reserve(_h.NumInodes); + UInt32 totalSize = (UInt32)_inodesData.Data.Size(); + _nodesPos.ClearAndReserve(_h.NumInodes); + _nodes.ClearAndReserve(_h.NumInodes); // we use _blockToNode for binary search seed optimizations - _blockToNode.Reserve(_inodesData.GetNumBlocks() + 1); + _blockToNode.ClearAndReserve(_inodesData.GetNumBlocks() + 1); int curBlock = 0; for (UInt32 i = 0; i < _h.NumInodes; i++) { @@ -1544,8 +1568,8 @@ HRESULT CHandler::Open2(IInStream *inStream) _blockToNode.Add(_nodesPos.Size()); curBlock++; } - _nodesPos.Add(pos); - _nodes.Add(n); + _nodesPos.AddInReserved(pos); + _nodes.AddInReserved(n); pos += size; } _blockToNode.Add(_nodesPos.Size()); @@ -1657,7 +1681,6 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb HRESULT res; try { - RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); _openCallback = callback; res = Open2(stream); } @@ -1679,6 +1702,8 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb STDMETHODIMP CHandler::Close() { + _sizeCalculated = 0; + _limitedInStreamSpec->ReleaseStream(); _stream.Release(); @@ -1801,12 +1826,14 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidMethod: { const char *s; - if (_h.SeveralMethods) + if (_noPropsLZMA) + s = "LZMA Spec"; + else if (_h.SeveralMethods) s = "LZMA ZLIB"; else { s = k_Methods[0]; - if (_h.Method < sizeof(k_Methods) / sizeof(k_Methods[0])) + if (_h.Method < ARRAY_SIZE(k_Methods)) s = k_Methods[_h.Method]; } prop = s; @@ -1906,7 +1933,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } case kpidPosixAttrib: { - if (node.Type != 0 && node.Type < sizeof(k_TypeToMode) / sizeof(k_TypeToMode[0])) + if (node.Type != 0 && node.Type < ARRAY_SIZE(k_TypeToMode)) prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type]; break; } @@ -1914,7 +1941,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidUser: { UInt32 offset = node.Uid * 4; - if (offset < _uids.GetCapacity()) + if (offset < _uids.Size()) prop = (UInt32)Get32(_uids + offset); break; } @@ -1923,13 +1950,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (_h.Major == 4 || node.Gid == _h.GetSpecGuidIndex()) { UInt32 offset = node.Uid * 4; - if (offset < _uids.GetCapacity()) + if (offset < _uids.Size()) prop = (UInt32)Get32(_uids + offset); } else { UInt32 offset = node.Gid * 4; - if (offset < _gids.GetCapacity()) + if (offset < _gids.Size()) prop = (UInt32)Get32(_gids + offset); } break; @@ -2028,7 +2055,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (numItems == 0) @@ -2095,7 +2122,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { if (hres == E_OUTOFMEMORY) return hres; - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; } else { @@ -2110,7 +2137,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } else if (hres == E_NOTIMPL) { - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; } else if(hres != S_FALSE) { @@ -2157,10 +2184,10 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) _nodeIndex = item.Node; size_t cacheSize = _h.BlockSize; - if (_cachedBlock.GetCapacity() != cacheSize) + if (_cachedBlock.Size() != cacheSize) { ClearCache(); - _cachedBlock.SetCapacity(cacheSize); + _cachedBlock.Alloc(cacheSize); } CSquashfsInStream *streamSpec = new CSquashfsInStream; @@ -2179,10 +2206,19 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -static IInArchive *CreateArc() { return new NArchive::NSquashfs::CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"SquashFS", L"squashfs", 0, 0xD2, SIGNATURE, kSignatureSize, false, CreateArc, 0 }; + { "SquashFS", "squashfs", 0, 0xD2, + 3 * (1 + 4), + { + 4, 'h', 's', 'q', 's', + 4, 's', 'q', 's', 'h', + 4, 's', 'h', 's', 'q', + }, + 0, + NArcInfoFlags::kMultiSignature, + CreateArc }; REGISTER_ARC(Cramfs) |