1 /*****************************************************************************
2 * vlc_block_helper.h: Helper functions for data blocks management.
3 *****************************************************************************
4 * Copyright (C) 2003-2017 VLC authors and VideoLAN
6 * Authors: Gildas Bazin <gbazin@netcourrier.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 #ifndef VLC_BLOCK_HELPER_H
24 #define VLC_BLOCK_HELPER_H 1
26 #include <vlc_block.h>
28 typedef struct block_bytestream_t
30 block_t
*p_chain
; /**< byte stream head block */
31 block_t
**pp_last
; /**< tail ppointer for appends */
32 block_t
*p_block
; /**< byte stream read pointer block */
33 size_t i_block_offset
; /**< byte stream read pointer offset within block */
34 size_t i_base_offset
; /**< block base offset (previous blocks total size) */
35 size_t i_total
; /**< total bytes over all linked blocks */
38 /*****************************************************************************
39 * block_bytestream_t management
40 *****************************************************************************/
41 static inline void block_BytestreamInit( block_bytestream_t
*p_bytestream
)
43 p_bytestream
->p_chain
= p_bytestream
->p_block
= NULL
;
44 p_bytestream
->pp_last
= &p_bytestream
->p_chain
;
45 p_bytestream
->i_block_offset
= 0;
46 p_bytestream
->i_base_offset
= 0;
47 p_bytestream
->i_total
= 0;
50 static inline void block_BytestreamRelease( block_bytestream_t
*p_bytestream
)
52 block_ChainRelease( p_bytestream
->p_chain
);
56 * It flush all data (read and unread) from a block_bytestream_t.
58 static inline void block_BytestreamEmpty( block_bytestream_t
*p_bytestream
)
60 block_BytestreamRelease( p_bytestream
);
61 block_BytestreamInit( p_bytestream
);
65 * It flushes all already read data from a block_bytestream_t.
67 static inline void block_BytestreamFlush( block_bytestream_t
*p_bytestream
)
69 block_t
*block
= p_bytestream
->p_chain
;
71 while( block
!= p_bytestream
->p_block
)
73 block_t
*p_next
= block
->p_next
;
75 p_bytestream
->i_total
-= block
->i_buffer
;
76 p_bytestream
->i_base_offset
-= block
->i_buffer
;
77 block_Release( block
);
81 while( block
!= NULL
&& block
->i_buffer
== p_bytestream
->i_block_offset
)
83 block_t
*p_next
= block
->p_next
;
85 p_bytestream
->i_total
-= block
->i_buffer
;
86 block_Release( block
);
88 p_bytestream
->i_block_offset
= 0;
91 p_bytestream
->p_chain
= p_bytestream
->p_block
= block
;
92 if( p_bytestream
->p_chain
== NULL
)
93 p_bytestream
->pp_last
= &p_bytestream
->p_chain
;
96 static inline void block_BytestreamPush( block_bytestream_t
*p_bytestream
,
99 block_ChainLastAppend( &p_bytestream
->pp_last
, p_block
);
100 if( !p_bytestream
->p_block
) p_bytestream
->p_block
= p_block
;
101 for( ; p_block
; p_block
= p_block
->p_next
)
102 p_bytestream
->i_total
+= p_block
->i_buffer
;
105 static inline size_t block_BytestreamRemaining( const block_bytestream_t
*p_bytestream
)
107 return ( p_bytestream
->i_total
> p_bytestream
->i_base_offset
+ p_bytestream
->i_block_offset
) ?
108 p_bytestream
->i_total
- p_bytestream
->i_base_offset
- p_bytestream
->i_block_offset
: 0;
112 static inline block_t
*block_BytestreamPop( block_bytestream_t
*p_bytestream
)
116 block_BytestreamFlush( p_bytestream
);
118 p_block
= p_bytestream
->p_block
;
119 if( unlikely( p_block
== NULL
) )
123 else if( !p_block
->p_next
)
125 p_block
->p_buffer
+= p_bytestream
->i_block_offset
;
126 p_block
->i_buffer
-= p_bytestream
->i_block_offset
;
127 p_bytestream
->i_block_offset
= 0;
128 p_bytestream
->i_total
= 0;
129 p_bytestream
->p_chain
= p_bytestream
->p_block
= NULL
;
130 p_bytestream
->pp_last
= &p_bytestream
->p_chain
;
134 while( p_block
->p_next
&& p_block
->p_next
->p_next
)
135 p_block
= p_block
->p_next
;
137 block_t
*p_block_old
= p_block
;
138 p_block
= p_block
->p_next
;
139 p_block_old
->p_next
= NULL
;
140 p_bytestream
->pp_last
= &p_block_old
->p_next
;
142 p_bytestream
->i_total
-= p_block
->i_buffer
;
147 static inline int block_WaitBytes( block_bytestream_t
*p_bytestream
,
150 if( block_BytestreamRemaining( p_bytestream
) >= i_data
)
155 static inline int block_PeekBytes( block_bytestream_t
*p_bytestream
,
156 uint8_t *p_data
, size_t i_data
)
158 if( block_BytestreamRemaining( p_bytestream
) < i_data
)
162 size_t i_offset
= p_bytestream
->i_block_offset
;
163 size_t i_size
= i_data
;
164 for( block_t
*p_block
= p_bytestream
->p_block
;
165 p_block
!= NULL
; p_block
= p_block
->p_next
)
167 size_t i_copy
= __MIN( i_size
, p_block
->i_buffer
- i_offset
);
172 memcpy( p_data
, p_block
->p_buffer
+ i_offset
, i_copy
);
184 static inline int block_GetBytes( block_bytestream_t
*p_bytestream
,
185 uint8_t *p_data
, size_t i_data
)
187 if( block_BytestreamRemaining( p_bytestream
) < i_data
)
191 size_t i_offset
= p_bytestream
->i_block_offset
;
192 size_t i_size
= i_data
;
195 for( p_block
= p_bytestream
->p_block
;
196 p_block
!= NULL
; p_block
= p_block
->p_next
)
198 i_copy
= __MIN( i_size
, p_block
->i_buffer
- i_offset
);
201 if( i_copy
&& p_data
!= NULL
)
203 memcpy( p_data
, p_block
->p_buffer
+ i_offset
, i_copy
);
210 p_bytestream
->i_base_offset
+= p_block
->i_buffer
;
214 p_bytestream
->p_block
= p_block
;
215 p_bytestream
->i_block_offset
= i_offset
+ i_copy
;
220 static inline int block_SkipBytes( block_bytestream_t
*p_bytestream
,
223 return block_GetBytes( p_bytestream
, NULL
, i_data
);
226 static inline int block_SkipByte( block_bytestream_t
*p_bytestream
)
228 return block_GetBytes( p_bytestream
, NULL
, 1 );
231 static inline int block_PeekOffsetBytes( block_bytestream_t
*p_bytestream
,
232 size_t i_peek_offset
, uint8_t *p_data
, size_t i_data
)
234 const size_t i_remain
= block_BytestreamRemaining( p_bytestream
);
235 if( i_remain
< i_data
+ i_peek_offset
)
238 /* Find the right place */
239 size_t i_offset
= p_bytestream
->i_block_offset
;
240 size_t i_size
= i_peek_offset
;
243 for( p_block
= p_bytestream
->p_block
;
244 p_block
!= NULL
; p_block
= p_block
->p_next
)
246 i_copy
= __MIN( i_size
, p_block
->i_buffer
- i_offset
);
257 for( ; p_block
!= NULL
; p_block
= p_block
->p_next
)
259 i_copy
= __MIN( i_size
, p_block
->i_buffer
- i_offset
);
264 memcpy( p_data
, p_block
->p_buffer
+ i_offset
, i_copy
);
276 typedef const uint8_t * (*block_startcode_helper_t
)( const uint8_t *, const uint8_t * );
277 typedef bool (*block_startcode_matcher_t
)( uint8_t, size_t, const uint8_t * );
279 static inline int block_FindStartcodeFromOffset(
280 block_bytestream_t
*p_bytestream
, size_t *pi_offset
,
281 const uint8_t *p_startcode
, int i_startcode_length
,
282 block_startcode_helper_t p_startcode_helper
,
283 block_startcode_matcher_t p_startcode_matcher
)
285 block_t
*p_block
, *p_block_backup
= 0;
287 size_t i_offset
, i_offset_backup
= 0;
288 int i_caller_offset_backup
= 0, i_match
;
290 /* Find the right place */
291 i_size
= *pi_offset
+ p_bytestream
->i_block_offset
;
292 for( p_block
= p_bytestream
->p_block
;
293 p_block
!= NULL
; p_block
= p_block
->p_next
)
295 i_size
-= p_block
->i_buffer
;
296 if( i_size
< 0 ) break;
299 if( unlikely( i_size
>= 0 ) )
301 /* Not enough data, bail out */
306 * We first look for an occurrence of the 1st startcode byte and
307 * if found, we do a more thorough check. */
308 i_size
+= p_block
->i_buffer
;
309 *pi_offset
-= i_size
;
311 for( ; p_block
!= NULL
; p_block
= p_block
->p_next
)
313 for( i_offset
= i_size
; i_offset
< p_block
->i_buffer
; i_offset
++ )
315 /* Use optimized helper when possible */
316 if( p_startcode_helper
&& !i_match
&&
317 (p_block
->i_buffer
- i_offset
) > ((size_t)i_startcode_length
- 1) )
319 const uint8_t *p_res
= p_startcode_helper( &p_block
->p_buffer
[i_offset
],
320 &p_block
->p_buffer
[p_block
->i_buffer
] );
323 *pi_offset
+= i_offset
+ (p_res
- &p_block
->p_buffer
[i_offset
]);
326 /* Then parsing boundary with legacy code */
327 i_offset
= p_block
->i_buffer
- (i_startcode_length
- 1);
330 bool b_matched
= ( p_startcode_matcher
)
331 ? p_startcode_matcher( p_block
->p_buffer
[i_offset
], i_match
, p_startcode
)
332 : p_block
->p_buffer
[i_offset
] == p_startcode
[i_match
];
337 p_block_backup
= p_block
;
338 i_offset_backup
= i_offset
;
339 i_caller_offset_backup
= *pi_offset
;
342 if( i_match
+ 1 == i_startcode_length
)
345 *pi_offset
+= i_offset
- i_match
;
351 else if ( i_match
> 0 )
354 p_block
= p_block_backup
;
355 i_offset
= i_offset_backup
;
356 *pi_offset
= i_caller_offset_backup
;
362 *pi_offset
+= i_offset
;
365 *pi_offset
-= i_match
;
369 #endif /* VLC_BLOCK_HELPER_H */