* include/vlc_block_helper.h: fixed an idiotically stupid bug in block_PeekOffsetBytes().
[vlc.git] / include / vlc_block_helper.h
1 /*****************************************************************************
2  * vlc_block_helper.h: Helper functions for data blocks management.
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: vlc_block_helper.h,v 1.4 2003/10/23 20:51:20 gbazin Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #ifndef _VLC_BLOCK_HELPER_H
25 #define _VLC_BLOCK_HELPER_H 1
26
27 typedef struct block_bytestream_t
28 {
29     block_t             *p_chain;
30     block_t             *p_block;
31     int                 i_offset;
32 } block_bytestream_t;
33
34 #define block_BytestreamInit( a, b, c ) __block_BytestreamInit( VLC_OBJECT(a), b, c )
35
36 /*****************************************************************************
37  * block_bytestream_t management
38  *****************************************************************************/
39 static inline block_bytestream_t __block_BytestreamInit( vlc_object_t *p_obj,
40                                            block_t *p_block, int i_offset )
41 {
42     block_bytestream_t bytestream;
43
44     bytestream.i_offset = i_offset;
45     bytestream.p_block = p_block;
46     bytestream.p_chain = p_block;
47
48     return bytestream;
49 }
50
51 static inline block_t *block_BytestreamFlush( block_bytestream_t *p_bytestream)
52 {
53     while( p_bytestream->p_chain != p_bytestream->p_block )
54     {
55         block_t *p_next;
56         p_next = p_bytestream->p_chain->p_next;
57         p_bytestream->p_chain->pf_release( p_bytestream->p_chain );
58         p_bytestream->p_chain = p_next;
59     }
60
61     return p_bytestream->p_chain;
62 }
63
64 static inline int block_SkipByte( block_bytestream_t *p_bytestream )
65 {
66     /* Most common case first */
67     if( p_bytestream->p_block->i_buffer - p_bytestream->i_offset )
68     {
69         p_bytestream->i_offset++;
70         return VLC_SUCCESS;
71     }
72     else
73     {
74         block_t *p_block;
75
76         /* Less common case which is also slower */
77         for( p_block = p_bytestream->p_block->p_next;
78              p_block != NULL; p_block = p_block->p_next )
79         {
80             if( p_block->i_buffer )
81             {
82                 p_bytestream->i_offset = 1;
83                 p_bytestream->p_block = p_block;
84                 return VLC_SUCCESS;
85             }
86         }
87     }
88
89     /* Not enough data, bail out */
90     return VLC_EGENERIC;
91 }
92
93 static inline int block_PeekByte( block_bytestream_t *p_bytestream,
94                                   uint8_t *p_data )
95 {
96     /* Most common case first */
97     if( p_bytestream->p_block->i_buffer - p_bytestream->i_offset )
98     {
99         *p_data = p_bytestream->p_block->p_buffer[p_bytestream->i_offset];
100         return VLC_SUCCESS;
101     }
102     else
103     {
104         block_t *p_block;
105
106         /* Less common case which is also slower */
107         for( p_block = p_bytestream->p_block->p_next;
108              p_block != NULL; p_block = p_block->p_next )
109         {
110             if( p_block->i_buffer )
111             {
112                 *p_data = p_block->p_buffer[0];
113                 return VLC_SUCCESS;
114             }
115         }
116     }
117
118     /* Not enough data, bail out */
119     return VLC_EGENERIC;
120 }
121
122 static inline int block_GetByte( block_bytestream_t *p_bytestream,
123                                  uint8_t *p_data )
124 {
125     /* Most common case first */
126     if( p_bytestream->p_block->i_buffer - p_bytestream->i_offset )
127     {
128         *p_data = p_bytestream->p_block->p_buffer[p_bytestream->i_offset];
129         p_bytestream->i_offset++;
130         return VLC_SUCCESS;
131     }
132     else
133     {
134         block_t *p_block;
135
136         /* Less common case which is also slower */
137         for( p_block = p_bytestream->p_block->p_next;
138              p_block != NULL; p_block = p_block->p_next )
139         {
140             if( p_block->i_buffer )
141             {
142                 *p_data = p_block->p_buffer[0];
143                 p_bytestream->i_offset = 1;
144                 p_bytestream->p_block = p_block;
145                 return VLC_SUCCESS;
146             }
147         }
148     }
149
150     /* Not enough data, bail out */
151     return VLC_EGENERIC;
152 }
153
154 static inline int block_SkipBytes( block_bytestream_t *p_bytestream,
155                                    int i_data )
156 {
157     block_t *p_block;
158     int i_offset, i_copy;
159
160     /* Check we have that much data */
161     i_offset = p_bytestream->i_offset;
162     i_copy = 0;
163     for( p_block = p_bytestream->p_block;
164          p_block != NULL; p_block = p_block->p_next )
165     {
166         i_copy = __MIN( i_data, p_block->i_buffer - i_offset );
167         i_data -= i_copy;
168
169         if( !i_data ) break;
170
171         i_offset = 0;
172     }
173
174     if( i_data )
175     {
176         /* Not enough data, bail out */
177         return VLC_EGENERIC;
178     }
179
180     p_bytestream->p_block = p_block;
181     p_bytestream->i_offset = i_offset + i_copy;
182     return VLC_SUCCESS;
183 }
184
185 static inline int block_PeekBytes( block_bytestream_t *p_bytestream,
186                                    uint8_t *p_data, int i_data )
187 {
188     block_t *p_block;
189     int i_offset, i_copy, i_size;
190
191     /* Check we have that much data */
192     i_offset = p_bytestream->i_offset;
193     i_size = i_data;
194     i_copy = 0;
195     for( p_block = p_bytestream->p_block;
196          p_block != NULL; p_block = p_block->p_next )
197     {
198         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
199         i_size -= i_copy;
200         i_offset = 0;
201
202         if( !i_size ) break;
203     }
204
205     if( i_size )
206     {
207         /* Not enough data, bail out */
208         return VLC_EGENERIC;
209     }
210
211     /* Copy the data */
212     i_offset = p_bytestream->i_offset;
213     i_size = i_data;
214     i_copy = 0;
215     for( p_block = p_bytestream->p_block;
216          p_block != NULL; p_block = p_block->p_next )
217     {
218         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
219         i_size -= i_copy;
220
221         if( i_copy )
222         {
223             memcpy( p_data, p_block->p_buffer + i_offset, i_copy );
224             p_data += i_copy;
225         }
226
227         i_offset = 0;
228
229         if( !i_size ) break;
230     }
231
232     return VLC_SUCCESS;
233 }
234
235 static inline int block_GetBytes( block_bytestream_t *p_bytestream,
236                                   uint8_t *p_data, int i_data )
237 {
238     block_t *p_block;
239     int i_offset, i_copy, i_size;
240
241     /* Check we have that much data */
242     i_offset = p_bytestream->i_offset;
243     i_size = i_data;
244     i_copy = 0;
245     for( p_block = p_bytestream->p_block;
246          p_block != NULL; p_block = p_block->p_next )
247     {
248         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
249         i_size -= i_copy;
250         i_offset = 0;
251
252         if( !i_size ) break;
253     }
254
255     if( i_size )
256     {
257         /* Not enough data, bail out */
258         return VLC_EGENERIC;
259     }
260
261     /* Copy the data */
262     i_offset = p_bytestream->i_offset;
263     i_size = i_data;
264     i_copy = 0;
265     for( p_block = p_bytestream->p_block;
266          p_block != NULL; p_block = p_block->p_next )
267     {
268         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
269         i_size -= i_copy;
270
271         if( i_copy )
272         {
273             memcpy( p_data, p_block->p_buffer + i_offset, i_copy );
274             p_data += i_copy;
275         }
276
277         if( !i_size ) break;
278
279         i_offset = 0;
280     }
281
282     /* No buffer given, just skip the data */
283     p_bytestream->p_block = p_block;
284     p_bytestream->i_offset = i_offset + i_copy;
285
286     return VLC_SUCCESS;
287 }
288
289 static inline int block_PeekOffsetBytes( block_bytestream_t *p_bytestream,
290     int i_peek_offset, uint8_t *p_data, int i_data )
291 {
292     block_t *p_block;
293     int i_offset, i_copy, i_size;
294
295     /* Check we have that much data */
296     i_offset = p_bytestream->i_offset;
297     i_size = i_data + i_peek_offset;
298     i_copy = 0;
299     for( p_block = p_bytestream->p_block;
300          p_block != NULL; p_block = p_block->p_next )
301     {
302         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
303         i_size -= i_copy;
304         i_offset = 0;
305
306         if( !i_size ) break;
307     }
308
309     if( i_size )
310     {
311         /* Not enough data, bail out */
312         return VLC_EGENERIC;
313     }
314
315     /* Find the right place */
316     i_offset = p_bytestream->i_offset;
317     i_size = i_peek_offset;
318     i_copy = 0;
319     for( p_block = p_bytestream->p_block;
320          p_block != NULL; p_block = p_block->p_next )
321     {
322         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
323         i_size -= i_copy;
324
325         if( !i_size ) break;
326
327         i_offset = 0;
328     }
329
330     /* Copy the data */
331     i_offset += i_copy;
332     i_size = i_data;
333     i_copy = 0;
334     for( ; p_block != NULL; p_block = p_block->p_next )
335     {
336         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
337         i_size -= i_copy;
338
339         if( i_copy )
340         {
341             memcpy( p_data, p_block->p_buffer + i_offset, i_copy );
342             p_data += i_copy;
343         }
344
345         i_offset = 0;
346
347         if( !i_size ) break;
348     }
349
350     return VLC_SUCCESS;
351 }
352
353 #endif /* VLC_BLOCK_HELPER_H */