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