]> git.sesse.net Git - vlc/blob - include/vlc_bits.h
vlc_bits: use vlc_common and guards against failed realloc
[vlc] / include / vlc_bits.h
1 /*****************************************************************************
2  * vlc_bits.h : Bit handling helpers
3  *****************************************************************************
4  * Copyright (C) 2001, 2002, 2003, 2006, 2015 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Gildas Bazin <gbazin at videolan dot org>
9  *          Rafaël Carré <funman at videolan dot org>
10  *
11  * This program is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation; either version 2.1 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 #ifndef VLC_BITS_H
27 #define VLC_BITS_H 1
28
29 #include <vlc_common.h>
30 #include <vlc_block.h>
31
32 /**
33  * \file
34  * This file defines functions, structures for handling streams of bits in vlc
35  */
36
37 typedef struct bo_t
38 {
39     block_t     *b;
40     size_t      basesize;
41 } bo_t;
42
43 typedef struct bs_s
44 {
45     uint8_t *p_start;
46     uint8_t *p;
47     uint8_t *p_end;
48
49     ssize_t  i_left;    /* i_count number of available bits */
50 } bs_t;
51
52 static inline void bs_init( bs_t *s, const void *p_data, size_t i_data )
53 {
54     s->p_start = (void *)p_data;
55     s->p       = s->p_start;
56     s->p_end   = s->p_start + i_data;
57     s->i_left  = 8;
58 }
59
60 static inline int bs_pos( const bs_t *s )
61 {
62     return( 8 * ( s->p - s->p_start ) + 8 - s->i_left );
63 }
64
65 static inline int bs_eof( const bs_t *s )
66 {
67     return( s->p >= s->p_end ? 1: 0 );
68 }
69
70 static inline uint32_t bs_read( bs_t *s, int i_count )
71 {
72      static const uint32_t i_mask[33] =
73      {  0x00,
74         0x01,      0x03,      0x07,      0x0f,
75         0x1f,      0x3f,      0x7f,      0xff,
76         0x1ff,     0x3ff,     0x7ff,     0xfff,
77         0x1fff,    0x3fff,    0x7fff,    0xffff,
78         0x1ffff,   0x3ffff,   0x7ffff,   0xfffff,
79         0x1fffff,  0x3fffff,  0x7fffff,  0xffffff,
80         0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,
81         0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff};
82     int      i_shr;
83     uint32_t i_result = 0;
84
85     while( i_count > 0 )
86     {
87         if( s->p >= s->p_end )
88         {
89             break;
90         }
91
92         if( ( i_shr = s->i_left - i_count ) >= 0 )
93         {
94             /* more in the buffer than requested */
95             i_result |= ( *s->p >> i_shr )&i_mask[i_count];
96             s->i_left -= i_count;
97             if( s->i_left == 0 )
98             {
99                 s->p++;
100                 s->i_left = 8;
101             }
102             return( i_result );
103         }
104         else
105         {
106             /* less in the buffer than requested */
107            i_result |= (*s->p&i_mask[s->i_left]) << -i_shr;
108            i_count  -= s->i_left;
109            s->p++;
110            s->i_left = 8;
111         }
112     }
113
114     return( i_result );
115 }
116
117 static inline uint32_t bs_read1( bs_t *s )
118 {
119     if( s->p < s->p_end )
120     {
121         unsigned int i_result;
122
123         s->i_left--;
124         i_result = ( *s->p >> s->i_left )&0x01;
125         if( s->i_left == 0 )
126         {
127             s->p++;
128             s->i_left = 8;
129         }
130         return i_result;
131     }
132
133     return 0;
134 }
135
136 static inline uint32_t bs_show( bs_t *s, int i_count )
137 {
138     bs_t     s_tmp = *s;
139     return bs_read( &s_tmp, i_count );
140 }
141
142 static inline void bs_skip( bs_t *s, ssize_t i_count )
143 {
144     s->i_left -= i_count;
145
146     if( s->i_left <= 0 )
147     {
148         const int i_bytes = ( -s->i_left + 8 ) / 8;
149
150         s->p += i_bytes;
151         s->i_left += 8 * i_bytes;
152     }
153 }
154
155 static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
156 {
157     while( i_count > 0 )
158     {
159         if( s->p >= s->p_end )
160         {
161             break;
162         }
163
164         i_count--;
165
166         if( ( i_bits >> i_count )&0x01 )
167         {
168             *s->p |= 1 << ( s->i_left - 1 );
169         }
170         else
171         {
172             *s->p &= ~( 1 << ( s->i_left - 1 ) );
173         }
174         s->i_left--;
175         if( s->i_left == 0 )
176         {
177             s->p++;
178             s->i_left = 8;
179         }
180     }
181 }
182
183 static inline void bs_align( bs_t *s )
184 {
185     if( s->i_left != 8 )
186     {
187         s->i_left = 8;
188         s->p++;
189     }
190 }
191
192 static inline void bs_align_0( bs_t *s )
193 {
194     if( s->i_left != 8 )
195     {
196         bs_write( s, s->i_left, 0 );
197     }
198 }
199
200 static inline void bs_align_1( bs_t *s )
201 {
202     while( s->i_left != 8 )
203     {
204         bs_write( s, 1, 1 );
205     }
206 }
207
208 static inline bool bo_init(bo_t *p_bo, int i_size)
209 {
210     p_bo->b = block_Alloc(i_size);
211     if (!p_bo->b)
212         return false;
213
214     p_bo->b->i_buffer = 0;
215     p_bo->basesize = i_size;
216
217     return true;
218 }
219
220 static inline void bo_free(bo_t *p_bo)
221 {
222     if(!p_bo)
223         return;
224     if(p_bo->b)
225         block_Release(p_bo->b);
226     free(p_bo);
227 }
228
229 static inline int bo_extend(bo_t *p_bo, size_t i_total)
230 {
231     if(!p_bo->b)
232         return false;
233     const size_t i_size = p_bo->b->i_size - (p_bo->b->p_buffer - p_bo->b->p_start);
234     if (i_total >= i_size)
235     {
236         int i_growth = p_bo->basesize;
237         while(i_total >= i_size + i_growth)
238             i_growth += p_bo->basesize;
239
240         int i = p_bo->b->i_buffer; /* Realloc would set payload size == buffer size */
241         p_bo->b = block_Realloc(p_bo->b, 0, i_size + i_growth);
242         if (!p_bo->b)
243             return false;
244         p_bo->b->i_buffer = i;
245     }
246     return true;
247 }
248
249 #define BO_SET_DECL_S(func, handler, type) static inline bool func(bo_t *p_bo, size_t i_offset, type val)\
250     {\
251         if (!bo_extend(p_bo, i_offset + sizeof(type)))\
252             return false;\
253         handler(&p_bo->b->p_buffer[i_offset], val);\
254         return true;\
255     }
256
257 #define BO_ADD_DECL_S(func, handler, type) static inline bool func(bo_t *p_bo, type val)\
258     {\
259         if(!p_bo->b || !handler(p_bo, p_bo->b->i_buffer, val))\
260             return false;\
261         p_bo->b->i_buffer += sizeof(type);\
262         return true;\
263     }
264
265 #define BO_FUNC_DECL(suffix, handler, type ) \
266     BO_SET_DECL_S( bo_set_ ## suffix ## be, handler ## BE, type )\
267     BO_SET_DECL_S( bo_set_ ## suffix ## le, handler ## LE, type )\
268     BO_ADD_DECL_S( bo_add_ ## suffix ## be, bo_set_ ## suffix ## be, type )\
269     BO_ADD_DECL_S( bo_add_ ## suffix ## le, bo_set_ ## suffix ## le, type )
270
271 static inline bool bo_set_8(bo_t *p_bo, size_t i_offset, uint8_t i)
272 {
273     if (!bo_extend(p_bo, i_offset + 1))
274         return false;
275     p_bo->b->p_buffer[i_offset] = i;
276     return true;
277 }
278
279 static inline bool bo_add_8(bo_t *p_bo, uint8_t i)
280 {
281     if(!p_bo->b || !bo_set_8( p_bo, p_bo->b->i_buffer, i ))
282         return false;
283     p_bo->b->i_buffer++;
284     return true;
285 }
286
287 /* declares all bo_[set,add]_[16,32,64] */
288 BO_FUNC_DECL( 16, SetW,  uint16_t )
289 BO_FUNC_DECL( 32, SetDW, uint32_t )
290 BO_FUNC_DECL( 64, SetQW, uint64_t )
291
292 #undef BO_FUNC_DECL
293 #undef BO_SET_DECL_S
294 #undef BO_ADD_DECL_S
295
296 static inline bool bo_add_24be(bo_t *p_bo, uint32_t i)
297 {
298     if(!p_bo->b || !bo_extend(p_bo, p_bo->b->i_buffer + 3))
299         return false;
300     p_bo->b->p_buffer[p_bo->b->i_buffer++] = ((i >> 16) & 0xff);
301     p_bo->b->p_buffer[p_bo->b->i_buffer++] = ((i >> 8) & 0xff);
302     p_bo->b->p_buffer[p_bo->b->i_buffer++] = (i & 0xff);
303     return true;
304 }
305
306 static inline void bo_swap_32be (bo_t *p_bo, size_t i_pos, uint32_t i)
307 {
308     if (!p_bo->b || p_bo->b->i_buffer < i_pos + 4)
309         return;
310     p_bo->b->p_buffer[i_pos    ] = (i >> 24)&0xff;
311     p_bo->b->p_buffer[i_pos + 1] = (i >> 16)&0xff;
312     p_bo->b->p_buffer[i_pos + 2] = (i >>  8)&0xff;
313     p_bo->b->p_buffer[i_pos + 3] = (i      )&0xff;
314 }
315
316 static inline bool bo_add_mem(bo_t *p_bo, size_t i_size, const void *p_mem)
317 {
318     if(!p_bo->b || !bo_extend(p_bo, p_bo->b->i_buffer + i_size))
319         return false;
320     memcpy(&p_bo->b->p_buffer[p_bo->b->i_buffer], p_mem, i_size);
321     p_bo->b->i_buffer += i_size;
322     return true;
323 }
324
325 #define bo_add_fourcc(p_bo, fcc) bo_add_mem(p_bo, 4, fcc)
326
327 #endif