diff --git a/libs/compression/lzokay.cpp b/libs/compression/lzokay.cpp deleted file mode 100644 index 2bccc48..0000000 --- a/libs/compression/lzokay.cpp +++ /dev/null @@ -1,647 +0,0 @@ -#include "lzokay.h" -#include -#include -#include - -/* - * Based on documentation from the Linux sources: Documentation/lzo.txt - * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/lzo.txt - */ - -namespace lzokay { - -#if _WIN32 -#define HOST_BIG_ENDIAN 0 -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define HOST_BIG_ENDIAN 1 -#else -#define HOST_BIG_ENDIAN 0 -#endif - -#if HOST_BIG_ENDIAN -static uint16_t get_le16(const uint8_t* p) { - uint16_t val = *reinterpret_cast(p); -#if __GNUC__ - return __builtin_bswap16(val); -#elif _WIN32 - return _byteswap_ushort(val); -#else - return (val = (val << 8) | ((val >> 8) & 0xFF)); -#endif -} -#else -static uint16_t get_le16(const uint8_t* p) { - return *reinterpret_cast(p); -} -#endif - -constexpr std::size_t Max255Count = std::size_t(~0) / 255 - 2; - -#define NEEDS_IN(count) \ -if (inp + (count) > inp_end) { \ - dst_size = outp - dst; \ - return EResult::InputOverrun; \ -} - -#define NEEDS_OUT(count) \ -if (outp + (count) > outp_end) { \ - dst_size = outp - dst; \ - return EResult::OutputOverrun; \ -} - -#define CONSUME_ZERO_BYTE_LENGTH \ -std::size_t offset; \ -{ \ - const uint8_t *old_inp = inp; \ - while (*inp == 0) ++inp; \ - offset = inp - old_inp; \ - if (offset > Max255Count) { \ - dst_size = outp - dst; \ - return EResult::Error; \ - } \ -} - -#define WRITE_ZERO_BYTE_LENGTH(length) \ -{ \ - std::size_t l; \ - for (l = length; l > 255; l -= 255) { *outp++ = 0; } \ - *outp++ = static_cast(l); \ -} - -constexpr uint32_t M1MaxOffset = 0x0400; -constexpr uint32_t M2MaxOffset = 0x0800; -constexpr uint32_t M3MaxOffset = 0x4000; -// constexpr uint32_t M4MaxOffset = 0xbfff; - -// constexpr uint32_t M1MinLen = 2; -// constexpr uint32_t M1MaxLen = 2; -constexpr uint32_t M2MinLen = 3; -constexpr uint32_t M2MaxLen = 8; -// constexpr uint32_t M3MinLen = 3; -constexpr uint32_t M3MaxLen = 33; -// constexpr uint32_t M4MinLen = 3; -constexpr uint32_t M4MaxLen = 9; - -constexpr uint32_t M1Marker = 0x0; -// constexpr uint32_t M2Marker = 0x40; -constexpr uint32_t M3Marker = 0x20; -constexpr uint32_t M4Marker = 0x10; - -constexpr uint32_t MaxMatchByLengthLen = 34; /* Max M3 len + 1 */ - -EResult decompress(const uint8_t* src, std::size_t src_size, - uint8_t* dst, std::size_t init_dst_size, - std::size_t& dst_size) { - dst_size = init_dst_size; - - if (src_size < 3) { - dst_size = 0; - return EResult::InputOverrun; - } - - const uint8_t* inp = src; - const uint8_t* inp_end = src + src_size; - uint8_t* outp = dst; - uint8_t* outp_end = dst + dst_size; - uint8_t* lbcur; - std::size_t lblen; - std::size_t state = 0; - std::size_t nstate = 0; - - /* First byte encoding */ - if (*inp >= 22) { - /* 22..255 : copy literal string - * length = (byte - 17) = 4..238 - * state = 4 [ don't copy extra literals ] - * skip byte - */ - std::size_t len = *inp++ - uint8_t(17); - NEEDS_IN(len) - NEEDS_OUT(len) - for (std::size_t i = 0; i < len; ++i) - *outp++ = *inp++; - state = 4; - } else if (*inp >= 18) { - /* 18..21 : copy 0..3 literals - * state = (byte - 17) = 0..3 [ copy literals ] - * skip byte - */ - nstate = *inp++ - uint8_t(17); - state = nstate; - NEEDS_IN(nstate) - NEEDS_OUT(nstate) - for (std::size_t i = 0; i < nstate; ++i) - *outp++ = *inp++; - } - /* 0..17 : follow regular instruction encoding, see below. It is worth - * noting that codes 16 and 17 will represent a block copy from - * the dictionary which is empty, and that they will always be - * invalid at this place. - */ - - while (true) { - NEEDS_IN(1) - uint8_t inst = *inp++; - if (inst & 0xC0) { - /* [M2] - * 1 L L D D D S S (128..255) - * Copy 5-8 bytes from block within 2kB distance - * state = S (copy S literals after this block) - * length = 5 + L - * Always followed by exactly one byte : H H H H H H H H - * distance = (H << 3) + D + 1 - * - * 0 1 L D D D S S (64..127) - * Copy 3-4 bytes from block within 2kB distance - * state = S (copy S literals after this block) - * length = 3 + L - * Always followed by exactly one byte : H H H H H H H H - * distance = (H << 3) + D + 1 - */ - NEEDS_IN(1) - lbcur = outp - ((*inp++ << 3) + ((inst >> 2) & 0x7) + 1); - lblen = std::size_t(inst >> 5) + 1; - nstate = inst & uint8_t(0x3); - } else if (inst & M3Marker) { - /* [M3] - * 0 0 1 L L L L L (32..63) - * Copy of small block within 16kB distance (preferably less than 34B) - * length = 2 + (L ?: 31 + (zero_bytes * 255) + non_zero_byte) - * Always followed by exactly one LE16 : D D D D D D D D : D D D D D D S S - * distance = D + 1 - * state = S (copy S literals after this block) - */ - lblen = std::size_t(inst & uint8_t(0x1f)) + 2; - if (lblen == 2) { - CONSUME_ZERO_BYTE_LENGTH - NEEDS_IN(1) - lblen += offset * 255 + 31 + *inp++; - } - NEEDS_IN(2) - nstate = get_le16(inp); - inp += 2; - lbcur = outp - ((nstate >> 2) + 1); - nstate &= 0x3; - } else if (inst & M4Marker) { - /* [M4] - * 0 0 0 1 H L L L (16..31) - * Copy of a block within 16..48kB distance (preferably less than 10B) - * length = 2 + (L ?: 7 + (zero_bytes * 255) + non_zero_byte) - * Always followed by exactly one LE16 : D D D D D D D D : D D D D D D S S - * distance = 16384 + (H << 14) + D - * state = S (copy S literals after this block) - * End of stream is reached if distance == 16384 - */ - lblen = std::size_t(inst & uint8_t(0x7)) + 2; - if (lblen == 2) { - CONSUME_ZERO_BYTE_LENGTH - NEEDS_IN(1) - lblen += offset * 255 + 7 + *inp++; - } - NEEDS_IN(2) - nstate = get_le16(inp); - inp += 2; - lbcur = outp - (((inst & 0x8) << 11) + (nstate >> 2)); - nstate &= 0x3; - if (lbcur == outp) - break; /* Stream finished */ - lbcur -= 16384; - } else { - /* [M1] Depends on the number of literals copied by the last instruction. */ - if (state == 0) { - /* If last instruction did not copy any literal (state == 0), this - * encoding will be a copy of 4 or more literal, and must be interpreted - * like this : - * - * 0 0 0 0 L L L L (0..15) : copy long literal string - * length = 3 + (L ?: 15 + (zero_bytes * 255) + non_zero_byte) - * state = 4 (no extra literals are copied) - */ - std::size_t len = inst + 3; - if (len == 3) { - CONSUME_ZERO_BYTE_LENGTH - NEEDS_IN(1) - len += offset * 255 + 15 + *inp++; - } - /* copy_literal_run */ - NEEDS_IN(len) - NEEDS_OUT(len) - for (std::size_t i = 0; i < len; ++i) - *outp++ = *inp++; - state = 4; - continue; - } else if (state != 4) { - /* If last instruction used to copy between 1 to 3 literals (encoded in - * the instruction's opcode or distance), the instruction is a copy of a - * 2-byte block from the dictionary within a 1kB distance. It is worth - * noting that this instruction provides little savings since it uses 2 - * bytes to encode a copy of 2 other bytes but it encodes the number of - * following literals for free. It must be interpreted like this : - * - * 0 0 0 0 D D S S (0..15) : copy 2 bytes from <= 1kB distance - * length = 2 - * state = S (copy S literals after this block) - * Always followed by exactly one byte : H H H H H H H H - * distance = (H << 2) + D + 1 - */ - NEEDS_IN(1) - nstate = inst & uint8_t(0x3); - lbcur = outp - ((inst >> 2) + (*inp++ << 2) + 1); - lblen = 2; - } else { - /* If last instruction used to copy 4 or more literals (as detected by - * state == 4), the instruction becomes a copy of a 3-byte block from the - * dictionary from a 2..3kB distance, and must be interpreted like this : - * - * 0 0 0 0 D D S S (0..15) : copy 3 bytes from 2..3 kB distance - * length = 3 - * state = S (copy S literals after this block) - * Always followed by exactly one byte : H H H H H H H H - * distance = (H << 2) + D + 2049 - */ - NEEDS_IN(1) - nstate = inst & uint8_t(0x3); - lbcur = outp - ((inst >> 2) + (*inp++ << 2) + 2049); - lblen = 3; - } - } - if (lbcur < dst) { - dst_size = outp - dst; - return EResult::LookbehindOverrun; - } - NEEDS_IN(nstate) - NEEDS_OUT(lblen + nstate) - /* Copy lookbehind */ - for (std::size_t i = 0; i < lblen; ++i) - *outp++ = *lbcur++; - state = nstate; - /* Copy literal */ - for (std::size_t i = 0; i < nstate; ++i) - *outp++ = *inp++; - } - - dst_size = outp - dst; - if (lblen != 3) /* Ensure terminating M4 was encountered */ - return EResult::Error; - if (inp == inp_end) - return EResult::Success; - else if (inp < inp_end) - return EResult::InputNotConsumed; - else - return EResult::InputOverrun; -} - -struct State { - const uint8_t* src; - const uint8_t* src_end; - const uint8_t* inp; - uint32_t wind_sz; - uint32_t wind_b; - uint32_t wind_e; - uint32_t cycle1_countdown; - - const uint8_t* bufp; - uint32_t buf_sz; - - /* Access next input byte and advance both ends of circular buffer */ - void get_byte(uint8_t* buf) { - if (inp >= src_end) { - if (wind_sz > 0) - --wind_sz; - buf[wind_e] = 0; - if (wind_e < DictBase::MaxMatchLen) - buf[DictBase::BufSize + wind_e] = 0; - } else { - buf[wind_e] = *inp; - if (wind_e < DictBase::MaxMatchLen) - buf[DictBase::BufSize + wind_e] = *inp; - ++inp; - } - if (++wind_e == DictBase::BufSize) - wind_e = 0; - if (++wind_b == DictBase::BufSize) - wind_b = 0; - } - - uint32_t pos2off(uint32_t pos) const { - return wind_b > pos ? wind_b - pos : DictBase::BufSize - (pos - wind_b); - } -}; - -class DictImpl : public DictBase { -public: - struct Match3Impl : DictBase::Match3 { - static uint32_t make_key(const uint8_t* data) { - return ((0x9f5f * (((uint32_t(data[0]) << 5 ^ uint32_t(data[1])) << 5) ^ data[2])) >> 5) & 0x3fff; - } - - uint16_t get_head(uint32_t key) const { - return (chain_sz[key] == 0) ? uint16_t(UINT16_MAX) : head[key]; - } - - void init() { - std::fill(std::begin(chain_sz), std::end(chain_sz), 0); - } - - void remove(uint32_t pos, const uint8_t* b) { - --chain_sz[make_key(b + pos)]; - } - - void advance(State& s, uint32_t& match_pos, uint32_t& match_count, const uint8_t* b) { - uint32_t key = make_key(b + s.wind_b); - match_pos = chain[s.wind_b] = get_head(key); - match_count = chain_sz[key]++; - if (match_count > DictBase::MaxMatchLen) - match_count = DictBase::MaxMatchLen; - head[key] = uint16_t(s.wind_b); - } - - void skip_advance(State& s, const uint8_t* b) { - uint32_t key = make_key(b + s.wind_b); - chain[s.wind_b] = get_head(key); - head[key] = uint16_t(s.wind_b); - best_len[s.wind_b] = uint16_t(DictBase::MaxMatchLen + 1); - chain_sz[key]++; - } - }; - - struct Match2Impl : DictBase::Match2 { - static uint32_t make_key(const uint8_t* data) { - return uint32_t(data[0]) ^ (uint32_t(data[1]) << 8); - } - - void init() { - std::fill(std::begin(head), std::end(head), UINT16_MAX); - } - - void add(uint16_t pos, const uint8_t* b) { - head[make_key(b + pos)] = pos; - } - - void remove(uint32_t pos, const uint8_t* b) { - uint16_t& p = head[make_key(b + pos)]; - if (p == pos) - p = UINT16_MAX; - } - - bool search(State& s, uint32_t& lb_pos, uint32_t& lb_len, - uint32_t best_pos[MaxMatchByLengthLen], const uint8_t* b) const { - uint16_t pos = head[make_key(b + s.wind_b)]; - if (pos == UINT16_MAX) - return false; - if (best_pos[2] == 0) - best_pos[2] = pos + 1; - if (lb_len < 2) { - lb_len = 2; - lb_pos = pos; - } - return true; - } - }; - - void init(State& s, const uint8_t* src, std::size_t src_size) { - auto& match3 = static_cast(_storage->match3); - auto& match2 = static_cast(_storage->match2); - - s.cycle1_countdown = DictBase::MaxDist; - match3.init(); - match2.init(); - - s.src = src; - s.src_end = src + src_size; - s.inp = src; - s.wind_sz = uint32_t(std::min(src_size, std::size_t(MaxMatchLen))); - s.wind_b = 0; - s.wind_e = s.wind_sz; - std::copy_n(s.inp, s.wind_sz, _storage->buffer); - s.inp += s.wind_sz; - - if (s.wind_e == DictBase::BufSize) - s.wind_e = 0; - - if (s.wind_sz < 3) - std::fill_n(_storage->buffer + s.wind_b + s.wind_sz, 3, 0); - } - - void reset_next_input_entry(State& s, Match3Impl& match3, Match2Impl& match2) { - /* Remove match from about-to-be-clobbered buffer entry */ - if (s.cycle1_countdown == 0) { - match3.remove(s.wind_e, _storage->buffer); - match2.remove(s.wind_e, _storage->buffer); - } else { - --s.cycle1_countdown; - } - } - - void advance(State& s, uint32_t& lb_off, uint32_t& lb_len, - uint32_t best_off[MaxMatchByLengthLen], bool skip) { - auto& match3 = static_cast(_storage->match3); - auto& match2 = static_cast(_storage->match2); - - if (skip) { - for (uint32_t i = 0; i < lb_len - 1; ++i) { - reset_next_input_entry(s, match3, match2); - match3.skip_advance(s, _storage->buffer); - match2.add(uint16_t(s.wind_b), _storage->buffer); - s.get_byte(_storage->buffer); - } - } - - lb_len = 1; - lb_off = 0; - uint32_t lb_pos; - - uint32_t best_pos[MaxMatchByLengthLen] = {}; - uint32_t match_pos, match_count; - match3.advance(s, match_pos, match_count, _storage->buffer); - - int best_char = _storage->buffer[s.wind_b]; - uint32_t best_len = lb_len; - if (lb_len >= s.wind_sz) { - if (s.wind_sz == 0) - best_char = -1; - lb_off = 0; - match3.best_len[s.wind_b] = DictBase::MaxMatchLen + 1; - } else { - if (match2.search(s, lb_pos, lb_len, best_pos, _storage->buffer) && s.wind_sz >= 3) { - for (uint32_t i = 0; i < match_count; ++i, match_pos = match3.chain[match_pos]) { - auto ref_ptr = _storage->buffer + s.wind_b; - auto match_ptr = _storage->buffer + match_pos; - auto mismatch = std::mismatch(ref_ptr, ref_ptr + s.wind_sz, match_ptr); - auto match_len = uint32_t(mismatch.first - ref_ptr); - if (match_len < 2) - continue; - if (match_len < MaxMatchByLengthLen && best_pos[match_len] == 0) - best_pos[match_len] = match_pos + 1; - if (match_len > lb_len) { - lb_len = match_len; - lb_pos = match_pos; - if (match_len == s.wind_sz || match_len > match3.best_len[match_pos]) - break; - } - } - } - if (lb_len > best_len) - lb_off = s.pos2off(lb_pos); - match3.best_len[s.wind_b] = uint16_t(lb_len); - for (auto posit = std::begin(best_pos) + 2, offit = best_off + 2; - posit != std::end(best_pos); ++posit, ++offit) { - *offit = (*posit > 0) ? s.pos2off(*posit - 1) : 0; - } - } - - reset_next_input_entry(s, match3, match2); - - match2.add(uint16_t(s.wind_b), _storage->buffer); - - s.get_byte(_storage->buffer); - - if (best_char < 0) { - s.buf_sz = 0; - lb_len = 0; - /* Signal exit */ - } else { - s.buf_sz = s.wind_sz + 1; - } - s.bufp = s.inp - s.buf_sz; - } -}; - -static void find_better_match(const uint32_t best_off[MaxMatchByLengthLen], uint32_t& lb_len, uint32_t& lb_off) { - if (lb_len <= M2MinLen || lb_off <= M2MaxOffset) - return; - if (lb_off > M2MaxOffset && lb_len >= M2MinLen + 1 && lb_len <= M2MaxLen + 1 && - best_off[lb_len - 1] != 0 && best_off[lb_len - 1] <= M2MaxOffset) { - lb_len -= 1; - lb_off = best_off[lb_len]; - } else if (lb_off > M3MaxOffset && lb_len >= M4MaxLen + 1 && lb_len <= M2MaxLen + 2 && - best_off[lb_len - 2] && best_off[lb_len] <= M2MaxOffset) { - lb_len -= 2; - lb_off = best_off[lb_len]; - } else if (lb_off > M3MaxOffset && lb_len >= M4MaxLen + 1 && lb_len <= M3MaxLen + 1 && - best_off[lb_len - 1] != 0 && best_off[lb_len - 2] <= M3MaxOffset) { - lb_len -= 1; - lb_off = best_off[lb_len]; - } -} - -static EResult encode_literal_run(uint8_t*& outp, const uint8_t* outp_end, const uint8_t* dst, std::size_t& dst_size, - const uint8_t* lit_ptr, uint32_t lit_len) { - if (outp == dst && lit_len <= 238) { - NEEDS_OUT(1); - *outp++ = uint8_t(17 + lit_len); - } else if (lit_len <= 3) { - outp[-2] = uint8_t(outp[-2] | lit_len); - } else if (lit_len <= 18) { - NEEDS_OUT(1); - *outp++ = uint8_t(lit_len - 3); - } else { - NEEDS_OUT((lit_len - 18) / 255 + 2); - *outp++ = 0; - WRITE_ZERO_BYTE_LENGTH(lit_len - 18); - } - NEEDS_OUT(lit_len); - outp = std::copy_n(lit_ptr, lit_len, outp); - return EResult::Success; -} - -static EResult encode_lookback_match(uint8_t*& outp, const uint8_t* outp_end, const uint8_t* dst, std::size_t& dst_size, - uint32_t lb_len, uint32_t lb_off, uint32_t last_lit_len) { - if (lb_len == 2) { - lb_off -= 1; - NEEDS_OUT(2); - *outp++ = uint8_t(M1Marker | ((lb_off & 0x3) << 2)); - *outp++ = uint8_t(lb_off >> 2); - } else if (lb_len <= M2MaxLen && lb_off <= M2MaxOffset) { - lb_off -= 1; - NEEDS_OUT(2); - *outp++ = uint8_t((lb_len - 1) << 5 | ((lb_off & 0x7) << 2)); - *outp++ = uint8_t(lb_off >> 3); - } else if (lb_len == M2MinLen && lb_off <= M1MaxOffset + M2MaxOffset && last_lit_len >= 4) { - lb_off -= 1 + M2MaxOffset; - NEEDS_OUT(2); - *outp++ = uint8_t(M1Marker | ((lb_off & 0x3) << 2)); - *outp++ = uint8_t(lb_off >> 2); - } else if (lb_off <= M3MaxOffset) { - lb_off -= 1; - if (lb_len <= M3MaxLen) { - NEEDS_OUT(1); - *outp++ = uint8_t(M3Marker | (lb_len - 2)); - } else { - lb_len -= M3MaxLen; - NEEDS_OUT(lb_len / 255 + 2); - *outp++ = uint8_t(M3Marker); - WRITE_ZERO_BYTE_LENGTH(lb_len); - } - NEEDS_OUT(2); - *outp++ = uint8_t(lb_off << 2); - *outp++ = uint8_t(lb_off >> 6); - } else { - lb_off -= 0x4000; - if (lb_len <= M4MaxLen) { - NEEDS_OUT(1); - *outp++ = uint8_t(M4Marker | ((lb_off & 0x4000) >> 11) | (lb_len - 2)); - } else { - lb_len -= M4MaxLen; - NEEDS_OUT(lb_len / 255 + 2); - *outp++ = uint8_t(M4Marker | ((lb_off & 0x4000) >> 11)); - WRITE_ZERO_BYTE_LENGTH(lb_len); - } - NEEDS_OUT(2); - *outp++ = uint8_t(lb_off << 2); - *outp++ = uint8_t(lb_off >> 6); - } - return EResult::Success; -} - -EResult compress(const uint8_t* src, std::size_t src_size, - uint8_t* dst, std::size_t init_dst_size, - std::size_t& dst_size, DictBase& dict) { - EResult err; - State s; - auto& d = static_cast(dict); - dst_size = init_dst_size; - uint8_t* outp = dst; - uint8_t* outp_end = dst + dst_size; - uint32_t lit_len = 0; - uint32_t lb_off, lb_len; - uint32_t best_off[MaxMatchByLengthLen]; - d.init(s, src, src_size); - const uint8_t* lit_ptr = s.inp; - d.advance(s, lb_off, lb_len, best_off, false); - while (s.buf_sz > 0) { - if (lit_len == 0) - lit_ptr = s.bufp; - if (lb_len < 2 || (lb_len == 2 && (lb_off > M1MaxOffset || lit_len == 0 || lit_len >= 4)) || - (lb_len == 2 && outp == dst) || (outp == dst && lit_len == 0)) { - lb_len = 0; - } else if (lb_len == M2MinLen && lb_off > M1MaxOffset + M2MaxOffset && lit_len >= 4) { - lb_len = 0; - } - if (lb_len == 0) { - ++lit_len; - d.advance(s, lb_off, lb_len, best_off, false); - continue; - } - find_better_match(best_off, lb_len, lb_off); - if ((err = encode_literal_run(outp, outp_end, dst, dst_size, lit_ptr, lit_len)) < EResult::Success) - return err; - if ((err = encode_lookback_match(outp, outp_end, dst, dst_size, lb_len, lb_off, lit_len)) < EResult::Success) - return err; - lit_len = 0; - d.advance(s, lb_off, lb_len, best_off, true); - } - if ((err = encode_literal_run(outp, outp_end, dst, dst_size, lit_ptr, lit_len)) < EResult::Success) - return err; - - /* Terminating M4 */ - NEEDS_OUT(3); - *outp++ = M4Marker | 1; - *outp++ = 0; - *outp++ = 0; - - dst_size = outp - dst; - return EResult::Success; -} - -} diff --git a/libs/compression/lzokay.h b/libs/compression/lzokay.h deleted file mode 100644 index 522edd8..0000000 --- a/libs/compression/lzokay.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once -#include -#include -#include - -namespace lzokay { - -enum class EResult { - LookbehindOverrun = -4, - OutputOverrun = -3, - InputOverrun = -2, - Error = -1, - Success = 0, - InputNotConsumed = 1, -}; - -class DictBase { -protected: - static constexpr uint32_t HashSize = 0x4000; - static constexpr uint32_t MaxDist = 0xbfff; - static constexpr uint32_t MaxMatchLen = 0x800; - static constexpr uint32_t BufSize = MaxDist + MaxMatchLen; - - /* List encoding of previous 3-byte data matches */ - struct Match3 { - uint16_t head[HashSize]; /* key -> chain-head-pos */ - uint16_t chain_sz[HashSize]; /* key -> chain-size */ - uint16_t chain[BufSize]; /* chain-pos -> next-chain-pos */ - uint16_t best_len[BufSize]; /* chain-pos -> best-match-length */ - }; - /* Encoding of 2-byte data matches */ - struct Match2 { - uint16_t head[1 << 16]; /* 2-byte-data -> head-pos */ - }; - - struct Data { - Match3 match3; - Match2 match2; - - /* Circular buffer caching enough data to access the maximum lookback - * distance of 48K + maximum match length of 2K. An additional 2K is - * allocated so the start of the buffer may be replicated at the end, - * therefore providing efficient circular access. - */ - uint8_t buffer[BufSize + MaxMatchLen]; - }; - using storage_type = Data; - storage_type* _storage; - DictBase() = default; - friend struct State; - friend EResult compress(const uint8_t* src, std::size_t src_size, - uint8_t* dst, std::size_t& dst_size, DictBase& dict); -}; -template class _Alloc = std::allocator> -class Dict : public DictBase { - _Alloc _allocator; -public: - Dict() { _storage = _allocator.allocate(1); } - ~Dict() { _allocator.deallocate(_storage, 1); } -}; - -EResult decompress(const uint8_t* src, std::size_t src_size, - uint8_t* dst, std::size_t dst_size, - std::size_t& out_size); -EResult compress(const uint8_t* src, std::size_t src_size, - uint8_t* dst, std::size_t dst_size, - std::size_t& out_size, DictBase& dict); -inline EResult compress(const uint8_t* src, std::size_t src_size, - uint8_t* dst, std::size_t dst_size, - std::size_t& out_size) { - Dict<> dict; - return compress(src, src_size, dst, dst_size, out_size, dict); -} - -constexpr std::size_t compress_worst_size(std::size_t s) { - return s + s / 16 + 64 + 3; -} - -}