2012-02-22 11:12:15 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#ifndef SeekableZStream_h
|
|
|
|
#define SeekableZStream_h
|
|
|
|
|
|
|
|
#include "Zip.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Seekable compressed stream are created by splitting the original
|
|
|
|
* decompressed data in small chunks and compress these chunks
|
|
|
|
* individually.
|
|
|
|
*
|
|
|
|
* The seekable compressed file format consists in a header defined below,
|
|
|
|
* followed by a table of 32-bits words containing the offsets for each
|
|
|
|
* individual compressed chunk, then followed by the compressed chunks.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma pack(1)
|
|
|
|
struct SeekableZStreamHeader: public Zip::SignedEntity<SeekableZStreamHeader>
|
|
|
|
{
|
|
|
|
SeekableZStreamHeader()
|
|
|
|
: Zip::SignedEntity<SeekableZStreamHeader>(magic)
|
2013-03-06 10:30:07 +04:00
|
|
|
, totalSize(0), chunkSize(0), dictSize(0), nChunks(0), lastChunkSize(0)
|
|
|
|
, windowBits(0), filter(0) { }
|
2012-02-22 11:12:15 +04:00
|
|
|
|
|
|
|
/* Reuse Zip::SignedEntity to handle the magic number used in the Seekable
|
|
|
|
* ZStream file format. The magic number is "SeZz". */
|
|
|
|
static const uint32_t magic = 0x7a5a6553;
|
|
|
|
|
|
|
|
/* Total size of the stream, including the 4 magic bytes. */
|
|
|
|
le_uint32 totalSize;
|
|
|
|
|
|
|
|
/* Chunk size */
|
2013-03-06 10:30:07 +04:00
|
|
|
le_uint16 chunkSize;
|
|
|
|
|
|
|
|
/* Size of the dictionary */
|
|
|
|
le_uint16 dictSize;
|
2012-02-22 11:12:15 +04:00
|
|
|
|
|
|
|
/* Number of chunks */
|
|
|
|
le_uint32 nChunks;
|
|
|
|
|
|
|
|
/* Size of last chunk (> 0, <= Chunk size) */
|
2013-03-06 10:29:41 +04:00
|
|
|
le_uint16 lastChunkSize;
|
|
|
|
|
|
|
|
/* windowBits value used when deflating */
|
|
|
|
signed char windowBits;
|
|
|
|
|
2013-03-06 10:29:59 +04:00
|
|
|
/* Filter Id */
|
|
|
|
unsigned char filter;
|
2012-02-22 11:12:15 +04:00
|
|
|
};
|
|
|
|
#pragma pack()
|
|
|
|
|
2013-07-18 21:59:53 +04:00
|
|
|
static_assert(sizeof(SeekableZStreamHeader) == 5 * 4,
|
|
|
|
"SeekableZStreamHeader should be 5 32-bits words");
|
2012-02-22 11:12:15 +04:00
|
|
|
|
2012-02-22 11:12:15 +04:00
|
|
|
/**
|
|
|
|
* Helper class used to decompress Seekable ZStreams.
|
|
|
|
*/
|
|
|
|
class SeekableZStream {
|
|
|
|
public:
|
|
|
|
/* Initialize from the given buffer. Returns whether initialization
|
|
|
|
* succeeded (true) or failed (false). */
|
2013-03-06 10:29:05 +04:00
|
|
|
bool Init(const void *buf, size_t length);
|
2012-02-22 11:12:15 +04:00
|
|
|
|
|
|
|
/* Decompresses starting from the given chunk. The decompressed data is
|
|
|
|
* stored at the given location. The given length, in bytes, indicates
|
|
|
|
* how much data to decompress. If length is 0, then exactly one chunk
|
|
|
|
* is decompressed.
|
|
|
|
* Returns whether decompression succeeded (true) or failed (false). */
|
|
|
|
bool Decompress(void *where, size_t chunk, size_t length = 0);
|
|
|
|
|
|
|
|
/* Decompresses the given chunk at the given address. If a length is given,
|
|
|
|
* only decompresses that amount of data instead of the entire chunk.
|
|
|
|
* Returns whether decompression succeeded (true) or failed (false). */
|
|
|
|
bool DecompressChunk(void *where, size_t chunk, size_t length = 0);
|
|
|
|
|
|
|
|
/* Returns the uncompressed size of the complete zstream */
|
2016-01-06 04:08:45 +03:00
|
|
|
size_t GetUncompressedSize() const
|
2012-02-22 11:12:15 +04:00
|
|
|
{
|
|
|
|
return (offsetTable.numElements() - 1) * chunkSize + lastChunkSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns the chunk size of the given chunk */
|
2016-01-06 04:08:45 +03:00
|
|
|
size_t GetChunkSize(size_t chunk = 0) const {
|
2012-02-22 11:12:15 +04:00
|
|
|
return (chunk == offsetTable.numElements() - 1) ? lastChunkSize : chunkSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns the number of chunks */
|
2016-01-06 04:08:45 +03:00
|
|
|
size_t GetChunksNum() const {
|
2012-02-22 11:12:15 +04:00
|
|
|
return offsetTable.numElements();
|
|
|
|
}
|
|
|
|
|
2013-03-06 10:29:59 +04:00
|
|
|
/**
|
|
|
|
* Filters used to improve compression rate.
|
|
|
|
*/
|
|
|
|
enum FilterDirection {
|
|
|
|
FILTER,
|
|
|
|
UNFILTER
|
|
|
|
};
|
|
|
|
typedef void (*ZStreamFilter)(off_t, FilterDirection,
|
|
|
|
unsigned char *, size_t);
|
|
|
|
|
|
|
|
enum FilterId {
|
|
|
|
NONE,
|
|
|
|
BCJ_THUMB,
|
|
|
|
BCJ_ARM,
|
2013-03-08 12:32:56 +04:00
|
|
|
BCJ_X86,
|
2013-03-06 10:29:59 +04:00
|
|
|
FILTER_MAX
|
|
|
|
};
|
|
|
|
static ZStreamFilter GetFilter(FilterId id);
|
|
|
|
|
|
|
|
static ZStreamFilter GetFilter(uint16_t id) {
|
|
|
|
return GetFilter(static_cast<FilterId>(id));
|
|
|
|
}
|
|
|
|
|
2012-02-22 11:12:15 +04:00
|
|
|
private:
|
|
|
|
/* RAW Seekable SZtream buffer */
|
|
|
|
const unsigned char *buffer;
|
|
|
|
|
|
|
|
/* Total size of the stream, including the 4 magic bytes. */
|
|
|
|
uint32_t totalSize;
|
|
|
|
|
|
|
|
/* Chunk size */
|
|
|
|
uint32_t chunkSize;
|
|
|
|
|
|
|
|
/* Size of last chunk (> 0, <= Chunk size) */
|
|
|
|
uint32_t lastChunkSize;
|
|
|
|
|
2013-03-06 10:29:41 +04:00
|
|
|
/* windowBits value used when deflating */
|
|
|
|
int windowBits;
|
|
|
|
|
2012-02-22 11:12:15 +04:00
|
|
|
/* Offsets table */
|
|
|
|
Array<le_uint32> offsetTable;
|
2013-03-06 10:29:59 +04:00
|
|
|
|
|
|
|
/* Filter */
|
|
|
|
ZStreamFilter filter;
|
2013-03-06 10:30:07 +04:00
|
|
|
|
|
|
|
/* Deflate dictionary */
|
|
|
|
Array<unsigned char> dictionary;
|
2015-02-10 10:04:37 +03:00
|
|
|
|
|
|
|
/* Special allocator for inflate to use the same buffers for every chunk */
|
|
|
|
zxx_stream::StaticAllocator allocator;
|
2012-02-22 11:12:15 +04:00
|
|
|
};
|
|
|
|
|
2013-03-13 18:28:57 +04:00
|
|
|
inline void
|
|
|
|
operator++(SeekableZStream::FilterId &other)
|
|
|
|
{
|
|
|
|
const int orig = static_cast<int>(other);
|
|
|
|
other = static_cast<SeekableZStream::FilterId>(orig + 1);
|
|
|
|
}
|
|
|
|
|
2012-02-22 11:12:15 +04:00
|
|
|
#endif /* SeekableZStream_h */
|