VLC  4.0.0-dev
vlc_block_helper.h
Go to the documentation of this file.
1 /*****************************************************************************
2  * vlc_block_helper.h: Helper functions for data blocks management.
3  *****************************************************************************
4  * Copyright (C) 2003-2017 VLC authors and VideoLAN
5  *
6  * Authors: Gildas Bazin <gbazin@netcourrier.com>
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22 
23 #ifndef VLC_BLOCK_HELPER_H
24 #define VLC_BLOCK_HELPER_H 1
25 
26 #include <vlc_block.h>
27 
28 typedef struct block_bytestream_t
29 {
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 */
37 
38 /*****************************************************************************
39  * block_bytestream_t management
40  *****************************************************************************/
41 static inline void block_BytestreamInit( block_bytestream_t *p_bytestream )
42 {
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;
48 }
49 
50 static inline void block_BytestreamRelease( block_bytestream_t *p_bytestream )
51 {
52  block_ChainRelease( p_bytestream->p_chain );
53 }
54 
55 /**
56  * It flush all data (read and unread) from a block_bytestream_t.
57  */
58 static inline void block_BytestreamEmpty( block_bytestream_t *p_bytestream )
59 {
60  block_BytestreamRelease( p_bytestream );
61  block_BytestreamInit( p_bytestream );
62 }
63 
64 /**
65  * It flushes all already read data from a block_bytestream_t.
66  */
67 static inline void block_BytestreamFlush( block_bytestream_t *p_bytestream )
68 {
69  block_t *block = p_bytestream->p_chain;
70 
71  while( block != p_bytestream->p_block )
72  {
73  block_t *p_next = block->p_next;
74 
75  p_bytestream->i_total -= block->i_buffer;
76  p_bytestream->i_base_offset -= block->i_buffer;
77  block_Release( block );
78  block = p_next;
79  }
80 
81  while( block != NULL && block->i_buffer == p_bytestream->i_block_offset )
82  {
83  block_t *p_next = block->p_next;
84 
85  p_bytestream->i_total -= block->i_buffer;
86  block_Release( block );
87  block = p_next;
88  p_bytestream->i_block_offset = 0;
89  }
90 
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;
94 }
95 
96 static inline void block_BytestreamPush( block_bytestream_t *p_bytestream,
97  block_t *p_block )
98 {
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;
103 }
104 
105 static inline size_t block_BytestreamRemaining( const block_bytestream_t *p_bytestream )
106 {
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;
109 }
110 
111 VLC_USED
112 static inline block_t *block_BytestreamPop( block_bytestream_t *p_bytestream )
113 {
114  block_t *p_block;
115 
116  block_BytestreamFlush( p_bytestream );
117 
118  p_block = p_bytestream->p_block;
119  if( unlikely( p_block == NULL ) )
120  {
121  return NULL;
122  }
123  else if( !p_block->p_next )
124  {
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;
131  return p_block;
132  }
133 
134  while( p_block->p_next && p_block->p_next->p_next )
135  p_block = p_block->p_next;
136 
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;
141  if( p_block )
142  p_bytestream->i_total -= p_block->i_buffer;
143 
144  return p_block;
145 }
146 
147 static inline int block_WaitBytes( block_bytestream_t *p_bytestream,
148  size_t i_data )
149 {
150  if( block_BytestreamRemaining( p_bytestream ) >= i_data )
151  return VLC_SUCCESS;
152  return VLC_EGENERIC;
153 }
154 
155 static inline int block_PeekBytes( block_bytestream_t *p_bytestream,
156  uint8_t *p_data, size_t i_data )
157 {
158  if( block_BytestreamRemaining( p_bytestream ) < i_data )
159  return VLC_EGENERIC;
160 
161  /* Copy the 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 )
166  {
167  size_t i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
168  i_size -= i_copy;
169 
170  if( i_copy )
171  {
172  memcpy( p_data, p_block->p_buffer + i_offset, i_copy );
173  p_data += i_copy;
174  }
175 
176  i_offset = 0;
177 
178  if( !i_size ) break;
179  }
180 
181  return VLC_SUCCESS;
182 }
183 
184 static inline int block_GetBytes( block_bytestream_t *p_bytestream,
185  uint8_t *p_data, size_t i_data )
186 {
187  if( block_BytestreamRemaining( p_bytestream ) < i_data )
188  return VLC_EGENERIC;
189 
190  /* Copy the data */
191  size_t i_offset = p_bytestream->i_block_offset;
192  size_t i_size = i_data;
193  size_t i_copy = 0;
194  block_t *p_block;
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 
201  if( i_copy && p_data != NULL )
202  {
203  memcpy( p_data, p_block->p_buffer + i_offset, i_copy );
204  p_data += i_copy;
205  }
206 
207  if( i_size == 0 )
208  break;
209 
210  p_bytestream->i_base_offset += p_block->i_buffer;
211  i_offset = 0;
212  }
213 
214  p_bytestream->p_block = p_block;
215  p_bytestream->i_block_offset = i_offset + i_copy;
216 
217  return VLC_SUCCESS;
218 }
219 
220 static inline int block_SkipBytes( block_bytestream_t *p_bytestream,
221  size_t i_data )
222 {
223  return block_GetBytes( p_bytestream, NULL, i_data );
224 }
225 
226 static inline int block_SkipByte( block_bytestream_t *p_bytestream )
227 {
228  return block_GetBytes( p_bytestream, NULL, 1 );
229 }
230 
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 )
233 {
234  const size_t i_remain = block_BytestreamRemaining( p_bytestream );
235  if( i_remain < i_data + i_peek_offset )
236  return VLC_EGENERIC;
237 
238  /* Find the right place */
239  size_t i_offset = p_bytestream->i_block_offset;
240  size_t i_size = i_peek_offset;
241  size_t i_copy = 0;
242  block_t *p_block;
243  for( p_block = p_bytestream->p_block;
244  p_block != NULL; p_block = p_block->p_next )
245  {
246  i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
247  i_size -= i_copy;
248 
249  if( !i_size ) break;
250 
251  i_offset = 0;
252  }
253 
254  /* Copy the data */
255  i_offset += i_copy;
256  i_size = i_data;
257  for( ; p_block != NULL; p_block = p_block->p_next )
258  {
259  i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
260  i_size -= i_copy;
261 
262  if( i_copy )
263  {
264  memcpy( p_data, p_block->p_buffer + i_offset, i_copy );
265  p_data += i_copy;
266  }
267 
268  i_offset = 0;
269 
270  if( !i_size ) break;
271  }
272 
273  return VLC_SUCCESS;
274 }
275 
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 * );
278 
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 )
284 {
285  block_t *p_block, *p_block_backup = 0;
286  ssize_t i_size = 0;
287  size_t i_offset, i_offset_backup = 0;
288  int i_caller_offset_backup = 0, i_match;
289 
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 )
294  {
295  i_size -= p_block->i_buffer;
296  if( i_size < 0 ) break;
297  }
298 
299  if( unlikely( i_size >= 0 ) )
300  {
301  /* Not enough data, bail out */
302  return VLC_EGENERIC;
303  }
304 
305  /* Begin the search.
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;
310  i_match = 0;
311  for( ; p_block != NULL; p_block = p_block->p_next )
312  {
313  for( i_offset = i_size; i_offset < p_block->i_buffer; i_offset++ )
314  {
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) )
318  {
319  const uint8_t *p_res = p_startcode_helper( &p_block->p_buffer[i_offset],
320  &p_block->p_buffer[p_block->i_buffer] );
321  if( p_res )
322  {
323  *pi_offset += i_offset + (p_res - &p_block->p_buffer[i_offset]);
324  return VLC_SUCCESS;
325  }
326  /* Then parsing boundary with legacy code */
327  i_offset = p_block->i_buffer - (i_startcode_length - 1);
328  }
329 
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];
333  if( b_matched )
334  {
335  if( i_match == 0 )
336  {
337  p_block_backup = p_block;
338  i_offset_backup = i_offset;
339  i_caller_offset_backup = *pi_offset;
340  }
341 
342  if( i_match + 1 == i_startcode_length )
343  {
344  /* We have it */
345  *pi_offset += i_offset - i_match;
346  return VLC_SUCCESS;
347  }
348 
349  i_match++;
350  }
351  else if ( i_match > 0 )
352  {
353  /* False positive */
354  p_block = p_block_backup;
355  i_offset = i_offset_backup;
356  *pi_offset = i_caller_offset_backup;
357  i_match = 0;
358  }
359 
360  }
361  i_size = 0;
362  *pi_offset += i_offset;
363  }
364 
365  *pi_offset -= i_match;
366  return VLC_EGENERIC;
367 }
368 
369 #endif /* VLC_BLOCK_HELPER_H */
block_PeekBytes
static int block_PeekBytes(block_bytestream_t *p_bytestream, uint8_t *p_data, size_t i_data)
Definition: vlc_block_helper.h:156
block_ChainRelease
static void block_ChainRelease(block_t *p_block)
Definition: vlc_block.h:358
block_SkipByte
static int block_SkipByte(block_bytestream_t *p_bytestream)
Definition: vlc_block_helper.h:227
unlikely
#define unlikely(p)
Predicted false condition.
Definition: vlc_common.h:227
vlc_common.h
block_t::i_buffer
size_t i_buffer
Payload length.
Definition: vlc_block.h:122
block_BytestreamEmpty
static void block_BytestreamEmpty(block_bytestream_t *p_bytestream)
It flush all data (read and unread) from a block_bytestream_t.
Definition: vlc_block_helper.h:59
block_bytestream_t
Definition: vlc_block_helper.h:29
block_BytestreamRemaining
static size_t block_BytestreamRemaining(const block_bytestream_t *p_bytestream)
Definition: vlc_block_helper.h:106
block_GetBytes
static int block_GetBytes(block_bytestream_t *p_bytestream, uint8_t *p_data, size_t i_data)
Definition: vlc_block_helper.h:185
block_BytestreamRelease
static void block_BytestreamRelease(block_bytestream_t *p_bytestream)
Definition: vlc_block_helper.h:51
VLC_EGENERIC
#define VLC_EGENERIC
Unspecified error.
Definition: vlc_common.h:474
block_startcode_matcher_t
bool(* block_startcode_matcher_t)(uint8_t, size_t, const uint8_t *)
Definition: vlc_block_helper.h:278
block_SkipBytes
static int block_SkipBytes(block_bytestream_t *p_bytestream, size_t i_data)
Definition: vlc_block_helper.h:221
block_FindStartcodeFromOffset
static int block_FindStartcodeFromOffset(block_bytestream_t *p_bytestream, size_t *pi_offset, const uint8_t *p_startcode, int i_startcode_length, block_startcode_helper_t p_startcode_helper, block_startcode_matcher_t p_startcode_matcher)
Definition: vlc_block_helper.h:280
block_t::p_next
block_t * p_next
Definition: vlc_block.h:119
block_bytestream_t::p_chain
block_t * p_chain
byte stream head block
Definition: vlc_block_helper.h:51
block_bytestream_t::pp_last
block_t ** pp_last
tail ppointer for appends
Definition: vlc_block_helper.h:52
block_BytestreamPush
static void block_BytestreamPush(block_bytestream_t *p_bytestream, block_t *p_block)
Definition: vlc_block_helper.h:97
block_BytestreamPop
static block_t * block_BytestreamPop(block_bytestream_t *p_bytestream)
Definition: vlc_block_helper.h:113
block_bytestream_t::p_block
block_t * p_block
byte stream read pointer block
Definition: vlc_block_helper.h:53
block_ChainLastAppend
static void block_ChainLastAppend(block_t ***ppp_last, block_t *p_block)
Definition: vlc_block.h:348
block_BytestreamInit
static void block_BytestreamInit(block_bytestream_t *p_bytestream)
Definition: vlc_block_helper.h:42
block_bytestream_t
struct block_bytestream_t block_bytestream_t
block_bytestream_t::i_base_offset
size_t i_base_offset
block base offset (previous blocks total size)
Definition: vlc_block_helper.h:55
VLC_SUCCESS
#define VLC_SUCCESS
No error.
Definition: vlc_common.h:472
block_bytestream_t::i_block_offset
size_t i_block_offset
byte stream read pointer offset within block
Definition: vlc_block_helper.h:54
block_startcode_helper_t
const typedef uint8_t *(* block_startcode_helper_t)(const uint8_t *, const uint8_t *)
Definition: vlc_block_helper.h:277
VLC_USED
#define VLC_USED
Definition: fourcc_gen.c:32
block_BytestreamFlush
static void block_BytestreamFlush(block_bytestream_t *p_bytestream)
It flushes all already read data from a block_bytestream_t.
Definition: vlc_block_helper.h:68
block_WaitBytes
static int block_WaitBytes(block_bytestream_t *p_bytestream, size_t i_data)
Definition: vlc_block_helper.h:148
vlc_block.h
block_PeekOffsetBytes
static int block_PeekOffsetBytes(block_bytestream_t *p_bytestream, size_t i_peek_offset, uint8_t *p_data, size_t i_data)
Definition: vlc_block_helper.h:232
block_t::p_buffer
uint8_t * p_buffer
Payload start.
Definition: vlc_block.h:121
block_bytestream_t::i_total
size_t i_total
total bytes over all linked blocks
Definition: vlc_block_helper.h:56
block_Release
void block_Release(block_t *block)
Releases a block.
Definition: block.c:135
block_t
Definition: vlc_block.h:117