/* Calculates size of the part after the header and tree of an LZ77 block, in bits. */ static size_t CalculateBlockSymbolSize(const unsigned* ll_lengths, const unsigned* d_lengths, const unsigned short* litlens, const unsigned short* dists, size_t lstart, size_t lend) { size_t result = 0; size_t i; for (i = lstart; i < lend; i++) { if (dists[i] == 0) { result += ll_lengths[litlens[i]]; } else { result += ll_lengths[ZopfliGetLengthSymbol(litlens[i])]; result += d_lengths[ZopfliGetDistSymbol(dists[i])]; result += ZopfliGetLengthExtraBits(litlens[i]); result += ZopfliGetDistExtraBits(dists[i]); } } result += ll_lengths[256]; /*end symbol*/ return result; }
/* Calculates size of the part after the header and tree of an LZ77 block, in bits. */ static size_t CalculateBlockSymbolSize(const unsigned* ll_lengths, const unsigned* d_lengths, const ZopfliLZ77Store* lz77, size_t lstart, size_t lend) { size_t result = 0; size_t i; if (lstart + ZOPFLI_NUM_LL * 3 > lend) { for (i = lstart; i < lend; i++) { assert(i < lz77->size); assert(lz77->litlens[i] < 259); if (lz77->dists[i] == 0) { result += ll_lengths[lz77->litlens[i]]; } else { int ll_symbol = ZopfliGetLengthSymbol(lz77->litlens[i]); int d_symbol = ZopfliGetDistSymbol(lz77->dists[i]); result += ll_lengths[ll_symbol]; result += d_lengths[d_symbol]; result += ZopfliGetLengthSymbolExtraBits(ll_symbol); result += ZopfliGetDistSymbolExtraBits(d_symbol); } } } else { size_t ll_counts[ZOPFLI_NUM_LL]; size_t d_counts[ZOPFLI_NUM_D]; ZopfliLZ77GetHistogram(lz77, lstart, lend, ll_counts, d_counts); for (i = 0; i < 256; i++) { result += ll_lengths[i] * ll_counts[i]; } for (i = 257; i < 286; i++) { result += ll_lengths[i] * ll_counts[i]; result += ZopfliGetLengthSymbolExtraBits(i) * ll_counts[i]; } for (i = 0; i < 30; i++) { result += d_lengths[i] * d_counts[i]; result += ZopfliGetDistSymbolExtraBits(i) * d_counts[i]; } } result += ll_lengths[256]; /*end symbol*/ return result; }
/* Adds all lit/len and dist codes from the lists as huffman symbols. Does not add end code 256. expected_data_size is the uncompressed block size, used for assert, but you can set it to 0 to not do the assertion. */ static void AddLZ77Data(const unsigned short* litlens, const unsigned short* dists, size_t lstart, size_t lend, size_t expected_data_size, const unsigned* ll_symbols, const unsigned* ll_lengths, const unsigned* d_symbols, const unsigned* d_lengths, unsigned char* bp, unsigned char** out, size_t* outsize) { size_t testlength = 0; size_t i; for (i = lstart; i < lend; i++) { unsigned dist = dists[i]; unsigned litlen = litlens[i]; if (dist == 0) { assert(litlen < 256); assert(ll_lengths[litlen] > 0); AddHuffmanBits(ll_symbols[litlen], ll_lengths[litlen], bp, out, outsize); testlength++; } else { unsigned lls = ZopfliGetLengthSymbol(litlen); unsigned ds = ZopfliGetDistSymbol(dist); assert(litlen >= 3 && litlen <= 288); assert(ll_lengths[lls] > 0); assert(d_lengths[ds] > 0); AddHuffmanBits(ll_symbols[lls], ll_lengths[lls], bp, out, outsize); AddBits(ZopfliGetLengthExtraBitsValue(litlen), ZopfliGetLengthExtraBits(litlen), bp, out, outsize); AddHuffmanBits(d_symbols[ds], d_lengths[ds], bp, out, outsize); AddBits(ZopfliGetDistExtraBitsValue(dist), ZopfliGetDistExtraBits(dist), bp, out, outsize); testlength += litlen; } } assert(expected_data_size == 0 || testlength == expected_data_size); }
/* Same as CalculateBlockSymbolSize, but for block size smaller than histogram size. */ static size_t CalculateBlockSymbolSizeSmall(const unsigned* ll_lengths, const unsigned* d_lengths, const ZopfliLZ77Store* lz77, size_t lstart, size_t lend) { size_t result = 0; size_t i; for (i = lstart; i < lend; i++) { assert(i < lz77->size); assert(lz77->litlens[i] < 259); if (lz77->dists[i] == 0) { result += ll_lengths[lz77->litlens[i]]; } else { int ll_symbol = ZopfliGetLengthSymbol(lz77->litlens[i]); int d_symbol = ZopfliGetDistSymbol(lz77->dists[i]); result += ll_lengths[ll_symbol]; result += d_lengths[d_symbol]; result += ZopfliGetLengthSymbolExtraBits(ll_symbol); result += ZopfliGetDistSymbolExtraBits(d_symbol); } } result += ll_lengths[256]; /*end symbol*/ return result; }
void ZopfliLZ77Counts(const unsigned short* litlens, const unsigned short* dists, size_t start, size_t end, size_t* ll_count, size_t* d_count) { size_t i; for (i = 0; i < 288; i++) { ll_count[i] = 0; } for (i = 0; i < 32; i++) { d_count[i] = 0; } for (i = start; i < end; i++) { if (dists[i] == 0) { ll_count[litlens[i]]++; } else { ll_count[ZopfliGetLengthSymbol(litlens[i])]++; d_count[ZopfliGetDistSymbol(dists[i])]++; } } ll_count[256] = 1; /* End symbol. */ }