diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2013-03-11 18:46:03 +0100 |
---|---|---|
committer | Dominik Riebeling <Dominik.Riebeling@gmail.com> | 2013-11-04 22:14:17 +0100 |
commit | 739a7ae0e9acb27227f5473a003833ea5a9c97ef (patch) | |
tree | 81f6dfd81b4343745b21a6c00c286791827175e4 /rbutil/rbutilqt/mspack/readbits.h | |
parent | 27111d83be815602ac35354e6a8e4e158c5968f9 (diff) | |
download | rockbox-739a7ae0e9acb27227f5473a003833ea5a9c97ef.tar.gz rockbox-739a7ae0e9acb27227f5473a003833ea5a9c97ef.zip |
Add libmspack to rbutil
Change-Id: I520c14131ec1e12013f106c13cba00aac058ad83
Reviewed-on: http://gerrit.rockbox.org/391
Reviewed-by: Dominik Riebeling <Dominik.Riebeling@gmail.com>
Diffstat (limited to 'rbutil/rbutilqt/mspack/readbits.h')
-rw-r--r-- | rbutil/rbutilqt/mspack/readbits.h | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/rbutil/rbutilqt/mspack/readbits.h b/rbutil/rbutilqt/mspack/readbits.h new file mode 100644 index 0000000000..457cbdd7d4 --- /dev/null +++ b/rbutil/rbutilqt/mspack/readbits.h | |||
@@ -0,0 +1,207 @@ | |||
1 | /* This file is part of libmspack. | ||
2 | * (C) 2003-2010 Stuart Caie. | ||
3 | * | ||
4 | * libmspack is free software; you can redistribute it and/or modify it under | ||
5 | * the terms of the GNU Lesser General Public License (LGPL) version 2.1 | ||
6 | * | ||
7 | * For further details, see the file COPYING.LIB distributed with libmspack | ||
8 | */ | ||
9 | |||
10 | #ifndef MSPACK_READBITS_H | ||
11 | #define MSPACK_READBITS_H 1 | ||
12 | |||
13 | /* this header defines macros that read data streams by | ||
14 | * the individual bits | ||
15 | * | ||
16 | * INIT_BITS initialises bitstream state in state structure | ||
17 | * STORE_BITS stores bitstream state in state structure | ||
18 | * RESTORE_BITS restores bitstream state from state structure | ||
19 | * ENSURE_BITS(n) ensure there are at least N bits in the bit buffer | ||
20 | * READ_BITS(var,n) takes N bits from the buffer and puts them in var | ||
21 | * PEEK_BITS(n) extracts without removing N bits from the bit buffer | ||
22 | * REMOVE_BITS(n) removes N bits from the bit buffer | ||
23 | * | ||
24 | * READ_BITS simply calls ENSURE_BITS, PEEK_BITS and REMOVE_BITS, | ||
25 | * which means it's limited to reading the number of bits you can | ||
26 | * ensure at any one time. It also fails if asked to read zero bits. | ||
27 | * If you need to read zero bits, or more bits than can be ensured in | ||
28 | * one go, use READ_MANY_BITS instead. | ||
29 | * | ||
30 | * These macros have variable names baked into them, so to use them | ||
31 | * you have to define some macros: | ||
32 | * - BITS_TYPE: the type name of your state structure | ||
33 | * - BITS_VAR: the variable that points to your state structure | ||
34 | * - define BITS_ORDER_MSB if bits are read from the MSB, or | ||
35 | * define BITS_ORDER_LSB if bits are read from the LSB | ||
36 | * - READ_BYTES: some code that reads more data into the bit buffer, | ||
37 | * it should use READ_IF_NEEDED (calls read_input if the byte buffer | ||
38 | * is empty), then INJECT_BITS(data,n) to put data from the byte | ||
39 | * buffer into the bit buffer. | ||
40 | * | ||
41 | * You also need to define some variables and structure members: | ||
42 | * - unsigned char *i_ptr; // current position in the byte buffer | ||
43 | * - unsigned char *i_end; // end of the byte buffer | ||
44 | * - unsigned int bit_buffer; // the bit buffer itself | ||
45 | * - unsigned int bits_left; // number of bits remaining | ||
46 | * | ||
47 | * If you use read_input() and READ_IF_NEEDED, they also expect these | ||
48 | * structure members: | ||
49 | * - struct mspack_system *sys; // to access sys->read() | ||
50 | * - unsigned int error; // to record/return read errors | ||
51 | * - unsigned char input_end; // to mark reaching the EOF | ||
52 | * - unsigned char *inbuf; // the input byte buffer | ||
53 | * - unsigned int inbuf_size; // the size of the input byte buffer | ||
54 | * | ||
55 | * Your READ_BYTES implementation should read data from *i_ptr and | ||
56 | * put them in the bit buffer. READ_IF_NEEDED will call read_input() | ||
57 | * if i_ptr reaches i_end, and will fill up inbuf and set i_ptr to | ||
58 | * the start of inbuf and i_end to the end of inbuf. | ||
59 | * | ||
60 | * If you're reading in MSB order, the routines work by using the area | ||
61 | * beyond the MSB and the LSB of the bit buffer as a free source of | ||
62 | * zeroes when shifting. This avoids having to mask any bits. So we | ||
63 | * have to know the bit width of the bit buffer variable. We use | ||
64 | * <limits.h> and CHAR_BIT to find the size of the bit buffer in bits. | ||
65 | * | ||
66 | * If you are reading in LSB order, bits need to be masked. Normally | ||
67 | * this is done by computing the mask: N bits are masked by the value | ||
68 | * (1<<N)-1). However, you can define BITS_LSB_TABLE to use a lookup | ||
69 | * table instead of computing this. This adds two new macros, | ||
70 | * PEEK_BITS_T and READ_BITS_T which work the same way as PEEK_BITS | ||
71 | * and READ_BITS, except they use this lookup table. This is useful if | ||
72 | * you need to look up a number of bits that are only known at | ||
73 | * runtime, so the bit mask can't be turned into a constant by the | ||
74 | * compiler. | ||
75 | |||
76 | * The bit buffer datatype should be at least 32 bits wide: it must be | ||
77 | * possible to ENSURE_BITS(17), so it must be possible to add 16 new bits | ||
78 | * to the bit buffer when the bit buffer already has 1 to 15 bits left. | ||
79 | */ | ||
80 | |||
81 | #ifndef BITS_VAR | ||
82 | # error "define BITS_VAR as the state structure poiner variable name" | ||
83 | #endif | ||
84 | #ifndef BITS_TYPE | ||
85 | # error "define BITS_TYPE as the state structure type" | ||
86 | #endif | ||
87 | #if defined(BITS_ORDER_MSB) && defined(BITS_ORDER_LSB) | ||
88 | # error "you must define either BITS_ORDER_MSB or BITS_ORDER_LSB" | ||
89 | #else | ||
90 | # if !(defined(BITS_ORDER_MSB) || defined(BITS_ORDER_LSB)) | ||
91 | # error "you must define BITS_ORDER_MSB or BITS_ORDER_LSB" | ||
92 | # endif | ||
93 | #endif | ||
94 | |||
95 | #if HAVE_LIMITS_H | ||
96 | # include <limits.h> | ||
97 | #endif | ||
98 | #ifndef CHAR_BIT | ||
99 | # define CHAR_BIT (8) | ||
100 | #endif | ||
101 | #define BITBUF_WIDTH (sizeof(bit_buffer) * CHAR_BIT) | ||
102 | |||
103 | #define INIT_BITS do { \ | ||
104 | BITS_VAR->i_ptr = &BITS_VAR->inbuf[0]; \ | ||
105 | BITS_VAR->i_end = &BITS_VAR->inbuf[0]; \ | ||
106 | BITS_VAR->bit_buffer = 0; \ | ||
107 | BITS_VAR->bits_left = 0; \ | ||
108 | BITS_VAR->input_end = 0; \ | ||
109 | } while (0) | ||
110 | |||
111 | #define STORE_BITS do { \ | ||
112 | BITS_VAR->i_ptr = i_ptr; \ | ||
113 | BITS_VAR->i_end = i_end; \ | ||
114 | BITS_VAR->bit_buffer = bit_buffer; \ | ||
115 | BITS_VAR->bits_left = bits_left; \ | ||
116 | } while (0) | ||
117 | |||
118 | #define RESTORE_BITS do { \ | ||
119 | i_ptr = BITS_VAR->i_ptr; \ | ||
120 | i_end = BITS_VAR->i_end; \ | ||
121 | bit_buffer = BITS_VAR->bit_buffer; \ | ||
122 | bits_left = BITS_VAR->bits_left; \ | ||
123 | } while (0) | ||
124 | |||
125 | #define ENSURE_BITS(nbits) do { \ | ||
126 | while (bits_left < (nbits)) READ_BYTES; \ | ||
127 | } while (0) | ||
128 | |||
129 | #define READ_BITS(val, nbits) do { \ | ||
130 | ENSURE_BITS(nbits); \ | ||
131 | (val) = PEEK_BITS(nbits); \ | ||
132 | REMOVE_BITS(nbits); \ | ||
133 | } while (0) | ||
134 | |||
135 | #define READ_MANY_BITS(val, bits) do { \ | ||
136 | unsigned char needed = (bits), bitrun; \ | ||
137 | (val) = 0; \ | ||
138 | while (needed > 0) { \ | ||
139 | if (bits_left <= (BITBUF_WIDTH - 16)) READ_BYTES; \ | ||
140 | bitrun = (bits_left < needed) ? bits_left : needed; \ | ||
141 | (val) = ((val) << bitrun) | PEEK_BITS(bitrun); \ | ||
142 | REMOVE_BITS(bitrun); \ | ||
143 | needed -= bitrun; \ | ||
144 | } \ | ||
145 | } while (0) | ||
146 | |||
147 | #ifdef BITS_ORDER_MSB | ||
148 | # define PEEK_BITS(nbits) (bit_buffer >> (BITBUF_WIDTH - (nbits))) | ||
149 | # define REMOVE_BITS(nbits) ((bit_buffer <<= (nbits)), (bits_left -= (nbits))) | ||
150 | # define INJECT_BITS(bitdata,nbits) ((bit_buffer |= \ | ||
151 | (bitdata) << (BITBUF_WIDTH - (nbits) - bits_left)), (bits_left += (nbits))) | ||
152 | #else /* BITS_ORDER_LSB */ | ||
153 | # define PEEK_BITS(nbits) (bit_buffer & ((1 << (nbits))-1)) | ||
154 | # define REMOVE_BITS(nbits) ((bit_buffer >>= (nbits)), (bits_left -= (nbits))) | ||
155 | # define INJECT_BITS(bitdata,nbits) ((bit_buffer |= \ | ||
156 | (bitdata) << bits_left), (bits_left += (nbits))) | ||
157 | #endif | ||
158 | |||
159 | #ifdef BITS_LSB_TABLE | ||
160 | /* lsb_bit_mask[n] = (1 << n) - 1 */ | ||
161 | static const unsigned short lsb_bit_mask[17] = { | ||
162 | 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, | ||
163 | 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff | ||
164 | }; | ||
165 | # define PEEK_BITS_T(nbits) (bit_buffer & lsb_bit_mask[(nbits)]) | ||
166 | # define READ_BITS_T(val, nbits) do { \ | ||
167 | ENSURE_BITS(nbits); \ | ||
168 | (val) = PEEK_BITS_T(nbits); \ | ||
169 | REMOVE_BITS(nbits); \ | ||
170 | } while (0) | ||
171 | #endif | ||
172 | |||
173 | #ifndef BITS_NO_READ_INPUT | ||
174 | # define READ_IF_NEEDED do { \ | ||
175 | if (i_ptr >= i_end) { \ | ||
176 | if (read_input(BITS_VAR)) \ | ||
177 | return BITS_VAR->error; \ | ||
178 | i_ptr = BITS_VAR->i_ptr; \ | ||
179 | i_end = BITS_VAR->i_end; \ | ||
180 | } \ | ||
181 | } while (0) | ||
182 | |||
183 | static int read_input(BITS_TYPE *p) { | ||
184 | int read = p->sys->read(p->input, &p->inbuf[0], (int)p->inbuf_size); | ||
185 | if (read < 0) return p->error = MSPACK_ERR_READ; | ||
186 | |||
187 | /* we might overrun the input stream by asking for bits we don't use, | ||
188 | * so fake 2 more bytes at the end of input */ | ||
189 | if (read == 0) { | ||
190 | if (p->input_end) { | ||
191 | D(("out of input bytes")) | ||
192 | return p->error = MSPACK_ERR_READ; | ||
193 | } | ||
194 | else { | ||
195 | read = 2; | ||
196 | p->inbuf[0] = p->inbuf[1] = 0; | ||
197 | p->input_end = 1; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | /* update i_ptr and i_end */ | ||
202 | p->i_ptr = &p->inbuf[0]; | ||
203 | p->i_end = &p->inbuf[read]; | ||
204 | return MSPACK_ERR_OK; | ||
205 | } | ||
206 | #endif | ||
207 | #endif | ||