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 )