mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-08 06:06:59 -06:00
162 lines
3.8 KiB
C
162 lines
3.8 KiB
C
/*
|
|
* Bitwise range encoder by Igor Pavlov
|
|
* Modified by Conor McCarthy
|
|
*
|
|
* Public domain
|
|
*/
|
|
|
|
#ifndef RANGE_ENCODER_H
|
|
#define RANGE_ENCODER_H
|
|
|
|
#include "mem.h"
|
|
#include "compiler.h"
|
|
|
|
#if defined (__cplusplus)
|
|
extern "C" {
|
|
#endif
|
|
|
|
#ifdef LZMA_ENC_PROB32
|
|
typedef U32 LZMA2_prob;
|
|
#else
|
|
typedef U16 LZMA2_prob;
|
|
#endif
|
|
|
|
#define kNumTopBits 24U
|
|
#define kTopValue (1UL << kNumTopBits)
|
|
#define kNumBitModelTotalBits 11U
|
|
#define kBitModelTotal (1 << kNumBitModelTotalBits)
|
|
#define kNumMoveBits 5U
|
|
#define kProbInitValue (kBitModelTotal >> 1U)
|
|
#define kNumMoveReducingBits 4U
|
|
#define kNumBitPriceShiftBits 5U
|
|
#define kPriceTableSize (kBitModelTotal >> kNumMoveReducingBits)
|
|
|
|
extern BYTE price_table[2][kPriceTableSize];
|
|
#if 0
|
|
void RC_printPriceTable();
|
|
#endif
|
|
|
|
typedef struct
|
|
{
|
|
BYTE *out_buffer;
|
|
size_t out_index;
|
|
U64 cache_size;
|
|
U64 low;
|
|
U32 range;
|
|
BYTE cache;
|
|
} RC_encoder;
|
|
|
|
void RC_reset(RC_encoder* const rc);
|
|
|
|
void RC_setOutputBuffer(RC_encoder* const rc, BYTE *const out_buffer);
|
|
|
|
void FORCE_NOINLINE RC_shiftLow(RC_encoder* const rc);
|
|
|
|
void RC_encodeBitTree(RC_encoder* const rc, LZMA2_prob *const probs, unsigned bit_count, unsigned symbol);
|
|
|
|
void RC_encodeBitTreeReverse(RC_encoder* const rc, LZMA2_prob *const probs, unsigned bit_count, unsigned symbol);
|
|
|
|
void FORCE_NOINLINE RC_encodeDirect(RC_encoder* const rc, unsigned value, unsigned bit_count);
|
|
|
|
HINT_INLINE
|
|
void RC_encodeBit0(RC_encoder* const rc, LZMA2_prob *const rprob)
|
|
{
|
|
unsigned prob = *rprob;
|
|
rc->range = (rc->range >> kNumBitModelTotalBits) * prob;
|
|
prob += (kBitModelTotal - prob) >> kNumMoveBits;
|
|
*rprob = (LZMA2_prob)prob;
|
|
if (rc->range < kTopValue) {
|
|
rc->range <<= 8;
|
|
RC_shiftLow(rc);
|
|
}
|
|
}
|
|
|
|
HINT_INLINE
|
|
void RC_encodeBit1(RC_encoder* const rc, LZMA2_prob *const rprob)
|
|
{
|
|
unsigned prob = *rprob;
|
|
U32 new_bound = (rc->range >> kNumBitModelTotalBits) * prob;
|
|
rc->low += new_bound;
|
|
rc->range -= new_bound;
|
|
prob -= prob >> kNumMoveBits;
|
|
*rprob = (LZMA2_prob)prob;
|
|
if (rc->range < kTopValue) {
|
|
rc->range <<= 8;
|
|
RC_shiftLow(rc);
|
|
}
|
|
}
|
|
|
|
HINT_INLINE
|
|
void RC_encodeBit(RC_encoder* const rc, LZMA2_prob *const rprob, unsigned const bit)
|
|
{
|
|
unsigned prob = *rprob;
|
|
if (bit != 0) {
|
|
U32 const new_bound = (rc->range >> kNumBitModelTotalBits) * prob;
|
|
rc->low += new_bound;
|
|
rc->range -= new_bound;
|
|
prob -= prob >> kNumMoveBits;
|
|
}
|
|
else {
|
|
rc->range = (rc->range >> kNumBitModelTotalBits) * prob;
|
|
prob += (kBitModelTotal - prob) >> kNumMoveBits;
|
|
}
|
|
*rprob = (LZMA2_prob)prob;
|
|
if (rc->range < kTopValue) {
|
|
rc->range <<= 8;
|
|
RC_shiftLow(rc);
|
|
}
|
|
}
|
|
|
|
#define GET_PRICE(prob, symbol) \
|
|
price_table[symbol][(prob) >> kNumMoveReducingBits]
|
|
|
|
#define GET_PRICE_0(prob) price_table[0][(prob) >> kNumMoveReducingBits]
|
|
|
|
#define GET_PRICE_1(prob) price_table[1][(prob) >> kNumMoveReducingBits]
|
|
|
|
#define kMinLitPrice 8U
|
|
|
|
HINT_INLINE
|
|
unsigned RC_getTreePrice(const LZMA2_prob* const prob_table, unsigned bit_count, size_t symbol)
|
|
{
|
|
unsigned price = 0;
|
|
symbol |= ((size_t)1 << bit_count);
|
|
do {
|
|
size_t const next_symbol = symbol >> 1;
|
|
unsigned prob = prob_table[next_symbol];
|
|
size_t bit = symbol & 1;
|
|
price += GET_PRICE(prob, bit);
|
|
symbol = next_symbol;
|
|
} while (symbol != 1);
|
|
return price;
|
|
}
|
|
|
|
HINT_INLINE
|
|
unsigned RC_getReverseTreePrice(const LZMA2_prob* const prob_table, unsigned bit_count, size_t symbol)
|
|
{
|
|
unsigned prob = prob_table[1];
|
|
size_t bit = symbol & 1;
|
|
unsigned price = GET_PRICE(prob, bit);
|
|
size_t m = 1;
|
|
while (--bit_count != 0) {
|
|
m = (m << 1) | bit;
|
|
symbol >>= 1;
|
|
prob = prob_table[m];
|
|
bit = symbol & 1;
|
|
price += GET_PRICE(prob, bit);
|
|
}
|
|
return price;
|
|
}
|
|
|
|
HINT_INLINE
|
|
void RC_flush(RC_encoder* const rc)
|
|
{
|
|
for (int i = 0; i < 5; ++i)
|
|
RC_shiftLow(rc);
|
|
}
|
|
|
|
#if defined (__cplusplus)
|
|
}
|
|
#endif
|
|
|
|
#endif /* RANGE_ENCODER_H */ |