Compress-Deflate7
view release on metacpan or search on metacpan
7zip/CPP/7zip/Archive/SquashfsHandler.cpp view on Meta::CPAN
if (size < 24)
return 0;
// LE_32 (20, RDev);
offset = 24;
break;
default:
return 0;
}
if (Type >= 8)
{
if (size < offset + 4)
return 0;
// LE_32 (offset, Xattr);
offset += 4;
}
return offset;
}
struct CItem
{
int Node;
int Parent;
UInt32 Ptr;
};
struct CData
{
CByteBuffer Data;
CRecordVector<UInt32> PackPos;
CRecordVector<UInt32> UnpackPos; // additional item at the end contains TotalUnpackSize
UInt32 GetNumBlocks() const { return PackPos.Size(); }
void Clear()
{
Data.Free();
PackPos.Clear();
UnpackPos.Clear();
}
};
struct CFrag
{
UInt64 StartBlock;
UInt32 Size;
};
class CHandler:
public IInArchive,
public IInArchiveGetStream,
public CMyUnknownImp
{
CRecordVector<CItem> _items;
CRecordVector<CNode> _nodes;
CRecordVector<UInt32> _nodesPos;
CRecordVector<UInt32> _blockToNode;
CData _inodesData;
CData _dirs;
CRecordVector<CFrag> _frags;
// CByteBuffer _uids;
// CByteBuffer _gids;
CHeader _h;
CMyComPtr<IInStream> _stream;
UInt64 _sizeCalculated;
IArchiveOpenCallback *_openCallback;
int _nodeIndex;
CRecordVector<bool> _blockCompressed;
CRecordVector<UInt64> _blockOffsets;
CByteBuffer _cachedBlock;
UInt64 _cachedBlockStartPos;
UInt32 _cachedPackBlockSize;
UInt32 _cachedUnpackBlockSize;
CLimitedSequentialInStream *_limitedInStreamSpec;
CMyComPtr<ISequentialInStream> _limitedInStream;
CBufPtrSeqOutStream *_outStreamSpec;
CMyComPtr<ISequentialOutStream> _outStream;
NCompress::NLzma::CDecoder *_lzmaDecoderSpec;
CMyComPtr<ICompressCoder> _lzmaDecoder;
NCompress::NZlib::CDecoder *_zlibDecoderSpec;
CMyComPtr<ICompressCoder> _zlibDecoder;
CByteBuffer _inputBuffer;
CDynBufSeqOutStream *_dynOutStreamSpec;
CMyComPtr<ISequentialOutStream> _dynOutStream;
void ClearCache()
{
_cachedBlockStartPos = 0;
_cachedPackBlockSize = 0;
_cachedUnpackBlockSize = 0;
}
HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize,
UInt32 inSize, UInt32 outSizeMax);
HRESULT ReadMetadataBlock(UInt32 &packSize);
HRESULT ReadData(CData &data, UInt64 start, UInt64 end);
HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex);
HRESULT ScanInodes(UInt64 ptr);
// HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids);
HRESULT Open2(IInStream *inStream);
AString GetPath(int index) const;
bool GetPackSize(int index, UInt64 &res, bool fillOffsets);
public:
CHandler();
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
};
7zip/CPP/7zip/Archive/SquashfsHandler.cpp view on Meta::CPAN
j += 8;
}
_frags.Add(frag);
}
}
if ((UInt32)_frags.Size() != _h.NumFrags)
return S_FALSE;
}
// RINOK(inStream->Seek(_h.InodeTable, STREAM_SEEK_SET, NULL));
RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable));
RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable));
UInt64 absOffset = _h.RootInode >> 16;
if (absOffset >= ((UInt64)1 << 32))
return S_FALSE;
{
UInt32 pos = 0;
UInt32 totalSize = (UInt32)_inodesData.Data.GetCapacity();
_nodesPos.Reserve(_h.NumInodes);
_nodes.Reserve(_h.NumInodes);
// we use _blockToNode for binary search seed optimizations
_blockToNode.Reserve(_inodesData.GetNumBlocks() + 1);
int curBlock = 0;
for (UInt32 i = 0; i < _h.NumInodes; i++)
{
CNode n;
const Byte *p = _inodesData.Data + pos;
UInt32 size = totalSize - pos;
switch(_h.Major)
{
case 1: size = n.Parse1(p, size, _h); break;
case 2: size = n.Parse2(p, size, _h); break;
case 3: size = n.Parse3(p, size, _h); break;
default: size = n.Parse4(p, size, _h); break;
}
if (size == 0)
return S_FALSE;
while (pos >= _inodesData.UnpackPos[curBlock])
{
_blockToNode.Add(_nodesPos.Size());
curBlock++;
}
_nodesPos.Add(pos);
_nodes.Add(n);
pos += size;
}
_blockToNode.Add(_nodesPos.Size());
if (pos != totalSize)
return S_FALSE;
}
int rootNodeIndex;
RINOK(OpenDir(-1, (UInt32)absOffset, (UInt32)_h.RootInode & 0xFFFF, 0, rootNodeIndex));
/*
if (_h.Major < 4)
{
RINOK(ReadUids(_h.UidTable, _h.NumUids, _uids));
RINOK(ReadUids(_h.GidTable, _h.NumGids, _gids));
}
else
{
UInt32 size = _h.NumIDs * 4;
_uids.SetCapacity(size);
UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize;
UInt32 numBlocksBytes = numBlocks << 3;
CByteBuffer data;
data.SetCapacity(numBlocksBytes);
RINOK(inStream->Seek(_h.UidTable, STREAM_SEEK_SET, NULL));
RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes));
for (UInt32 i = 0; i < numBlocks; i++)
{
UInt64 offset = GetUi64(data + i * 8);
UInt32 unpackSize, packSize;
RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize));
if (unpackSize != kMetadataBlockSize)
if (i != numBlocks - 1 || unpackSize != (size & (kMetadataBlockSize - 1)))
return S_FALSE;
}
}
*/
{
const UInt32 alignSize = 1 << 12;
Byte buf[alignSize];
RINOK(inStream->Seek(_h.Size, STREAM_SEEK_SET, NULL));
UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1);
_sizeCalculated = _h.Size;
if (rem != 0)
{
if (ReadStream_FALSE(_stream, buf, rem) == S_OK)
{
size_t i;
for (i = 0; i < rem && buf[i] == 0; i++);
if (i == rem)
_sizeCalculated = _h.Size + rem;
}
}
}
return S_OK;
}
AString CHandler::GetPath(int index) const
{
unsigned len = 0;
int indexMem = index;
bool be = _h.be;
do
{
const CItem &item = _items[index];
index = item.Parent;
const Byte *p = _dirs.Data + item.Ptr;
unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1;
p += _h.GetFileNameOffset();
unsigned i;
for (i = 0; i < size && p[i]; i++);
7zip/CPP/7zip/Archive/SquashfsHandler.cpp view on Meta::CPAN
index = item.Parent;
const Byte *p = _dirs.Data + item.Ptr;
unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1;
p += _h.GetFileNameOffset();
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;
}
STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
{
COM_TRY_BEGIN
{
Close();
_limitedInStreamSpec->SetStream(stream);
HRESULT res;
try
{
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
_openCallback = callback;
res = Open2(stream);
}
catch(...)
{
Close();
throw;
}
if (res != S_OK)
{
Close();
return res;
}
_stream = stream;
}
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::Close()
{
_limitedInStreamSpec->ReleaseStream();
_stream.Release();
_items.Clear();
_nodes.Clear();
_nodesPos.Clear();
_blockToNode.Clear();
_frags.Clear();
_inodesData.Clear();
_dirs.Clear();
// _uids.Free();
// _gids.Free();;
_cachedBlock.Free();
ClearCache();
return S_OK;
}
bool CHandler::GetPackSize(int index, UInt64 &totalPack, bool fillOffsets)
{
totalPack = 0;
const CItem &item = _items[index];
const CNode &node = _nodes[item.Node];
UInt32 ptr = _nodesPos[item.Node];
const Byte *p = _inodesData.Data + ptr;
bool be = _h.be;
UInt32 type = node.Type;
UInt32 offset;
if (node.IsLink() || node.FileSize == 0)
{
totalPack = node.FileSize;
return true;
}
UInt32 numBlocks = (UInt32)node.GetNumBlocks(_h);
if (fillOffsets)
{
_blockOffsets.Clear();
_blockCompressed.Clear();
_blockOffsets.Add(totalPack);
}
if (_h.Major <= 1)
{
offset = 15;
p += offset;
for (UInt32 i = 0; i < numBlocks; i++)
{
UInt32 t = Get16(p + i * 2);
if (fillOffsets)
_blockCompressed.Add((t & kNotCompressedBit16) == 0);
if (t != kNotCompressedBit16)
t &= ~kNotCompressedBit16;
totalPack += t;
if (fillOffsets)
_blockOffsets.Add(totalPack);
}
}
else
{
if (_h.Major <= 2)
offset = 24;
else if (type == kType_FILE)
offset = 32;
else if (type == kType_FILE + 7)
offset = (_h.Major <= 3 ? 40 : 56);
else
return false;
7zip/CPP/7zip/Archive/SquashfsHandler.cpp view on Meta::CPAN
if (GetPackSize(index, size, false))
prop = size;
}
break;
case kpidMTime:
{
UInt32 offset = 0;
switch(_h.Major)
{
case 1:
if (node.Type == kType_FILE)
offset = 3;
else if (node.Type == kType_DIR)
offset = 7;
break;
case 2:
if (node.Type == kType_FILE)
offset = 4;
else if (node.Type == kType_DIR)
offset = 8;
else if (node.Type == kType_DIR + 7)
offset = 9;
break;
case 3: offset = 4; break;
case 4: offset = 8; break;
}
if (offset != 0)
{
const Byte *p = _inodesData.Data + _nodesPos[item.Node] + offset;
FILETIME ft;
NWindows::NTime::UnixTimeToFileTime(Get32(p), ft);
prop = ft;
}
break;
}
case kpidPosixAttrib:
{
if (node.Type != 0 && node.Type < sizeof(k_TypeToMode) / sizeof(k_TypeToMode[0]))
prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type];
break;
}
/*
case kpidUser:
{
UInt32 offset = node.Uid * 4;
if (offset < _uids.GetCapacity())
prop = (UInt32)Get32(_uids + offset);
break;
}
case kpidGroup:
{
if (_h.Major == 4 || node.Gid == _h.GetSpecGuidIndex())
{
UInt32 offset = node.Uid * 4;
if (offset < _uids.GetCapacity())
prop = (UInt32)Get32(_uids + offset);
}
else
{
UInt32 offset = node.Gid * 4;
if (offset < _gids.GetCapacity())
prop = (UInt32)Get32(_gids + offset);
}
break;
}
*/
/*
case kpidLinks:
if (_h.Major >= 3 && node.Type != kType_FILE)
prop = node.NumLinks;
break;
*/
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
class CSquashfsInStream: public CCachedInStream
{
HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
public:
CHandler *Handler;
};
HRESULT CSquashfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
{
return Handler->ReadBlock(blockIndex, dest, blockSize);
}
HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
{
const CNode &node = _nodes[_nodeIndex];
UInt64 blockOffset;
UInt32 packBlockSize;
UInt32 offsetInBlock = 0;
bool compressed;
if (blockIndex < _blockCompressed.Size())
{
compressed = _blockCompressed[(int)blockIndex];
blockOffset = _blockOffsets[(int)blockIndex];
packBlockSize = (UInt32)(_blockOffsets[(int)blockIndex + 1] - blockOffset);
blockOffset += node.StartBlock;
}
else
{
if (!node.ThereAreFrags())
return S_FALSE;
const CFrag &frag = _frags[node.Frag];
offsetInBlock = node.Offset;
blockOffset = frag.StartBlock;
packBlockSize = GET_COMPRESSED_BLOCK_SIZE(frag.Size);
compressed = IS_COMPRESSED_BLOCK(frag.Size);
}
if (packBlockSize == 0)
{
// sparse file ???
memset(dest, 0, blockSize);
return S_OK;
}
( run in 0.484 second using v1.01-cache-2.11-cpan-5735350b133 )