A bit of vlc/libvlc cleanup:
[vlc.git] / include / vlc_block_helper.h
1 /*****************************************************************************
2  * vlc_block_helper.h: Helper functions for data blocks management.
3  *****************************************************************************
4  * Copyright (C) 2003 the VideoLAN team
5  * $Id$
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #if !defined( __LIBVLC__ )
25   #error You are not libvlc or one of its plugins. You cannot include this file
26 #endif
27
28 #ifndef _VLC_BLOCK_HELPER_H
29 #define _VLC_BLOCK_HELPER_H 1
30
31 #include <vlc_block.h>
32
33 typedef struct block_bytestream_t
34 {
35     block_t             *p_chain;
36     block_t             *p_block;
37     int                 i_offset;
38
39 } block_bytestream_t;
40
41 #define block_BytestreamInit( a ) __block_BytestreamInit( VLC_OBJECT(a) )
42
43 /*****************************************************************************
44  * block_bytestream_t management
45  *****************************************************************************/
46 static inline block_bytestream_t __block_BytestreamInit( vlc_object_t *p_obj )
47 {
48     block_bytestream_t bytestream;
49
50     bytestream.i_offset = 0;
51     bytestream.p_chain = bytestream.p_block = NULL;
52
53     return bytestream;
54 }
55
56 static inline void block_BytestreamRelease( block_bytestream_t *p_bytestream )
57 {
58     while( p_bytestream->p_chain )
59     {
60         block_t *p_next;
61         p_next = p_bytestream->p_chain->p_next;
62         p_bytestream->p_chain->pf_release( p_bytestream->p_chain );
63         p_bytestream->p_chain = p_next;
64     }
65     p_bytestream->i_offset = 0;
66     p_bytestream->p_chain = p_bytestream->p_block = NULL;
67 }
68
69 static inline void block_BytestreamFlush( block_bytestream_t *p_bytestream )
70 {
71     while( p_bytestream->p_chain != p_bytestream->p_block )
72     {
73         block_t *p_next;
74         p_next = p_bytestream->p_chain->p_next;
75         p_bytestream->p_chain->pf_release( p_bytestream->p_chain );
76         p_bytestream->p_chain = p_next;
77     }
78     while( p_bytestream->p_block &&
79            (p_bytestream->p_block->i_buffer - p_bytestream->i_offset) == 0 )
80     {
81         block_t *p_next;
82         p_next = p_bytestream->p_chain->p_next;
83         p_bytestream->p_chain->pf_release( p_bytestream->p_chain );
84         p_bytestream->p_chain = p_bytestream->p_block = p_next;
85         p_bytestream->i_offset = 0;
86     }
87 }
88
89 static inline void block_BytestreamPush( block_bytestream_t *p_bytestream,
90                                          block_t *p_block )
91 {
92     block_ChainAppend( &p_bytestream->p_chain, p_block );
93     if( !p_bytestream->p_block ) p_bytestream->p_block = p_block;
94 }
95
96 static inline block_t *block_BytestreamPop( block_bytestream_t *p_bytestream )
97 {
98     block_t *p_block;
99
100     block_BytestreamFlush( p_bytestream );
101
102     p_block = p_bytestream->p_block;
103     if( p_block == NULL )
104     {
105         return NULL;
106     }
107     else if( !p_block->p_next )
108     {
109         p_block->p_buffer += p_bytestream->i_offset;
110         p_block->i_buffer -= p_bytestream->i_offset;
111         p_bytestream->i_offset = 0;
112         p_bytestream->p_chain = p_bytestream->p_block = NULL;
113         return p_block;
114     }
115
116     while( p_block->p_next && p_block->p_next->p_next )
117         p_block = p_block->p_next;
118
119     {
120         block_t *p_block_old = p_block;
121         p_block = p_block->p_next;
122         p_block_old->p_next = NULL;
123     }
124
125     return p_block;
126 }
127
128 static inline int block_SkipByte( block_bytestream_t *p_bytestream )
129 {
130     /* Most common case first */
131     if( p_bytestream->p_block->i_buffer - p_bytestream->i_offset )
132     {
133         p_bytestream->i_offset++;
134         return VLC_SUCCESS;
135     }
136     else
137     {
138         block_t *p_block;
139
140         /* Less common case which is also slower */
141         for( p_block = p_bytestream->p_block->p_next;
142              p_block != NULL; p_block = p_block->p_next )
143         {
144             if( p_block->i_buffer )
145             {
146                 p_bytestream->i_offset = 1;
147                 p_bytestream->p_block = p_block;
148                 return VLC_SUCCESS;
149             }
150         }
151     }
152
153     /* Not enough data, bail out */
154     return VLC_EGENERIC;
155 }
156
157 static inline int block_PeekByte( block_bytestream_t *p_bytestream,
158                                   uint8_t *p_data )
159 {
160     /* Most common case first */
161     if( p_bytestream->p_block->i_buffer - p_bytestream->i_offset )
162     {
163         *p_data = p_bytestream->p_block->p_buffer[p_bytestream->i_offset];
164         return VLC_SUCCESS;
165     }
166     else
167     {
168         block_t *p_block;
169
170         /* Less common case which is also slower */
171         for( p_block = p_bytestream->p_block->p_next;
172              p_block != NULL; p_block = p_block->p_next )
173         {
174             if( p_block->i_buffer )
175             {
176                 *p_data = p_block->p_buffer[0];
177                 return VLC_SUCCESS;
178             }
179         }
180     }
181
182     /* Not enough data, bail out */
183     return VLC_EGENERIC;
184 }
185
186 static inline int block_GetByte( block_bytestream_t *p_bytestream,
187                                  uint8_t *p_data )
188 {
189     /* Most common case first */
190     if( p_bytestream->p_block->i_buffer - p_bytestream->i_offset )
191     {
192         *p_data = p_bytestream->p_block->p_buffer[p_bytestream->i_offset];
193         p_bytestream->i_offset++;
194         return VLC_SUCCESS;
195     }
196     else
197     {
198         block_t *p_block;
199
200         /* Less common case which is also slower */
201         for( p_block = p_bytestream->p_block->p_next;
202              p_block != NULL; p_block = p_block->p_next )
203         {
204             if( p_block->i_buffer )
205             {
206                 *p_data = p_block->p_buffer[0];
207                 p_bytestream->i_offset = 1;
208                 p_bytestream->p_block = p_block;
209                 return VLC_SUCCESS;
210             }
211         }
212     }
213
214     /* Not enough data, bail out */
215     return VLC_EGENERIC;
216 }
217
218 static inline int block_WaitBytes( block_bytestream_t *p_bytestream,
219                                    int i_data )
220 {
221     block_t *p_block;
222     int i_offset, i_copy, i_size;
223
224     /* Check we have that much data */
225     i_offset = p_bytestream->i_offset;
226     i_size = i_data;
227     i_copy = 0;
228     for( p_block = p_bytestream->p_block;
229          p_block != NULL; p_block = p_block->p_next )
230     {
231         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
232         i_size -= i_copy;
233         i_offset = 0;
234
235         if( !i_size ) break;
236     }
237
238     if( i_size )
239     {
240         /* Not enough data, bail out */
241         return VLC_EGENERIC;
242     }
243     return VLC_SUCCESS;
244 }
245
246 static inline int block_SkipBytes( block_bytestream_t *p_bytestream,
247                                    int i_data )
248 {
249     block_t *p_block;
250     int i_offset, i_copy;
251
252     /* Check we have that much data */
253     i_offset = p_bytestream->i_offset;
254     i_copy = 0;
255     for( p_block = p_bytestream->p_block;
256          p_block != NULL; p_block = p_block->p_next )
257     {
258         i_copy = __MIN( i_data, p_block->i_buffer - i_offset );
259         i_data -= i_copy;
260
261         if( !i_data ) break;
262
263         i_offset = 0;
264     }
265
266     if( i_data )
267     {
268         /* Not enough data, bail out */
269         return VLC_EGENERIC;
270     }
271
272     p_bytestream->p_block = p_block;
273     p_bytestream->i_offset = i_offset + i_copy;
274     return VLC_SUCCESS;
275 }
276
277 static inline int block_PeekBytes( block_bytestream_t *p_bytestream,
278                                    uint8_t *p_data, int i_data )
279 {
280     block_t *p_block;
281     int i_offset, i_copy, i_size;
282
283     /* Check we have that much data */
284     i_offset = p_bytestream->i_offset;
285     i_size = i_data;
286     i_copy = 0;
287     for( p_block = p_bytestream->p_block;
288          p_block != NULL; p_block = p_block->p_next )
289     {
290         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
291         i_size -= i_copy;
292         i_offset = 0;
293
294         if( !i_size ) break;
295     }
296
297     if( i_size )
298     {
299         /* Not enough data, bail out */
300         return VLC_EGENERIC;
301     }
302
303     /* Copy the data */
304     i_offset = p_bytestream->i_offset;
305     i_size = i_data;
306     i_copy = 0;
307     for( p_block = p_bytestream->p_block;
308          p_block != NULL; p_block = p_block->p_next )
309     {
310         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
311         i_size -= i_copy;
312
313         if( i_copy )
314         {
315             memcpy( p_data, p_block->p_buffer + i_offset, i_copy );
316             p_data += i_copy;
317         }
318
319         i_offset = 0;
320
321         if( !i_size ) break;
322     }
323
324     return VLC_SUCCESS;
325 }
326
327 static inline int block_GetBytes( block_bytestream_t *p_bytestream,
328                                   uint8_t *p_data, int i_data )
329 {
330     block_t *p_block;
331     int i_offset, i_copy, i_size;
332
333     /* Check we have that much data */
334     i_offset = p_bytestream->i_offset;
335     i_size = i_data;
336     i_copy = 0;
337     for( p_block = p_bytestream->p_block;
338          p_block != NULL; p_block = p_block->p_next )
339     {
340         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
341         i_size -= i_copy;
342         i_offset = 0;
343
344         if( !i_size ) break;
345     }
346
347     if( i_size )
348     {
349         /* Not enough data, bail out */
350         return VLC_EGENERIC;
351     }
352
353     /* Copy the data */
354     i_offset = p_bytestream->i_offset;
355     i_size = i_data;
356     i_copy = 0;
357     for( p_block = p_bytestream->p_block;
358          p_block != NULL; p_block = p_block->p_next )
359     {
360         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
361         i_size -= i_copy;
362
363         if( i_copy )
364         {
365             memcpy( p_data, p_block->p_buffer + i_offset, i_copy );
366             p_data += i_copy;
367         }
368
369         if( !i_size ) break;
370
371         i_offset = 0;
372     }
373
374     /* No buffer given, just skip the data */
375     p_bytestream->p_block = p_block;
376     p_bytestream->i_offset = i_offset + i_copy;
377
378     return VLC_SUCCESS;
379 }
380
381 static inline int block_PeekOffsetBytes( block_bytestream_t *p_bytestream,
382     int i_peek_offset, uint8_t *p_data, int i_data )
383 {
384     block_t *p_block;
385     int i_offset, i_copy, i_size;
386
387     /* Check we have that much data */
388     i_offset = p_bytestream->i_offset;
389     i_size = i_data + i_peek_offset;
390     i_copy = 0;
391     for( p_block = p_bytestream->p_block;
392          p_block != NULL; p_block = p_block->p_next )
393     {
394         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
395         i_size -= i_copy;
396         i_offset = 0;
397
398         if( !i_size ) break;
399     }
400
401     if( i_size )
402     {
403         /* Not enough data, bail out */
404         return VLC_EGENERIC;
405     }
406
407     /* Find the right place */
408     i_offset = p_bytestream->i_offset;
409     i_size = i_peek_offset;
410     i_copy = 0;
411     for( p_block = p_bytestream->p_block;
412          p_block != NULL; p_block = p_block->p_next )
413     {
414         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
415         i_size -= i_copy;
416
417         if( !i_size ) break;
418
419         i_offset = 0;
420     }
421
422     /* Copy the data */
423     i_offset += i_copy;
424     i_size = i_data;
425     i_copy = 0;
426     for( ; p_block != NULL; p_block = p_block->p_next )
427     {
428         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
429         i_size -= i_copy;
430
431         if( i_copy )
432         {
433             memcpy( p_data, p_block->p_buffer + i_offset, i_copy );
434             p_data += i_copy;
435         }
436
437         i_offset = 0;
438
439         if( !i_size ) break;
440     }
441
442     return VLC_SUCCESS;
443 }
444
445 static inline int block_FindStartcodeFromOffset(
446     block_bytestream_t *p_bytestream, int *pi_offset,
447     uint8_t *p_startcode, int i_startcode_length )
448 {
449     block_t *p_block, *p_block_backup = 0;
450     int i_size, i_offset, i_offset_backup = 0;
451     int i_caller_offset_backup = 0, i_match;
452
453     /* Find the right place */
454     i_size = *pi_offset + p_bytestream->i_offset;
455     for( p_block = p_bytestream->p_block;
456          p_block != NULL; p_block = p_block->p_next )
457     {
458         i_size -= p_block->i_buffer;
459         if( i_size < 0 ) break;
460     }
461
462     if( i_size >= 0 )
463     {
464         /* Not enough data, bail out */
465         return VLC_EGENERIC;
466     }
467
468     /* Begin the search.
469      * We first look for an occurrence of the 1st startcode byte and
470      * if found, we do a more thorough check. */
471     i_size = p_block->i_buffer + i_size;
472     *pi_offset -= i_size;
473     i_match = 0;
474     for( ; p_block != NULL; p_block = p_block->p_next )
475     {
476         for( i_offset = i_size; i_offset < p_block->i_buffer; i_offset++ )
477         {
478             if( p_block->p_buffer[i_offset] == p_startcode[i_match] )
479             {
480                 if( !i_match )
481                 {
482                     p_block_backup = p_block;
483                     i_offset_backup = i_offset;
484                     i_caller_offset_backup = *pi_offset;
485                 }
486
487                 if( i_match + 1 == i_startcode_length )
488                 {
489                     /* We have it */
490                     *pi_offset += i_offset - i_match;
491                     return VLC_SUCCESS;
492                 }
493
494                 i_match++;
495             }
496             else if ( i_match )
497             {
498                 /* False positive */
499                 p_block = p_block_backup;
500                 i_offset = i_offset_backup;
501                 *pi_offset = i_caller_offset_backup;
502                 i_match = 0;
503             }
504
505         }
506         i_size = 0;
507         *pi_offset += i_offset;
508     }
509
510     *pi_offset -= i_match;
511     return VLC_EGENERIC;
512 }
513
514 #endif /* VLC_BLOCK_HELPER_H */