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