Context algorithm
Semi-predictive context algorithm implementation
 All Data Structures Files Functions Variables Typedefs Macros Pages
bitio.c
Go to the documentation of this file.
1 /*
2  * Listing 4 -- bitio.c
3  *
4  * This routine contains a set of bit oriented i/o routines
5  * used for arithmetic data compression. The important fact to
6  * know about these is that the first bit is stored in the msb of
7  * the first byte of the output, like you might expect.
8  *
9  * Both input and output maintain a local buffer so that they only
10  * have to do block reads and writes. This is done in spite of the
11  * fact that C standard I/O does the same thing. If these
12  * routines are ever ported to assembly language the buffering
13  * will come in handy.
14  *
15  */
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include "coder.h"
19 #include "bitio.h"
20 
21 #define BUFFER_SIZE 256
22 static char buffer[ BUFFER_SIZE + 2 ]; /* This is the i/o buffer */
23 static char *current_byte; /* Pointer to current byte */
24 
25 static int output_mask; /* During output, this byte */
26  /* contains the mask that is */
27  /* applied to the output byte*/
28  /* if the output bit is a 1 */
29 
30 static int input_bytes_left; /* During input, these three */
31 static int input_bits_left; /* variables keep track of my*/
32 static int past_eof; /* input state. The past_eof*/
33  /* byte comes about because */
34  /* of the fact that there is */
35  /* a possibility the decoder */
36  /* can legitimately ask for */
37  /* more bits even after the */
38  /* entire file has been */
39  /* sucked dry. */
40 
41 
42 /*
43  * This routine is called once to initialze the output bitstream.
44  * All it has to do is set up the current_byte pointer, clear out
45  * all the bits in my current output byte, and set the output mask
46  * so it will set the proper bit next time a bit is output.
47  */
49 {
51  *current_byte = 0;
52  output_mask = 0x80;
53 }
54 
55 /*
56  * The output bit routine just has to set a bit in the current byte
57  * if requested to. After that, it updates the mask. If the mask
58  * shows that the current byte is filled up, it is time to go to the
59  * next character in the buffer. If the next character is past the
60  * end of the buffer, it is time to flush the buffer.
61  */
62 void output_bit( FILE *stream, int bit )
63 {
64  if ( bit )
66  output_mask >>= 1;
67  if ( output_mask == 0 )
68  {
69  output_mask = 0x80;
70  current_byte++;
71  if ( current_byte == ( buffer + BUFFER_SIZE ) )
72  {
73  fwrite( buffer, 1, BUFFER_SIZE, stream );
75  }
76  *current_byte = 0;
77  }
78 }
79 
80 /*
81  * When the encoding is done, there will still be a lot of bits and
82  * bytes sitting in the buffer waiting to be sent out. This routine
83  * is called to clean things up at that point.
84  */
85 void flush_output_bitstream( FILE *stream )
86 {
87  fwrite( buffer, 1, (size_t)( current_byte - buffer ) + 1, stream );
89 }
90 
91 /*
92  * Bit oriented input is set up so that the next time the input_bit
93  * routine is called, it will trigger the read of a new block. That
94  * is why input_bits_left is set to 0.
95  */
97 {
98  input_bits_left = 0;
99  input_bytes_left = 1;
100  past_eof = 0;
101 }
102 
103 /*
104  * This routine reads bits in from a file. The bits are all sitting
105  * in a buffer, and this code pulls them out, one at a time. When the
106  * buffer has been emptied, that triggers a new file read, and the
107  * pointers are reset. This routine is set up to allow for two dummy
108  * bytes to be read in after the end of file is reached. This is because
109  * we have to keep feeding bits into the pipeline to be decoded so that
110  * the old stuff that is 16 bits upstream can be pushed out.
111  */
112 short int input_bit( FILE *stream )
113 {
114  if ( input_bits_left == 0 )
115  {
116  current_byte++;
118  input_bits_left = 8;
119  if ( input_bytes_left == 0 )
120  {
121  input_bytes_left = fread( buffer, 1, BUFFER_SIZE, stream );
122  if ( input_bytes_left == 0 )
123  {
124  if ( past_eof )
125  {
126  perror("Bad input file");
127  exit( -1 );
128  }
129  else
130  {
131  past_eof = 1;
132  input_bytes_left = 2;
133  }
134  }
136  }
137  }
138  input_bits_left--;
139  return ( ( *current_byte >> input_bits_left ) & 1 );
140 }
141 
142 /*
143  * When monitoring compression ratios, we need to know how many
144  * bytes have been output so far. This routine takes care of telling
145  * how many bytes have been output, including pending bytes that
146  * haven't actually been written out.
147  */
148 long bit_ftell_output( FILE *stream )
149 {
150  long total;
151 
152  total = ftell( stream );
153  total += current_byte - buffer;
154  total += underflow_bits/8;
155  return( total );
156 }
157 
158 /*
159  * When monitoring compression ratios, we need to know how many bits
160  * have been read in so far. This routine tells how many bytes have
161  * been read in, excluding bytes that are pending in the buffer.
162  */
163 long bit_ftell_input( FILE *stream )
164 {
165  return( ftell( stream ) - input_bytes_left + 1 );
166 }
167 
void initialize_input_bitstream()
Definition: bitio.c:96
void initialize_output_bitstream()
Definition: bitio.c:48
void flush_output_bitstream(FILE *stream)
Definition: bitio.c:85
static int input_bytes_left
Definition: bitio.c:30
static int output_mask
Definition: bitio.c:25
long bit_ftell_input(FILE *stream)
Definition: bitio.c:163
long underflow_bits
Definition: coder.c:29
static char buffer[BUFFER_SIZE+2]
Definition: bitio.c:22
static int input_bits_left
Definition: bitio.c:31
void output_bit(FILE *stream, int bit)
Definition: bitio.c:62
static int past_eof
Definition: bitio.c:32
short int input_bit(FILE *stream)
Definition: bitio.c:112
#define BUFFER_SIZE
Definition: bitio.c:21
static char * current_byte
Definition: bitio.c:23
long bit_ftell_output(FILE *stream)
Definition: bitio.c:148