/src/speex/libspeex/bits.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2002 Jean-Marc Valin |
2 | | File: speex_bits.c |
3 | | |
4 | | Handles bit packing/unpacking |
5 | | |
6 | | Redistribution and use in source and binary forms, with or without |
7 | | modification, are permitted provided that the following conditions |
8 | | are met: |
9 | | |
10 | | - Redistributions of source code must retain the above copyright |
11 | | notice, this list of conditions and the following disclaimer. |
12 | | |
13 | | - Redistributions in binary form must reproduce the above copyright |
14 | | notice, this list of conditions and the following disclaimer in the |
15 | | documentation and/or other materials provided with the distribution. |
16 | | |
17 | | - Neither the name of the Xiph.org Foundation nor the names of its |
18 | | contributors may be used to endorse or promote products derived from |
19 | | this software without specific prior written permission. |
20 | | |
21 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
22 | | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
23 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
24 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR |
25 | | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
26 | | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
27 | | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
28 | | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
29 | | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
30 | | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
31 | | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
32 | | |
33 | | */ |
34 | | |
35 | | #ifdef HAVE_CONFIG_H |
36 | | #include "config.h" |
37 | | #endif |
38 | | |
39 | | #include "speex/speex_bits.h" |
40 | | #include "arch.h" |
41 | | #include "os_support.h" |
42 | | |
43 | | /* Maximum size of the bit-stream (for fixed-size allocation) */ |
44 | | #ifndef MAX_CHARS_PER_FRAME |
45 | 6.89k | #define MAX_CHARS_PER_FRAME (2000/BYTES_PER_CHAR) |
46 | | #endif |
47 | | |
48 | | EXPORT void speex_bits_init(SpeexBits *bits) |
49 | 3.44k | { |
50 | 3.44k | bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME); |
51 | 3.44k | if (!bits->chars) |
52 | 0 | return; |
53 | | |
54 | 3.44k | bits->buf_size = MAX_CHARS_PER_FRAME; |
55 | | |
56 | 3.44k | bits->owner=1; |
57 | | |
58 | 3.44k | speex_bits_reset(bits); |
59 | 3.44k | } |
60 | | |
61 | | EXPORT void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size) |
62 | 0 | { |
63 | 0 | bits->chars = (char*)buff; |
64 | 0 | bits->buf_size = buf_size; |
65 | |
|
66 | 0 | bits->owner=0; |
67 | |
|
68 | 0 | speex_bits_reset(bits); |
69 | 0 | } |
70 | | |
71 | | EXPORT void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size) |
72 | 0 | { |
73 | 0 | bits->chars = (char*)buff; |
74 | 0 | bits->buf_size = buf_size; |
75 | |
|
76 | 0 | bits->owner=0; |
77 | |
|
78 | 0 | bits->nbBits=buf_size<<LOG2_BITS_PER_CHAR; |
79 | 0 | bits->charPtr=0; |
80 | 0 | bits->bitPtr=0; |
81 | 0 | bits->overflow=0; |
82 | |
|
83 | 0 | } |
84 | | |
85 | | EXPORT void speex_bits_destroy(SpeexBits *bits) |
86 | 3.44k | { |
87 | 3.44k | if (bits->owner) |
88 | 3.44k | speex_free(bits->chars); |
89 | | /* Will do something once the allocation is dynamic */ |
90 | 3.44k | } |
91 | | |
92 | | EXPORT void speex_bits_reset(SpeexBits *bits) |
93 | 3.44k | { |
94 | | /* We only need to clear the first byte now */ |
95 | 3.44k | bits->chars[0]=0; |
96 | 3.44k | bits->nbBits=0; |
97 | 3.44k | bits->charPtr=0; |
98 | 3.44k | bits->bitPtr=0; |
99 | 3.44k | bits->overflow=0; |
100 | 3.44k | } |
101 | | |
102 | | EXPORT void speex_bits_rewind(SpeexBits *bits) |
103 | 0 | { |
104 | 0 | bits->charPtr=0; |
105 | 0 | bits->bitPtr=0; |
106 | 0 | bits->overflow=0; |
107 | 0 | } |
108 | | |
109 | | EXPORT void speex_bits_read_from(SpeexBits *bits, const char *chars, int len) |
110 | 26.3k | { |
111 | 26.3k | int i; |
112 | 26.3k | int nchars = len / BYTES_PER_CHAR; |
113 | 26.3k | if (nchars > bits->buf_size) |
114 | 5 | { |
115 | 5 | speex_notify("Packet is larger than allocated buffer"); |
116 | 5 | if (bits->owner) |
117 | 5 | { |
118 | 5 | char *tmp = (char*)speex_realloc(bits->chars, nchars); |
119 | 5 | if (tmp) |
120 | 5 | { |
121 | 5 | bits->buf_size=nchars; |
122 | 5 | bits->chars=tmp; |
123 | 5 | } else { |
124 | 0 | nchars=bits->buf_size; |
125 | 0 | speex_warning("Could not resize input buffer: truncating input"); |
126 | 0 | } |
127 | 5 | } else { |
128 | 0 | speex_warning("Do not own input buffer: truncating oversize input"); |
129 | 0 | nchars=bits->buf_size; |
130 | 0 | } |
131 | 5 | } |
132 | | #if (BYTES_PER_CHAR==2) |
133 | | /* Swap bytes to proper endian order (could be done externally) */ |
134 | | #define HTOLS(A) ((((A) >> 8)&0xff)|(((A) & 0xff)<<8)) |
135 | | #else |
136 | 230k | #define HTOLS(A) (A) |
137 | 26.3k | #endif |
138 | 256k | for (i=0;i<nchars;i++) |
139 | 230k | bits->chars[i]=HTOLS(chars[i]); |
140 | | |
141 | 26.3k | bits->nbBits=nchars<<LOG2_BITS_PER_CHAR; |
142 | 26.3k | bits->charPtr=0; |
143 | 26.3k | bits->bitPtr=0; |
144 | 26.3k | bits->overflow=0; |
145 | 26.3k | } |
146 | | |
147 | | static void speex_bits_flush(SpeexBits *bits) |
148 | 0 | { |
149 | 0 | int nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); |
150 | 0 | if (bits->charPtr>0) |
151 | 0 | SPEEX_MOVE(bits->chars, &bits->chars[bits->charPtr], nchars-bits->charPtr); |
152 | 0 | bits->nbBits -= bits->charPtr<<LOG2_BITS_PER_CHAR; |
153 | 0 | bits->charPtr=0; |
154 | 0 | } |
155 | | |
156 | | EXPORT void speex_bits_read_whole_bytes(SpeexBits *bits, const char *chars, int nbytes) |
157 | 0 | { |
158 | 0 | int i,pos; |
159 | 0 | int nchars = nbytes/BYTES_PER_CHAR; |
160 | |
|
161 | 0 | if (((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)+nchars > bits->buf_size) |
162 | 0 | { |
163 | | /* Packet is larger than allocated buffer */ |
164 | 0 | if (bits->owner) |
165 | 0 | { |
166 | 0 | char *tmp = (char*)speex_realloc(bits->chars, (bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1); |
167 | 0 | if (tmp) |
168 | 0 | { |
169 | 0 | bits->buf_size=(bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1; |
170 | 0 | bits->chars=tmp; |
171 | 0 | } else { |
172 | 0 | nchars=bits->buf_size-(bits->nbBits>>LOG2_BITS_PER_CHAR)-1; |
173 | 0 | speex_warning("Could not resize input buffer: truncating oversize input"); |
174 | 0 | } |
175 | 0 | } else { |
176 | 0 | speex_warning("Do not own input buffer: truncating oversize input"); |
177 | 0 | nchars=bits->buf_size; |
178 | 0 | } |
179 | 0 | } |
180 | |
|
181 | 0 | speex_bits_flush(bits); |
182 | 0 | pos=bits->nbBits>>LOG2_BITS_PER_CHAR; |
183 | 0 | for (i=0;i<nchars;i++) |
184 | 0 | bits->chars[pos+i]=HTOLS(chars[i]); |
185 | 0 | bits->nbBits+=nchars<<LOG2_BITS_PER_CHAR; |
186 | 0 | } |
187 | | |
188 | | EXPORT int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes) |
189 | 0 | { |
190 | 0 | int i; |
191 | 0 | int max_nchars = max_nbytes/BYTES_PER_CHAR; |
192 | 0 | int charPtr, bitPtr, nbBits; |
193 | | |
194 | | /* Insert terminator, but save the data so we can put it back after */ |
195 | 0 | bitPtr=bits->bitPtr; |
196 | 0 | charPtr=bits->charPtr; |
197 | 0 | nbBits=bits->nbBits; |
198 | 0 | speex_bits_insert_terminator(bits); |
199 | 0 | bits->bitPtr=bitPtr; |
200 | 0 | bits->charPtr=charPtr; |
201 | 0 | bits->nbBits=nbBits; |
202 | |
|
203 | 0 | if (max_nchars > ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)) |
204 | 0 | max_nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); |
205 | |
|
206 | 0 | for (i=0;i<max_nchars;i++) |
207 | 0 | chars[i]=HTOLS(bits->chars[i]); |
208 | 0 | return max_nchars*BYTES_PER_CHAR; |
209 | 0 | } |
210 | | |
211 | | EXPORT int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes) |
212 | 0 | { |
213 | 0 | int max_nchars = max_nbytes/BYTES_PER_CHAR; |
214 | 0 | int i; |
215 | 0 | if (max_nchars > ((bits->nbBits)>>LOG2_BITS_PER_CHAR)) |
216 | 0 | max_nchars = ((bits->nbBits)>>LOG2_BITS_PER_CHAR); |
217 | 0 | for (i=0;i<max_nchars;i++) |
218 | 0 | chars[i]=HTOLS(bits->chars[i]); |
219 | |
|
220 | 0 | if (bits->bitPtr>0) |
221 | 0 | bits->chars[0]=bits->chars[max_nchars]; |
222 | 0 | else |
223 | 0 | bits->chars[0]=0; |
224 | 0 | bits->charPtr=0; |
225 | 0 | bits->nbBits &= (BITS_PER_CHAR-1); |
226 | 0 | return max_nchars*BYTES_PER_CHAR; |
227 | 0 | } |
228 | | |
229 | | EXPORT void speex_bits_pack(SpeexBits *bits, int data, int nbBits) |
230 | 0 | { |
231 | 0 | unsigned int d=data; |
232 | |
|
233 | 0 | if (bits->charPtr+((nbBits+bits->bitPtr)>>LOG2_BITS_PER_CHAR) >= bits->buf_size) |
234 | 0 | { |
235 | 0 | speex_notify("Buffer too small to pack bits"); |
236 | 0 | if (bits->owner) |
237 | 0 | { |
238 | 0 | int new_nchars = ((bits->buf_size+5)*3)>>1; |
239 | 0 | char *tmp = (char*)speex_realloc(bits->chars, new_nchars); |
240 | 0 | if (tmp) |
241 | 0 | { |
242 | 0 | bits->buf_size=new_nchars; |
243 | 0 | bits->chars=tmp; |
244 | 0 | } else { |
245 | 0 | speex_warning("Could not resize input buffer: not packing"); |
246 | 0 | return; |
247 | 0 | } |
248 | 0 | } else { |
249 | 0 | speex_warning("Do not own input buffer: not packing"); |
250 | 0 | return; |
251 | 0 | } |
252 | 0 | } |
253 | | |
254 | 0 | while(nbBits) |
255 | 0 | { |
256 | 0 | int bit; |
257 | 0 | bit = (d>>(nbBits-1))&1; |
258 | 0 | bits->chars[bits->charPtr] |= bit<<(BITS_PER_CHAR-1-bits->bitPtr); |
259 | 0 | bits->bitPtr++; |
260 | |
|
261 | 0 | if (bits->bitPtr==BITS_PER_CHAR) |
262 | 0 | { |
263 | 0 | bits->bitPtr=0; |
264 | 0 | bits->charPtr++; |
265 | 0 | bits->chars[bits->charPtr] = 0; |
266 | 0 | } |
267 | 0 | bits->nbBits++; |
268 | 0 | nbBits--; |
269 | 0 | } |
270 | 0 | } |
271 | | |
272 | | EXPORT int speex_bits_unpack_signed(SpeexBits *bits, int nbBits) |
273 | 0 | { |
274 | 0 | unsigned int d=speex_bits_unpack_unsigned(bits,nbBits); |
275 | | /* If number is negative */ |
276 | 0 | if (d>>(nbBits-1)) |
277 | 0 | { |
278 | 0 | d |= (~0u)<<nbBits; |
279 | 0 | } |
280 | 0 | return d; |
281 | 0 | } |
282 | | |
283 | | EXPORT unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits) |
284 | 655k | { |
285 | 655k | unsigned int d=0; |
286 | 655k | if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+nbBits>bits->nbBits) |
287 | 397k | bits->overflow=1; |
288 | 655k | if (bits->overflow) |
289 | 464k | return 0; |
290 | 937k | while(nbBits) |
291 | 746k | { |
292 | 746k | d<<=1; |
293 | 746k | d |= (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; |
294 | 746k | bits->bitPtr++; |
295 | 746k | if (bits->bitPtr==BITS_PER_CHAR) |
296 | 79.7k | { |
297 | 79.7k | bits->bitPtr=0; |
298 | 79.7k | bits->charPtr++; |
299 | 79.7k | } |
300 | 746k | nbBits--; |
301 | 746k | } |
302 | 190k | return d; |
303 | 655k | } |
304 | | |
305 | | EXPORT unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits) |
306 | 0 | { |
307 | 0 | unsigned int d=0; |
308 | 0 | int bitPtr, charPtr; |
309 | 0 | char *chars; |
310 | |
|
311 | 0 | if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+nbBits>bits->nbBits) |
312 | 0 | bits->overflow=1; |
313 | 0 | if (bits->overflow) |
314 | 0 | return 0; |
315 | | |
316 | 0 | bitPtr=bits->bitPtr; |
317 | 0 | charPtr=bits->charPtr; |
318 | 0 | chars = bits->chars; |
319 | 0 | while(nbBits) |
320 | 0 | { |
321 | 0 | d<<=1; |
322 | 0 | d |= (chars[charPtr]>>(BITS_PER_CHAR-1 - bitPtr))&1; |
323 | 0 | bitPtr++; |
324 | 0 | if (bitPtr==BITS_PER_CHAR) |
325 | 0 | { |
326 | 0 | bitPtr=0; |
327 | 0 | charPtr++; |
328 | 0 | } |
329 | 0 | nbBits--; |
330 | 0 | } |
331 | 0 | return d; |
332 | 0 | } |
333 | | |
334 | | EXPORT int speex_bits_peek(SpeexBits *bits) |
335 | 18.0k | { |
336 | 18.0k | if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+1>bits->nbBits) |
337 | 0 | bits->overflow=1; |
338 | 18.0k | if (bits->overflow) |
339 | 0 | return 0; |
340 | 18.0k | return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; |
341 | 18.0k | } |
342 | | |
343 | | EXPORT void speex_bits_advance(SpeexBits *bits, int n) |
344 | 5.27k | { |
345 | 5.27k | if (((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+n>bits->nbBits) || bits->overflow){ |
346 | 2.09k | bits->overflow=1; |
347 | 2.09k | return; |
348 | 2.09k | } |
349 | 3.18k | bits->charPtr += (bits->bitPtr+n) >> LOG2_BITS_PER_CHAR; /* divide by BITS_PER_CHAR */ |
350 | 3.18k | bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1); /* modulo by BITS_PER_CHAR */ |
351 | 3.18k | } |
352 | | |
353 | | EXPORT int speex_bits_remaining(SpeexBits *bits) |
354 | 133k | { |
355 | 133k | if (bits->overflow) |
356 | 32.8k | return -1; |
357 | 100k | else |
358 | 100k | return bits->nbBits-((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr); |
359 | 133k | } |
360 | | |
361 | | EXPORT int speex_bits_nbytes(SpeexBits *bits) |
362 | 0 | { |
363 | 0 | return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); |
364 | 0 | } |
365 | | |
366 | | EXPORT void speex_bits_insert_terminator(SpeexBits *bits) |
367 | 0 | { |
368 | 0 | if (bits->bitPtr) |
369 | 0 | speex_bits_pack(bits, 0, 1); |
370 | 0 | while (bits->bitPtr) |
371 | 0 | speex_bits_pack(bits, 1, 1); |
372 | 0 | } |