home *** CD-ROM | disk | FTP | other *** search
- #include "arith.h"
- #include "files.h"
-
-
- /*
- Declare variables use for arithmetic compression
- */
-
- static int under_flow_count = 0;
- static unsigned int low = 0;
- static unsigned int range = MAX_RANGE;
- static unsigned int value = 0;
-
- static unsigned int code_value = 0;
- static unsigned int code_bit_count = 0;
- static unsigned codesize = 0;
-
-
- static int shift_count (unsigned);
-
- static void put_bit (int);
- static void put_bit_string (unsigned, int);
- static void clear_under_flow (unsigned);
-
- static unsigned get_bit_string (int);
- static unsigned get_bit (void);
-
-
-
- /*
- Initialize arithmetic coder at start of any compress/expand procedure
- */
-
- void InitCoder (void)
-
- {
- low = 0;
- range = MAX_RANGE;
- }
-
-
-
- /*
- Terminate arithmetic code operation
- Write bit string whose value is within active code range
- Force final byte to be output to file
- */
-
- void CloseCoder (void)
-
- {
- int i;
-
- put_bit (1);
- for (i = 0; i < 7; i++) put_bit (0);
- CloseOutputFile ();
- }
-
-
-
- /*
- Save state of arithmetic coder
- Allows state to be restored at a later time
- */
-
- void SaveCoderState (struct coder_state *p)
-
- {
- p -> low = low;
- p -> range = range;
- p -> uflow = under_flow_count;
- p -> bits = code_bit_count;
- p -> fpos = codesize;
- }
-
-
- /*
- Restore arithmetic coder state from saved value
- Repositin output file
- Set all internal values to their original state
- */
-
- void RestoreCoderState (struct coder_state *p)
-
- {
- int n;
- int cv;
- static unsigned char reset_mask [] =
-
- {
- 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF,
- };
-
- n = codesize - p -> fpos;
- cv = ResetOutputPointer (n);
-
- low = p -> low;
- range = p -> range;
-
- under_flow_count = p -> uflow;
- code_bit_count = p -> bits;
- code_value = cv & reset_mask [code_bit_count];
- codesize -= n;
- }
-
-
- /*
- Estimate length of output code string
- Uses previously saved coder state
- Returns difference between saved position and current position
- */
-
- int CodeLength (struct coder_state *csptr)
-
- {
- int len;
-
- len = codesize - csptr -> fpos;
- len *= 8;
- len += under_flow_count - csptr -> uflow;
- len += code_bit_count - csptr -> bits;
-
- return len;
- }
-
-
- /*
- Arithmetic coder
- Encode symbol using input frequencies
- Output as many bits as possible to output file
- Update coder values for next symbol
- */
-
- void EncodeArith (unsigned base, unsigned freq, unsigned cmax)
-
- {
- unsigned long t;
- unsigned x;
-
- int n1, n2;
-
- t = (long) range * (long) base;
- t += (long) base;
- low += (unsigned) (t / cmax);
- x = (unsigned) (t % cmax);
-
- t = (long) range * (long) freq;
-
- t += (long) (freq + x);
- t -= cmax;
- range = (unsigned) (t / cmax);
-
- n1 = shift_count ((low + range) ^ low);
- if (n1 && under_flow_count)
- {
- clear_under_flow ((low & 0x8000) != 0);
- low ^= 0x8000;
- }
-
- if (n1)
- {
- put_bit_string (low, n1);
- low <<= n1;
- range = ((range + 1) << n1) - 1;
- }
-
- if (range < MIN_RANGE)
- {
- n2 = shift_count (range - 1) - 1;
-
- under_flow_count += n2;
- low <<= n2;
- low &= 0x7FFF;
- range = ((range + 1) << n2) - 1;
- }
- }
-
-
- /*
- Send bit string based on underflow count
- Uses bit value followed by its complement
-
- generates: 0111... or 1000...
- */
-
- static void clear_under_flow (unsigned bit)
-
- {
- put_bit (bit);
- bit ^= 0x01;
- while (-- under_flow_count) put_bit (bit);
- }
-
-
-
- /*
- Send bit string
- */
-
- static void put_bit_string (unsigned x, int count)
-
- {
- while (count)
- {
- put_bit ((x & 0x8000) != 0);
- x <<= 1;
- count --;
- }
- }
-
-
-
- /*
- Write single bit to output file using internal buffer
- */
-
- static void put_bit (int bit)
-
- {
- static unsigned char mask [] =
- {
- 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
- };
-
- if (bit) code_value |= mask [code_bit_count];
- if (++ code_bit_count == 8)
- {
- WriteOutputFile (code_value);
- code_value = 0;
- code_bit_count = 0;
- codesize ++;
- }
- }
-
-
-
- /*
- Determine number of leading zero bits on unsigned value
- */
-
- static int shift_count (unsigned n)
-
- {
- int i;
-
- i = 0;
- while ((n & 0x8000) == 0 && i < 16)
- {
- i ++;
- n <<= 1;
- }
-
- return i;
- }
-
-
-
- /*
- Read bit string from input stream
- Length is limited to word size
- */
-
- static unsigned get_bit_string (int n)
-
- {
- unsigned x = 0;
-
- while (n)
- {
- x <<= 1;
- x += get_bit ();
- n --;
- }
-
- return x;
- }
-
-
-
- /*
- Read a single bit from input stream
- Uses a one byte buffer for intermediate values
- */
-
- static unsigned get_bit (void)
-
- {
- int n;
-
- if (code_bit_count == 0)
- {
- code_bit_count = 8;
- n = ReadInputFile ();
- code_value = n >= 0 ? n : 0;
- }
-
- code_bit_count --;
- n = code_value & 0x80;
- code_value <<= 1;
-
- return n != 0;
- }
-
-
-
- /*
- Initialize arithmetic decode procedure
- */
-
- void StartDecode (void)
-
- {
- int i;
-
- value = 0;
- for (i = 0; i < 16; i ++)
- {
- value <<= 1;
- value |= get_bit ();
- }
- }
-
-
- /*
- Return value of next input code
- Input consists of total frequency for active symbol set
- Note that decoder must be updated with actual frequencies used
- */
-
- int DecodeArith (unsigned cmax)
-
- {
- unsigned long t;
-
- t = (long) (value - low + 1) * (long) cmax;
- t -= 1;
- t /= (long) range + 1;
-
- return (unsigned) t;
- }
-
-
- /*
- Update arithmetic decoder using actual symbol frequencies
- Read additional bits from input based on symbol values
- */
-
- void UpdateDecoder (unsigned base, unsigned freq, unsigned cmax)
-
- {
- unsigned long t;
- unsigned x, y;
-
- int n1, n2;
-
- t = (long) range * (long) base;
- t += (long) base;
- x = (unsigned) (t / cmax);
- y = (unsigned) (t % cmax);
-
- low += x;
-
- t = (long) range * (long) freq;
- t += (long) (freq + y);
- t -= cmax;
- range = (unsigned) (t / cmax);
-
- n1 = shift_count ((low + range) ^ low);
- if (n1)
- {
- low <<= n1;
- range = ((range + 1) << n1) - 1;
- value <<= n1;
- value |= get_bit_string (n1);
- }
-
- if (range < MIN_RANGE)
- {
- n2 = shift_count (range - 1) - 1;
- value -= low;
- low <<= n2;
- low &= 0x7FFF;
- range = ((range + 1) << n2) - 1;
- value <<= n2;
- value |= get_bit_string (n2);
- value += low;
- }
- }
-