1 /*****************************************************************************
2 * libasf.c : asf stream demux module for vlc
3 *****************************************************************************
4 * Copyright © 2001-2004, 2006-2008 VLC authors and VideoLAN
5 *
6 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7 * Gildas Bazin <gbazin@videolan.org>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <limits.h>
29
30 #include <vlc_demux.h>
31 #include <vlc_charset.h> /* FromCharset */
32
33 #include "libasf.h"
34
35 #ifndef NDEBUG
36 # define ASF_DEBUG 1
37 #endif
38
39 /* Helpers:
40 * They ensure that invalid reads will not create problems.
41 * They are expansion safe
42 * They make the following assumptions:
43 * const uint8_t *p_peek exists and points to the start of a buffer
44 * ssize_t i_peek the size of the buffer pointed to by p_peek
45 * const uint8_t *p_data exits and points to the data inside p_peek to be read.
46 */
47 /* ASF_HAVE(n):
48 * Check that n bytes can be read */
AsfObjectHelperHave(const uint8_t * p_peek,size_t i_peek,const uint8_t * p_current,size_t i_wanted)49 static inline bool AsfObjectHelperHave( const uint8_t *p_peek, size_t i_peek, const uint8_t *p_current, size_t i_wanted )
50 {
51 if( i_wanted > i_peek )
52 return false;
53 return &p_current[i_wanted] <= &p_peek[i_peek];
54 }
55 #define ASF_HAVE(n) AsfObjectHelperHave( p_peek, i_peek, p_data, n )
56
57 /* ASF_SKIP(n)
58 * Skip n bytes if possible */
AsfObjectHelperSkip(const uint8_t * p_peek,size_t i_peek,uint8_t ** pp_data,size_t i_wanted)59 static inline void AsfObjectHelperSkip( const uint8_t *p_peek, size_t i_peek, uint8_t **pp_data, size_t i_wanted )
60 {
61 if( AsfObjectHelperHave( p_peek, i_peek, *pp_data, i_wanted ) )
62 *pp_data += i_wanted;
63 else
64 *pp_data = (uint8_t*)&p_peek[i_peek];
65 }
66 #define ASF_SKIP(n) AsfObjectHelperSkip( p_peek, i_peek, (uint8_t**)&p_data, n )
67
68 /* ASF_READX()
69 * Read X byte if possible, else return 0 */
70 #define ASF_FUNCTION_READ_X(type, x, cmd ) \
71 static inline type AsfObjectHelperRead##x( const uint8_t *p_peek, size_t i_peek, uint8_t **pp_data ) { \
72 uint8_t *p_data = *pp_data; \
73 type i_ret = 0; \
74 if( ASF_HAVE(x) ) \
75 i_ret = cmd; \
76 ASF_SKIP(x); \
77 *pp_data = p_data; \
78 return i_ret; }
79 ASF_FUNCTION_READ_X( uint8_t, 1, *p_data )
80 ASF_FUNCTION_READ_X( uint16_t, 2, GetWLE(p_data) )
81 ASF_FUNCTION_READ_X( uint32_t, 4, GetDWLE(p_data) )
82 ASF_FUNCTION_READ_X( uint64_t, 8, GetQWLE(p_data) )
83 #define ASF_READ1() AsfObjectHelperRead1( p_peek, i_peek, (uint8_t**)&p_data )
84 #define ASF_READ2() AsfObjectHelperRead2( p_peek, i_peek, (uint8_t**)&p_data )
85 #define ASF_READ4() AsfObjectHelperRead4( p_peek, i_peek, (uint8_t**)&p_data )
86 #define ASF_READ8() AsfObjectHelperRead8( p_peek, i_peek, (uint8_t**)&p_data )
87
88 /* ASF_READS(n)
89 * Read a string of n/2 wchar long ie n bytes. Do a stupid conversion (suppose latin1)
90 * Return allocated "" if not possible */
AsfObjectHelperReadString(const uint8_t * p_peek,size_t i_peek,uint8_t ** pp_data,size_t i_size)91 static char *AsfObjectHelperReadString( const uint8_t *p_peek, size_t i_peek, uint8_t **pp_data, size_t i_size )
92 {
93 uint8_t *p_data = *pp_data;
94 char *psz_string = NULL;
95 if( ASF_HAVE(i_size) )
96 {
97 psz_string = FromCharset( "UTF-16LE", p_data, i_size );
98 }
99 ASF_SKIP(i_size);
100 *pp_data = p_data;
101 return psz_string;
102 }
103 #define ASF_READS(n) AsfObjectHelperReadString( p_peek, i_peek, (uint8_t**)&p_data, n )
104
105 /****************************************************************************
106 *
107 ****************************************************************************/
108 static int ASF_ReadObject( stream_t *, asf_object_t *, asf_object_t * );
109
110 /****************************************************************************
111 *
112 ****************************************************************************/
ASF_ReadObjectCommon(stream_t * s,asf_object_t * p_obj)113 static int ASF_ReadObjectCommon( stream_t *s, asf_object_t *p_obj )
114 {
115 asf_object_common_t *p_common = &p_obj->common;
116 const uint8_t *p_peek;
117
118 if( vlc_stream_Peek( s, &p_peek, ASF_OBJECT_COMMON_SIZE ) < ASF_OBJECT_COMMON_SIZE )
119 return VLC_EGENERIC;
120
121 ASF_GetGUID( &p_common->i_object_id, p_peek );
122 p_common->i_object_size = GetQWLE( p_peek + 16 );
123 p_common->i_object_pos = vlc_stream_Tell( s );
124 p_common->p_next = NULL;
125
126 #ifdef ASF_DEBUG
127 msg_Dbg( s,
128 "found object guid: " GUID_FMT " size:%"PRId64" at %"PRId64,
129 GUID_PRINT( p_common->i_object_id ),
130 p_common->i_object_size, p_common->i_object_pos );
131 #endif
132
133 return VLC_SUCCESS;
134 }
135
ASF_NextObject(stream_t * s,asf_object_t * p_obj,uint64_t i_boundary)136 static int ASF_NextObject( stream_t *s, asf_object_t *p_obj, uint64_t i_boundary )
137 {
138 asf_object_t obj;
139
140 int64_t i_pos = vlc_stream_Tell( s );
141 if ( i_boundary && i_pos >= 0 && (uint64_t) i_pos >= i_boundary )
142 {
143 return VLC_EGENERIC;
144 }
145
146 if( p_obj == NULL )
147 {
148 if( ASF_ReadObjectCommon( s, &obj ) )
149 return VLC_EGENERIC;
150
151 p_obj = &obj;
152 }
153
154 if( p_obj->common.i_object_size <= 0 )
155 return VLC_EGENERIC;
156
157 if( ( UINT64_MAX - p_obj->common.i_object_pos ) < p_obj->common.i_object_size )
158 return VLC_EGENERIC;
159
160 if( p_obj->common.p_father &&
161 p_obj->common.p_father->common.i_object_size != 0 )
162 {
163 if( p_obj->common.p_father->common.i_object_pos +
164 p_obj->common.p_father->common.i_object_size <
165 p_obj->common.i_object_pos + p_obj->common.i_object_size + ASF_OBJECT_COMMON_SIZE )
166 /* ASF_OBJECT_COMMON_SIZE is min size of an object */
167 {
168 return VLC_EGENERIC;
169 }
170
171 }
172
173 return vlc_stream_Seek( s, p_obj->common.i_object_pos +
174 p_obj->common.i_object_size );
175 }
176
ASF_FreeObject_Null(asf_object_t * pp_obj)177 static void ASF_FreeObject_Null( asf_object_t *pp_obj )
178 {
179 VLC_UNUSED(pp_obj);
180 }
181
ASF_ReadObject_Header(stream_t * s,asf_object_t * p_obj)182 static int ASF_ReadObject_Header( stream_t *s, asf_object_t *p_obj )
183 {
184 asf_object_header_t *p_hdr = &p_obj->header;
185 asf_object_t *p_subobj;
186 const uint8_t *p_peek;
187
188 if( vlc_stream_Peek( s, &p_peek, 30 ) < 30 )
189 return VLC_EGENERIC;
190
191 p_hdr->i_sub_object_count = GetDWLE( p_peek + ASF_OBJECT_COMMON_SIZE );
192 p_hdr->i_reserved1 = p_peek[28];
193 p_hdr->i_reserved2 = p_peek[29];
194 p_hdr->p_first = NULL;
195 p_hdr->p_last = NULL;
196
197 #ifdef ASF_DEBUG
198 msg_Dbg( s,
199 "read \"header object\" subobj:%d, reserved1:%d, reserved2:%d",
200 p_hdr->i_sub_object_count,
201 p_hdr->i_reserved1,
202 p_hdr->i_reserved2 );
203 #endif
204
205 if( vlc_stream_Read( s, NULL, 30 ) != 30 )
206 return VLC_EGENERIC;
207
208 /* Now load sub object */
209 for( ; ; )
210 {
211 p_subobj = malloc( sizeof( asf_object_t ) );
212
213 if( !p_subobj || ASF_ReadObject( s, p_subobj, (asf_object_t*)p_hdr ) )
214 {
215 free( p_subobj );
216 break;
217 }
218 if( ASF_NextObject( s, p_subobj, 0 ) ) /* Go to the next object */
219 break;
220 }
221 return VLC_SUCCESS;
222 }
223
ASF_ReadObject_Data(stream_t * s,asf_object_t * p_obj)224 static int ASF_ReadObject_Data( stream_t *s, asf_object_t *p_obj )
225 {
226 asf_object_data_t *p_data = &p_obj->data;
227 const uint8_t *p_peek;
228
229 if( vlc_stream_Peek( s, &p_peek, 50 ) < 50 )
230 return VLC_EGENERIC;
231
232 ASF_GetGUID( &p_data->i_file_id, p_peek + ASF_OBJECT_COMMON_SIZE );
233 p_data->i_total_data_packets = GetQWLE( p_peek + 40 );
234 p_data->i_reserved = GetWLE( p_peek + 48 );
235
236 #ifdef ASF_DEBUG
237 msg_Dbg( s,
238 "read \"data object\" file_id:" GUID_FMT " total data packet:"
239 "%"PRId64" reserved:%d",
240 GUID_PRINT( p_data->i_file_id ),
241 p_data->i_total_data_packets,
242 p_data->i_reserved );
243 #endif
244
245 return VLC_SUCCESS;
246 }
247
ASF_ReadObject_Index(stream_t * s,asf_object_t * p_obj)248 static int ASF_ReadObject_Index( stream_t *s, asf_object_t *p_obj )
249 {
250 asf_object_index_t *p_index = &p_obj->index;
251 const uint8_t *p_peek;
252 unsigned int i;
253
254 /* We just ignore error on the index */
255 if( p_index->i_object_size < 56
256 || p_index->i_object_size > INT32_MAX
257 || vlc_stream_Peek( s, &p_peek, p_index->i_object_size )
258 < (int64_t)p_index->i_object_size )
259 return VLC_SUCCESS;
260
261 ASF_GetGUID( &p_index->i_file_id, p_peek + ASF_OBJECT_COMMON_SIZE );
262 p_index->i_index_entry_time_interval = GetQWLE( p_peek + 40 );
263 p_index->i_max_packet_count = GetDWLE( p_peek + 48 );
264 p_index->i_index_entry_count = GetDWLE( p_peek + 52 );
265 p_index->index_entry = NULL;
266
267 #ifdef ASF_DEBUG
268 msg_Dbg( s,
269 "read \"index object\" file_id:" GUID_FMT
270 " index_entry_time_interval:%"PRId64" max_packet_count:%d "
271 "index_entry_count:%ld",
272 GUID_PRINT( p_index->i_file_id ),
273 p_index->i_index_entry_time_interval,
274 p_index->i_max_packet_count,
275 (long int)p_index->i_index_entry_count );
276 #endif
277
278 /* Sanity checking */
279 if( !p_index->i_index_entry_time_interval )
280 {
281 /* We can't use this index if it has an invalid time interval */
282 p_index->i_index_entry_count = 0;
283 return VLC_ENOMEM;
284 }
285 if( p_index->i_index_entry_count > (p_index->i_object_size - 56) / 6 )
286 p_index->i_index_entry_count = (p_index->i_object_size - 56) / 6;
287
288 p_index->index_entry = calloc( p_index->i_index_entry_count,
289 sizeof(asf_index_entry_t) );
290 if( !p_index->index_entry )
291 {
292 p_index->i_index_entry_count = 0;
293 return VLC_ENOMEM;
294 }
295
296 for( i = 0, p_peek += 56; i < p_index->i_index_entry_count; i++, p_peek += 6 )
297 {
298 p_index->index_entry[i].i_packet_number = GetDWLE( p_peek );
299 p_index->index_entry[i].i_packet_count = GetWLE( p_peek + 4 );
300 }
301
302 return VLC_SUCCESS;
303 }
304
ASF_FreeObject_Index(asf_object_t * p_obj)305 static void ASF_FreeObject_Index( asf_object_t *p_obj )
306 {
307 asf_object_index_t *p_index = &p_obj->index;
308
309 FREENULL( p_index->index_entry );
310 }
311
ASF_ReadObject_file_properties(stream_t * s,asf_object_t * p_obj)312 static int ASF_ReadObject_file_properties( stream_t *s, asf_object_t *p_obj )
313 {
314 asf_object_file_properties_t *p_fp = &p_obj->file_properties;
315 const uint8_t *p_peek;
316
317 if( vlc_stream_Peek( s, &p_peek, 104 ) < 104 )
318 return VLC_EGENERIC;
319
320 ASF_GetGUID( &p_fp->i_file_id, p_peek + ASF_OBJECT_COMMON_SIZE );
321 p_fp->i_file_size = GetQWLE( p_peek + 40 );
322 p_fp->i_creation_date = GetQWLE( p_peek + 48 );
323 p_fp->i_data_packets_count = GetQWLE( p_peek + 56 );
324 p_fp->i_play_duration = GetQWLE( p_peek + 64 );
325 p_fp->i_send_duration = GetQWLE( p_peek + 72 );
326 p_fp->i_preroll = GetQWLE( p_peek + 80 );
327 p_fp->i_flags = GetDWLE( p_peek + 88 );
328 p_fp->i_min_data_packet_size = __MAX( GetDWLE( p_peek + 92 ), (uint32_t) 1 );
329 p_fp->i_max_data_packet_size = __MAX( GetDWLE( p_peek + 96 ), (uint32_t) 1 );
330 p_fp->i_max_bitrate = GetDWLE( p_peek + 100 );
331
332 #ifdef ASF_DEBUG
333 msg_Dbg( s,
334 "read \"file properties object\" file_id:" GUID_FMT
335 " file_size:%"PRId64" creation_date:%"PRId64" data_packets_count:"
336 "%"PRId64" play_duration:%"PRId64" send_duration:%"PRId64" preroll:%"PRId64
337 " flags:%d min_data_packet_size:%d "
338 " max_data_packet_size:%d max_bitrate:%d",
339 GUID_PRINT( p_fp->i_file_id ), p_fp->i_file_size,
340 p_fp->i_creation_date, p_fp->i_data_packets_count,
341 p_fp->i_play_duration, p_fp->i_send_duration,
342 p_fp->i_preroll, p_fp->i_flags,
343 p_fp->i_min_data_packet_size, p_fp->i_max_data_packet_size,
344 p_fp->i_max_bitrate );
345 #endif
346
347 return VLC_SUCCESS;
348 }
349
ASF_FreeObject_metadata(asf_object_t * p_obj)350 static void ASF_FreeObject_metadata( asf_object_t *p_obj )
351 {
352 asf_object_metadata_t *p_meta = &p_obj->metadata;
353
354 for( uint32_t i = 0; i < p_meta->i_record_entries_count; i++ )
355 {
356 free( p_meta->record[i].psz_name );
357 free( p_meta->record[i].p_data );
358 }
359 free( p_meta->record );
360 }
361
ASF_ReadObject_metadata(stream_t * s,asf_object_t * p_obj)362 static int ASF_ReadObject_metadata( stream_t *s, asf_object_t *p_obj )
363 {
364 asf_object_metadata_t *p_meta = &p_obj->metadata;
365
366 uint32_t i;
367 const uint8_t *p_peek, *p_data;
368
369 if( p_meta->i_object_size < 26 || p_meta->i_object_size > INT32_MAX )
370 return VLC_EGENERIC;
371
372 ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_meta->i_object_size );
373 if( i_peek < (int64_t)p_meta->i_object_size )
374 return VLC_EGENERIC;
375
376 p_meta->i_record_entries_count = GetWLE( p_peek + ASF_OBJECT_COMMON_SIZE );
377
378 p_data = p_peek + 26;
379
380 p_meta->record = calloc( p_meta->i_record_entries_count,
381 sizeof(asf_metadata_record_t) );
382 if( !p_meta->record )
383 {
384 p_meta->i_record_entries_count = 0;
385 return VLC_ENOMEM;
386 }
387
388 for( i = 0; i < p_meta->i_record_entries_count; i++ )
389 {
390 asf_metadata_record_t *p_record = &p_meta->record[i];
391 uint16_t i_name;
392 uint32_t i_data;
393
394 if( !ASF_HAVE( 2+2+2+2+4 ) )
395 break;
396
397 if( ASF_READ2() != 0 )
398 break;
399
400 p_record->i_stream = ASF_READ2();
401 i_name = ASF_READ2();
402 p_record->i_type = ASF_READ2();
403 i_data = ASF_READ4();
404
405 if( UINT32_MAX - i_name < i_data ||
406 !ASF_HAVE( i_name + i_data ) )
407 break;
408
409 /* Read name */
410 p_record->psz_name = ASF_READS( i_name );
411
412 /* Read data */
413 if( p_record->i_type == ASF_METADATA_TYPE_STRING )
414 {
415 p_record->p_data = (uint8_t *)ASF_READS( i_data );
416 if( p_record->p_data )
417 p_record->i_data = i_data/2; /* FIXME Is that needed ? */
418 }
419 else if( p_record->i_type == ASF_METADATA_TYPE_BYTE )
420 {
421 p_record->p_data = malloc( i_data );
422 if( p_record->p_data )
423 {
424 p_record->i_data = i_data;
425 if( p_record->p_data && i_data > 0 )
426 memcpy( p_record->p_data, p_data, i_data );
427 }
428 p_data += i_data;
429 }
430 else if( p_record->i_type == ASF_METADATA_TYPE_QWORD )
431 {
432 p_record->i_val = ASF_READ8();
433 }
434 else if( p_record->i_type == ASF_METADATA_TYPE_DWORD )
435 {
436 p_record->i_val = ASF_READ4();
437 }
438 else if( p_record->i_type == ASF_METADATA_TYPE_WORD )
439 {
440 p_record->i_val = ASF_READ2();
441 }
442 else if( p_record->i_type == ASF_METADATA_TYPE_BOOL )
443 {
444 p_record->i_val = ASF_READ2();
445 }
446 else
447 {
448 /* Unknown */
449 p_data += i_data;
450 }
451 }
452 p_meta->i_record_entries_count = i;
453
454 #ifdef ASF_DEBUG
455 msg_Dbg( s,
456 "read \"metadata object\" %"PRIu32" entries",
457 p_meta->i_record_entries_count );
458 for( uint32_t j = 0; j < p_meta->i_record_entries_count; j++ )
459 {
460 asf_metadata_record_t *p_rec = &p_meta->record[j];
461
462 if( p_rec->i_type == ASF_METADATA_TYPE_STRING )
463 msg_Dbg( s, " - %s=%s",
464 p_rec->psz_name, p_rec->p_data );
465 else if( p_rec->i_type == ASF_METADATA_TYPE_BYTE )
466 msg_Dbg( s, " - %s (%u bytes)",
467 p_rec->psz_name, p_rec->i_data );
468 else
469 msg_Dbg( s, " - %s=%"PRIu64,
470 p_rec->psz_name, p_rec->i_val );
471 }
472 #endif
473
474 return VLC_SUCCESS;
475 }
476
ASF_ReadObject_header_extension(stream_t * s,asf_object_t * p_obj)477 static int ASF_ReadObject_header_extension( stream_t *s, asf_object_t *p_obj )
478 {
479 asf_object_header_extension_t *p_he = &p_obj->header_extension;
480 const uint8_t *p_peek;
481
482 if( p_he->i_object_size > INT32_MAX )
483 return VLC_EGENERIC;
484
485 ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_he->i_object_size );
486 if( i_peek < 46 )
487 return VLC_EGENERIC;
488
489 ASF_GetGUID( &p_he->i_reserved1, p_peek + ASF_OBJECT_COMMON_SIZE );
490 p_he->i_reserved2 = GetWLE( p_peek + 40 );
491 p_he->i_header_extension_size = GetDWLE( p_peek + 42 );
492 if( p_he->i_header_extension_size )
493 {
494 if( (unsigned int)(i_peek-46) < p_he->i_header_extension_size )
495 return VLC_EGENERIC;
496
497 p_he->p_header_extension_data =
498 malloc( p_he->i_header_extension_size );
499 if( !p_he->p_header_extension_data )
500 return VLC_ENOMEM;
501
502 memcpy( p_he->p_header_extension_data, p_peek + 46,
503 p_he->i_header_extension_size );
504 }
505 else
506 {
507 p_he->p_header_extension_data = NULL;
508 p_he->i_header_extension_size = 0;
509 }
510
511 #ifdef ASF_DEBUG
512 msg_Dbg( s,
513 "read \"header extension object\" reserved1:" GUID_FMT
514 " reserved2:%u header_extension_size:%"PRIu32,
515 GUID_PRINT( p_he->i_reserved1 ), p_he->i_reserved2,
516 p_he->i_header_extension_size );
517 #endif
518
519 if( !p_he->i_header_extension_size ) return VLC_SUCCESS;
520
521 /* Read the extension objects */
522 if( vlc_stream_Read( s, NULL, 46 ) != 46 )
523 {
524 free( p_he->p_header_extension_data );
525 return VLC_EGENERIC;
526 }
527
528 for( ; ; )
529 {
530 asf_object_t *p_child = malloc( sizeof( asf_object_t ) );
531
532 if( p_child == NULL
533 || ASF_ReadObject( s, p_child, (asf_object_t*)p_he ) )
534 {
535 free( p_child );
536 break;
537 }
538
539 if( ASF_NextObject( s, p_child, 0 ) ) /* Go to the next object */
540 {
541 break;
542 }
543 }
544
545 return VLC_SUCCESS;
546 }
547
ASF_FreeObject_header_extension(asf_object_t * p_obj)548 static void ASF_FreeObject_header_extension( asf_object_t *p_obj )
549 {
550 asf_object_header_extension_t *p_he = &p_obj->header_extension;
551
552 FREENULL( p_he->p_header_extension_data );
553 }
554
ASF_ReadObject_stream_properties(stream_t * s,asf_object_t * p_obj)555 static int ASF_ReadObject_stream_properties( stream_t *s, asf_object_t *p_obj )
556 {
557 asf_object_stream_properties_t *p_sp = &p_obj->stream_properties;
558 const uint8_t *p_peek;
559
560 #if UINT64_MAX > SSIZE_MAX
561 if( p_sp->i_object_size > SSIZE_MAX )
562 {
563 msg_Err( s, "unable to peek: object size is too large" );
564 return VLC_EGENERIC;
565 }
566 #endif
567
568 if( p_sp->i_object_size > INT32_MAX )
569 return VLC_EGENERIC;
570
571 ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_sp->i_object_size );
572 if( i_peek < 78 )
573 return VLC_EGENERIC;
574
575 ASF_GetGUID( &p_sp->i_stream_type, p_peek + ASF_OBJECT_COMMON_SIZE );
576 ASF_GetGUID( &p_sp->i_error_correction_type, p_peek + 40 );
577 p_sp->i_time_offset = GetQWLE( p_peek + 56 );
578 p_sp->i_type_specific_data_length = GetDWLE( p_peek + 64 );
579 p_sp->i_error_correction_data_length = GetDWLE( p_peek + 68 );
580 p_sp->i_flags = GetWLE( p_peek + 72 );
581 p_sp->i_stream_number = p_sp->i_flags&0x07f;
582 if ( p_sp->i_stream_number > ASF_MAX_STREAMNUMBER )
583 return VLC_EGENERIC;
584 p_sp->i_reserved = GetDWLE( p_peek + 74 );
585 i_peek -= 78;
586
587 if( p_sp->i_type_specific_data_length )
588 {
589 if( i_peek < p_sp->i_type_specific_data_length )
590 return VLC_EGENERIC;
591
592 p_sp->p_type_specific_data =
593 malloc( p_sp->i_type_specific_data_length );
594 if( !p_sp->p_type_specific_data )
595 return VLC_ENOMEM;
596
597 memcpy( p_sp->p_type_specific_data, p_peek + 78,
598 p_sp->i_type_specific_data_length );
599 i_peek -= p_sp->i_type_specific_data_length;
600 }
601
602 if( p_sp->i_error_correction_data_length )
603 {
604 if( i_peek < p_sp->i_error_correction_data_length )
605 {
606 free( p_sp->p_type_specific_data );
607 return VLC_EGENERIC;
608 }
609
610 p_sp->p_error_correction_data =
611 malloc( p_sp->i_error_correction_data_length );
612 if( !p_sp->p_error_correction_data )
613 {
614 free( p_sp->p_type_specific_data );
615 return VLC_ENOMEM;
616 }
617 memcpy( p_sp->p_error_correction_data,
618 p_peek + 78 + p_sp->i_type_specific_data_length,
619 p_sp->i_error_correction_data_length );
620 }
621
622 #ifdef ASF_DEBUG
623 msg_Dbg( s,
624 "read \"stream Properties object\" stream_type:" GUID_FMT
625 " error_correction_type:" GUID_FMT " time_offset:%"PRIu64
626 " type_specific_data_length:%"PRIu32" error_correction_data_length:%"PRIu32
627 " flags:0x%x stream_number:%d",
628 GUID_PRINT( p_sp->i_stream_type ),
629 GUID_PRINT( p_sp->i_error_correction_type ),
630 p_sp->i_time_offset,
631 p_sp->i_type_specific_data_length,
632 p_sp->i_error_correction_data_length,
633 p_sp->i_flags,
634 p_sp->i_stream_number );
635
636 #endif
637 return VLC_SUCCESS;
638 }
639
ASF_FreeObject_stream_properties(asf_object_t * p_obj)640 static void ASF_FreeObject_stream_properties( asf_object_t *p_obj )
641 {
642 asf_object_stream_properties_t *p_sp = &p_obj->stream_properties;
643
644 FREENULL( p_sp->p_type_specific_data );
645 FREENULL( p_sp->p_error_correction_data );
646 }
647
ASF_FreeObject_codec_list(asf_object_t * p_obj)648 static void ASF_FreeObject_codec_list( asf_object_t *p_obj )
649 {
650 asf_object_codec_list_t *p_cl = &p_obj->codec_list;
651
652 for( asf_codec_entry_t *codec = p_cl->codecs, *next;
653 codec != NULL;
654 codec = next )
655 {
656 next = codec->p_next;
657 free( codec->psz_name );
658 free( codec->psz_description );
659 free( codec->p_information );
660 free( codec );
661 }
662 }
663
ASF_ReadObject_codec_list(stream_t * s,asf_object_t * p_obj)664 static int ASF_ReadObject_codec_list( stream_t *s, asf_object_t *p_obj )
665 {
666 asf_object_codec_list_t *p_cl = &p_obj->codec_list;
667 const uint8_t *p_peek, *p_data;
668
669 if( p_cl->i_object_size > INT32_MAX )
670 return VLC_EGENERIC;
671
672 ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_cl->i_object_size );
673 if( i_peek < 44 )
674 return VLC_EGENERIC;
675
676 ASF_GetGUID( &p_cl->i_reserved, p_peek + ASF_OBJECT_COMMON_SIZE );
677 uint32_t count = GetDWLE( p_peek + 40 );
678 #ifdef ASF_DEBUG
679 msg_Dbg( s, "read \"codec list object\" reserved_guid:" GUID_FMT
680 " codec_entries_count:%d", GUID_PRINT( p_cl->i_reserved ),
681 count );
682 #endif
683
684 p_data = p_peek + 44;
685
686 asf_codec_entry_t **pp = &p_cl->codecs;
687
688 for( uint32_t i = 0; i < count; i++ )
689 {
690 asf_codec_entry_t *p_codec = malloc( sizeof( *p_codec ) );
691
692 if( unlikely(p_codec == NULL) || !ASF_HAVE( 2+2+2 ) )
693 {
694 free( p_codec );
695 *pp = NULL;
696 goto error;
697 }
698
699 /* */
700 p_codec->i_type = ASF_READ2();
701
702 /* XXX the length here are the number of *unicode* characters and
703 * not of bytes like nearly every elsewhere */
704
705 /* codec name */
706 p_codec->psz_name = ASF_READS( 2*ASF_READ2() );
707
708 /* description */
709 p_codec->psz_description = ASF_READS( 2*ASF_READ2() );
710
711 /* opaque information */
712 p_codec->i_information_length = ASF_READ2();
713 if( ASF_HAVE( p_codec->i_information_length ) )
714 {
715 p_codec->p_information = malloc( p_codec->i_information_length );
716 if( likely(p_codec->p_information != NULL) )
717 memcpy( p_codec->p_information, p_data,
718 p_codec->i_information_length );
719 p_data += p_codec->i_information_length;
720 }
721 else
722 p_codec->p_information = NULL;
723
724 #ifdef ASF_DEBUG
725 msg_Dbg( s, " - codec[%"PRIu32"] %s name:\"%s\" "
726 "description:\"%s\" information_length:%u", i,
727 ( p_codec->i_type == ASF_CODEC_TYPE_VIDEO ) ? "video"
728 : ( ( p_codec->i_type == ASF_CODEC_TYPE_AUDIO ) ? "audio"
729 : "unknown" ), p_codec->psz_name,
730 p_codec->psz_description, p_codec->i_information_length );
731 #endif
732 *pp = p_codec;
733 pp = &p_codec->p_next;
734 }
735
736 *pp = NULL;
737 return VLC_SUCCESS;
738
739 error:
740 ASF_FreeObject_codec_list( p_obj );
741 return VLC_EGENERIC;
742 }
743
get_wstring(const uint8_t * p_data,size_t i_size)744 static inline char *get_wstring( const uint8_t *p_data, size_t i_size )
745 {
746 char *psz_str = FromCharset( "UTF-16LE", p_data, i_size );
747 if( psz_str )
748 p_data += i_size;
749 return psz_str;
750 }
751
752 /* Microsoft should go to hell. This time the length give number of bytes
753 * and for the some others object, length give char16 count ... */
ASF_ReadObject_content_description(stream_t * s,asf_object_t * p_obj)754 static int ASF_ReadObject_content_description(stream_t *s, asf_object_t *p_obj)
755 {
756 asf_object_content_description_t *p_cd = &p_obj->content_description;
757 const uint8_t *p_peek, *p_data;
758 uint16_t i_title, i_artist, i_copyright, i_description, i_rating;
759
760 if( p_cd->i_object_size > INT32_MAX )
761 return VLC_EGENERIC;
762
763 ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_cd->i_object_size );
764 if( i_peek < 34 )
765 return VLC_EGENERIC;
766
767 p_data = p_peek + ASF_OBJECT_COMMON_SIZE;
768
769 i_title = ASF_READ2();
770 i_artist = ASF_READ2();
771 i_copyright = ASF_READ2();
772 i_description = ASF_READ2();
773 i_rating = ASF_READ2();
774
775 if( !ASF_HAVE( i_title+i_artist+i_copyright+i_description+i_rating ) )
776 return VLC_EGENERIC;
777
778 p_cd->psz_title = get_wstring( p_data, i_title );
779 p_cd->psz_artist = get_wstring( p_data, i_artist );
780 p_cd->psz_copyright = get_wstring( p_data, i_copyright );
781 p_cd->psz_description = get_wstring( p_data, i_description );
782 p_cd->psz_rating = get_wstring( p_data, i_rating );
783
784 #ifdef ASF_DEBUG
785 msg_Dbg( s,
786 "read \"content description object\" title:\"%s\" artist:\"%s\" copyright:\"%s\" description:\"%s\" rating:\"%s\"",
787 p_cd->psz_title,
788 p_cd->psz_artist,
789 p_cd->psz_copyright,
790 p_cd->psz_description,
791 p_cd->psz_rating );
792 #endif
793
794 return VLC_SUCCESS;
795 }
796
ASF_FreeObject_content_description(asf_object_t * p_obj)797 static void ASF_FreeObject_content_description( asf_object_t *p_obj)
798 {
799 asf_object_content_description_t *p_cd = &p_obj->content_description;
800
801 FREENULL( p_cd->psz_title );
802 FREENULL( p_cd->psz_artist );
803 FREENULL( p_cd->psz_copyright );
804 FREENULL( p_cd->psz_description );
805 FREENULL( p_cd->psz_rating );
806 }
807
808 /* Language list: */
ASF_ReadObject_language_list(stream_t * s,asf_object_t * p_obj)809 static int ASF_ReadObject_language_list(stream_t *s, asf_object_t *p_obj)
810 {
811 asf_object_language_list_t *p_ll = &p_obj->language_list;
812 const uint8_t *p_peek, *p_data;
813 uint16_t i;
814
815 if( p_ll->i_object_size > INT32_MAX )
816 return VLC_EGENERIC;
817
818 ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_ll->i_object_size );
819 if( i_peek < 26 )
820 return VLC_EGENERIC;
821
822 p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
823
824 p_ll->i_language = ASF_READ2();
825 if( p_ll->i_language > 0 )
826 {
827 p_ll->ppsz_language = calloc( p_ll->i_language, sizeof( char *) );
828 if( !p_ll->ppsz_language )
829 return VLC_ENOMEM;
830
831 for( i = 0; i < p_ll->i_language; i++ )
832 {
833 if( !ASF_HAVE(1) )
834 break;
835 p_ll->ppsz_language[i] = ASF_READS( ASF_READ1() );
836 }
837 p_ll->i_language = i;
838 }
839
840 #ifdef ASF_DEBUG
841 msg_Dbg( s, "read \"language list object\" %u entries",
842 p_ll->i_language );
843 for( i = 0; i < p_ll->i_language; i++ )
844 msg_Dbg( s, " - '%s'",
845 p_ll->ppsz_language[i] );
846 #endif
847 return VLC_SUCCESS;
848 }
849
ASF_FreeObject_language_list(asf_object_t * p_obj)850 static void ASF_FreeObject_language_list( asf_object_t *p_obj)
851 {
852 asf_object_language_list_t *p_ll = &p_obj->language_list;
853 uint16_t i;
854
855 for( i = 0; i < p_ll->i_language; i++ )
856 FREENULL( p_ll->ppsz_language[i] );
857 FREENULL( p_ll->ppsz_language );
858 }
859
860 /* Stream bitrate properties */
ASF_ReadObject_stream_bitrate_properties(stream_t * s,asf_object_t * p_obj)861 static int ASF_ReadObject_stream_bitrate_properties( stream_t *s,
862 asf_object_t *p_obj)
863 {
864 asf_object_stream_bitrate_properties_t *p_sb = &p_obj->stream_bitrate;
865 const uint8_t *p_peek, *p_data;
866 uint16_t i;
867
868 if( p_sb->i_object_size > INT32_MAX )
869 return VLC_EGENERIC;
870
871 ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_sb->i_object_size );
872 if( i_peek < 26 )
873 return VLC_EGENERIC;
874
875 p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
876
877 p_sb->i_bitrate = ASF_READ2();
878 if( p_sb->i_bitrate > ASF_MAX_STREAMNUMBER )
879 p_sb->i_bitrate = ASF_MAX_STREAMNUMBER; /* Buggy ? */
880 for( i = 0; i < p_sb->i_bitrate; i++ )
881 {
882 if( !ASF_HAVE(2 + 4) )
883 break;
884 p_sb->bitrate[i].i_stream_number = (uint8_t) ASF_READ2()& 0x7f;
885 if ( p_sb->bitrate[i].i_stream_number > ASF_MAX_STREAMNUMBER )
886 return VLC_EGENERIC;
887 p_sb->bitrate[i].i_avg_bitrate = ASF_READ4();
888 }
889 p_sb->i_bitrate = i;
890
891 #ifdef ASF_DEBUG
892 msg_Dbg( s,"read \"stream bitrate properties object\"" );
893 for( i = 0; i < p_sb->i_bitrate; i++ )
894 {
895 msg_Dbg( s," - stream=%u bitrate=%"PRIu32,
896 p_sb->bitrate[i].i_stream_number,
897 p_sb->bitrate[i].i_avg_bitrate );
898 }
899 #endif
900 return VLC_SUCCESS;
901 }
ASF_FreeObject_stream_bitrate_properties(asf_object_t * p_obj)902 static void ASF_FreeObject_stream_bitrate_properties( asf_object_t *p_obj)
903 {
904 VLC_UNUSED(p_obj);
905 }
906
ASF_FreeObject_extended_stream_properties(asf_object_t * p_obj)907 static void ASF_FreeObject_extended_stream_properties( asf_object_t *p_obj)
908 {
909 asf_object_extended_stream_properties_t *p_esp = &p_obj->ext_stream;
910
911 if ( p_esp->p_ext )
912 {
913 for( uint16_t i = 0; i < p_esp->i_payload_extension_system_count; i++ )
914 free( p_esp->p_ext[i].pi_info );
915 FREENULL( p_esp->p_ext );
916 }
917 for( uint16_t i = 0; i < p_esp->i_stream_name_count; i++ )
918 FREENULL( p_esp->ppsz_stream_name[i] );
919 FREENULL( p_esp->pi_stream_name_language );
920 FREENULL( p_esp->ppsz_stream_name );
921 }
922
ASF_ReadObject_extended_stream_properties(stream_t * s,asf_object_t * p_obj)923 static int ASF_ReadObject_extended_stream_properties( stream_t *s,
924 asf_object_t *p_obj)
925 {
926 asf_object_extended_stream_properties_t *p_esp = &p_obj->ext_stream;
927 const uint8_t *p_peek, *p_data;
928 uint16_t i;
929
930 if( p_esp->i_object_size > INT32_MAX )
931 return VLC_EGENERIC;
932
933 ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_esp->i_object_size );
934 if( i_peek < 88 )
935 return VLC_EGENERIC;
936
937 p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
938
939 p_esp->i_start_time = GetQWLE( &p_data[0] );
940 p_esp->i_end_time = GetQWLE( &p_data[8] );
941 p_esp->i_data_bitrate = GetDWLE( &p_data[16] );
942 p_esp->i_buffer_size = GetDWLE( &p_data[20] );
943 p_esp->i_initial_buffer_fullness = GetDWLE( &p_data[ASF_OBJECT_COMMON_SIZE] );
944 p_esp->i_alternate_data_bitrate = GetDWLE( &p_data[28] );
945 p_esp->i_alternate_buffer_size = GetDWLE( &p_data[32] );
946 p_esp->i_alternate_initial_buffer_fullness = GetDWLE( &p_data[36] );
947 p_esp->i_maximum_object_size = GetDWLE( &p_data[40] );
948 p_esp->i_flags = GetDWLE( &p_data[44] );
949 p_esp->i_stream_number = GetWLE( &p_data[48] );
950 if ( p_esp->i_stream_number > ASF_MAX_STREAMNUMBER )
951 return VLC_EGENERIC;
952 p_esp->i_language_index = GetWLE( &p_data[50] );
953 p_esp->i_average_time_per_frame= GetQWLE( &p_data[52] );
954 p_esp->i_stream_name_count = GetWLE( &p_data[60] );
955 p_esp->i_payload_extension_system_count = GetWLE( &p_data[62] );
956
957 p_data += 64;
958
959 p_esp->pi_stream_name_language = calloc( p_esp->i_stream_name_count,
960 sizeof(uint16_t) );
961 p_esp->ppsz_stream_name = calloc( p_esp->i_stream_name_count,
962 sizeof(char*) );
963 if( !p_esp->pi_stream_name_language ||
964 !p_esp->ppsz_stream_name )
965 {
966 free( p_esp->pi_stream_name_language );
967 free( p_esp->ppsz_stream_name );
968 return VLC_ENOMEM;
969 }
970 for( i = 0; i < p_esp->i_stream_name_count; i++ )
971 {
972 if( !ASF_HAVE( 2+2 ) )
973 break;
974 p_esp->pi_stream_name_language[i] = ASF_READ2();
975 p_esp->ppsz_stream_name[i] = ASF_READS( ASF_READ2() );
976 }
977 p_esp->i_stream_name_count = i;
978
979 p_esp->p_ext = calloc( p_esp->i_payload_extension_system_count,
980 sizeof( asf_payload_extension_system_t ) );
981 if ( p_esp->p_ext )
982 {
983 for( i = 0; i < p_esp->i_payload_extension_system_count; i++ )
984 {
985 asf_payload_extension_system_t *p_ext = & p_esp->p_ext[i];
986 if( !ASF_HAVE( 16+2+4 ) ) break;
987 ASF_GetGUID( &p_ext->i_extension_id, p_data );
988 ASF_SKIP( 16 ); // GUID
989 p_ext->i_data_size = ASF_READ2();
990 p_ext->i_info_length = ASF_READ4();
991 if ( p_ext->i_info_length )
992 {
993 if( !ASF_HAVE( p_ext->i_info_length ) ) break;
994 p_ext->pi_info = malloc( p_ext->i_info_length );
995 if ( p_ext->pi_info )
996 memcpy( p_ext->pi_info, p_data, p_ext->i_info_length );
997 ASF_SKIP( p_ext->i_info_length );
998 }
999 }
1000 p_esp->i_payload_extension_system_count = i;
1001 } else p_esp->i_payload_extension_system_count = 0;
1002
1003 p_esp->p_sp = NULL;
1004
1005 /* Read tail objects */
1006 if( p_data < &p_peek[i_peek] )
1007 {
1008 if( vlc_stream_Read( s, NULL, p_data - p_peek ) != (p_data - p_peek) )
1009 {
1010 ASF_FreeObject_extended_stream_properties( p_obj );
1011 return VLC_EGENERIC;
1012 }
1013
1014 asf_object_t *p_sp = malloc( sizeof( asf_object_t ) );
1015 if( !p_sp || ASF_ReadObject( s, p_sp, NULL ) )
1016 {
1017 free( p_sp );
1018 }
1019 else
1020 {
1021 /* This p_sp will be inserted by ReadRoot later */
1022 p_esp->p_sp = (asf_object_stream_properties_t*)p_sp;
1023 }
1024 }
1025
1026 #ifdef ASF_DEBUG
1027 msg_Dbg( s, "read \"extended stream properties object\":" );
1028 msg_Dbg( s, " - start=%"PRIu64" end=%"PRIu64,
1029 p_esp->i_start_time, p_esp->i_end_time );
1030 msg_Dbg( s, " - data bitrate=%"PRId32" buffer=%"PRId32" initial fullness=%"PRId32,
1031 p_esp->i_data_bitrate,
1032 p_esp->i_buffer_size,
1033 p_esp->i_initial_buffer_fullness );
1034 msg_Dbg( s, " - alternate data bitrate=%"PRId32" buffer=%"PRId32" initial fullness=%"PRId32,
1035 p_esp->i_alternate_data_bitrate,
1036 p_esp->i_alternate_buffer_size,
1037 p_esp->i_alternate_initial_buffer_fullness );
1038 msg_Dbg( s, " - maximum object size=%"PRId32, p_esp->i_maximum_object_size );
1039 msg_Dbg( s, " - flags=0x%x", p_esp->i_flags );
1040 msg_Dbg( s, " - stream number=%u language=%u",
1041 p_esp->i_stream_number, p_esp->i_language_index );
1042 msg_Dbg( s, " - average time per frame=%"PRIu64,
1043 p_esp->i_average_time_per_frame );
1044 msg_Dbg( s, " - stream name count=%u", p_esp->i_stream_name_count );
1045 for( i = 0; i < p_esp->i_stream_name_count; i++ )
1046 msg_Dbg( s, " - lang id=%u name=%s",
1047 p_esp->pi_stream_name_language[i],
1048 p_esp->ppsz_stream_name[i] );
1049 msg_Dbg( s, " - payload extension system count=%u",
1050 p_esp->i_payload_extension_system_count );
1051 for( i = 0; i < p_esp->i_payload_extension_system_count; i++ )
1052 msg_Dbg( s, " - %u - payload extension: " GUID_FMT, i,
1053 GUID_PRINT( p_esp->p_ext[i].i_extension_id ) );
1054 #endif
1055 return VLC_SUCCESS;
1056 }
1057
ASF_ReadObject_advanced_mutual_exclusion(stream_t * s,asf_object_t * p_obj)1058 static int ASF_ReadObject_advanced_mutual_exclusion( stream_t *s,
1059 asf_object_t *p_obj)
1060 {
1061 asf_object_advanced_mutual_exclusion_t *p_ae = &p_obj->advanced_mutual_exclusion;
1062 const uint8_t *p_peek, *p_data;
1063 uint16_t i;
1064
1065 if( p_ae->i_object_size > INT32_MAX )
1066 return VLC_EGENERIC;
1067
1068 ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_ae->i_object_size );
1069 if( i_peek < 42 )
1070 return VLC_EGENERIC;
1071
1072 p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
1073
1074 if( !ASF_HAVE( 16 + 2 * sizeof(uint16_t) ) ) /* at least one entry */
1075 return VLC_EGENERIC;
1076
1077 if ( guidcmp( (const guid_t *) p_data, &asf_guid_mutex_language ) )
1078 p_ae->exclusion_type = LANGUAGE;
1079 else if ( guidcmp( (const guid_t *) p_data, &asf_guid_mutex_bitrate ) )
1080 p_ae->exclusion_type = BITRATE;
1081 ASF_SKIP( 16 );
1082
1083 p_ae->i_stream_number_count = ASF_READ2();
1084 p_ae->pi_stream_number = calloc( p_ae->i_stream_number_count, sizeof(uint16_t) );
1085 if ( !p_ae->pi_stream_number )
1086 {
1087 p_ae->i_stream_number_count = 0;
1088 return VLC_ENOMEM;
1089 }
1090
1091 for( i = 0; i < p_ae->i_stream_number_count; i++ )
1092 {
1093 if( !ASF_HAVE(2) )
1094 break;
1095 p_ae->pi_stream_number[i] = ASF_READ2();
1096 if ( p_ae->pi_stream_number[i] > ASF_MAX_STREAMNUMBER )
1097 break;
1098 }
1099 p_ae->i_stream_number_count = i;
1100
1101 #ifdef ASF_DEBUG
1102 msg_Dbg( s, "read \"advanced mutual exclusion object\" type %s",
1103 p_ae->exclusion_type == LANGUAGE ? "Language" :
1104 ( p_ae->exclusion_type == BITRATE ) ? "Bitrate" : "Unknown"
1105 );
1106 for( i = 0; i < p_ae->i_stream_number_count; i++ )
1107 msg_Dbg( s, " - stream=%d", p_ae->pi_stream_number[i] );
1108 #endif
1109 return VLC_SUCCESS;
1110 }
ASF_FreeObject_advanced_mutual_exclusion(asf_object_t * p_obj)1111 static void ASF_FreeObject_advanced_mutual_exclusion( asf_object_t *p_obj)
1112 {
1113 asf_object_advanced_mutual_exclusion_t *p_ae = &p_obj->advanced_mutual_exclusion;
1114
1115 FREENULL( p_ae->pi_stream_number );
1116 }
1117
1118
ASF_ReadObject_stream_prioritization(stream_t * s,asf_object_t * p_obj)1119 static int ASF_ReadObject_stream_prioritization( stream_t *s,
1120 asf_object_t *p_obj)
1121 {
1122 asf_object_stream_prioritization_t *p_sp = &p_obj->stream_prioritization;
1123 const uint8_t *p_peek, *p_data;
1124 uint16_t i;
1125
1126 if( p_sp->i_object_size > INT32_MAX )
1127 return VLC_EGENERIC;
1128
1129 ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_sp->i_object_size );
1130 if( i_peek < 26 )
1131 return VLC_EGENERIC;
1132
1133 p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
1134
1135 p_sp->i_priority_count = ASF_READ2();
1136
1137 p_sp->pi_priority_flag = calloc( p_sp->i_priority_count, sizeof(uint16_t) );
1138 p_sp->pi_priority_stream_number =
1139 calloc( p_sp->i_priority_count, sizeof(uint16_t) );
1140
1141 if( !p_sp->pi_priority_flag || !p_sp->pi_priority_stream_number )
1142 {
1143 free( p_sp->pi_priority_flag );
1144 free( p_sp->pi_priority_stream_number );
1145 return VLC_ENOMEM;
1146 }
1147
1148 for( i = 0; i < p_sp->i_priority_count; i++ )
1149 {
1150 if( !ASF_HAVE(2+2) )
1151 break;
1152 p_sp->pi_priority_stream_number[i] = ASF_READ2();
1153 p_sp->pi_priority_flag[i] = ASF_READ2();
1154 }
1155 p_sp->i_priority_count = i;
1156
1157 #ifdef ASF_DEBUG
1158 msg_Dbg( s, "read \"stream prioritization object\"" );
1159 for( i = 0; i < p_sp->i_priority_count; i++ )
1160 msg_Dbg( s, " - Stream:%u flags=0x%x",
1161 p_sp->pi_priority_stream_number[i],
1162 p_sp->pi_priority_flag[i] );
1163 #endif
1164 return VLC_SUCCESS;
1165 }
ASF_FreeObject_stream_prioritization(asf_object_t * p_obj)1166 static void ASF_FreeObject_stream_prioritization( asf_object_t *p_obj)
1167 {
1168 asf_object_stream_prioritization_t *p_sp = &p_obj->stream_prioritization;
1169
1170 FREENULL( p_sp->pi_priority_stream_number );
1171 FREENULL( p_sp->pi_priority_flag );
1172 }
1173
ASF_ReadObject_bitrate_mutual_exclusion(stream_t * s,asf_object_t * p_obj)1174 static int ASF_ReadObject_bitrate_mutual_exclusion( stream_t *s, asf_object_t *p_obj )
1175 {
1176 asf_object_bitrate_mutual_exclusion_t *p_ex = &p_obj->bitrate_mutual_exclusion;
1177 const uint8_t *p_peek, *p_data;
1178
1179 if( p_ex->i_object_size > INT32_MAX )
1180 return VLC_EGENERIC;
1181
1182 ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_ex->i_object_size );
1183 if( i_peek < 42 )
1184 return VLC_EGENERIC;
1185
1186 p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
1187
1188 if( !ASF_HAVE( 16 + 2 * sizeof(uint16_t) ) ) /* at least one entry */
1189 return VLC_EGENERIC;
1190
1191 if ( guidcmp( (const guid_t *) p_data, &asf_guid_mutex_language ) )
1192 p_ex->exclusion_type = LANGUAGE;
1193 else if ( guidcmp( (const guid_t *) p_data, &asf_guid_mutex_bitrate ) )
1194 p_ex->exclusion_type = BITRATE;
1195 ASF_SKIP( 16 );
1196
1197 p_ex->i_stream_number_count = ASF_READ2();
1198 p_ex->pi_stream_numbers = calloc( p_ex->i_stream_number_count, sizeof(uint16_t) );
1199 if ( ! p_ex->pi_stream_numbers )
1200 {
1201 p_ex->i_stream_number_count = 0;
1202 return VLC_ENOMEM;
1203 }
1204
1205 for( uint16_t i = 0; i < p_ex->i_stream_number_count; i++ )
1206 {
1207 if( !ASF_HAVE(2) )
1208 break;
1209 p_ex->pi_stream_numbers[i] = ASF_READ2();
1210 if ( p_ex->pi_stream_numbers[i] > ASF_MAX_STREAMNUMBER )
1211 {
1212 free( p_ex->pi_stream_numbers );
1213 return VLC_EGENERIC;
1214 }
1215 }
1216
1217 #ifdef ASF_DEBUG
1218 msg_Dbg( s, "read \"bitrate exclusion object\" type %s",
1219 p_ex->exclusion_type == LANGUAGE ? "Language" :
1220 ( p_ex->exclusion_type == BITRATE ) ? "Bitrate" : "Unknown"
1221 );
1222 for( uint16_t i = 0; i < p_ex->i_stream_number_count; i++ )
1223 msg_Dbg( s, " - stream=%i", p_ex->pi_stream_numbers[i] );
1224 #endif
1225
1226 return VLC_SUCCESS;
1227 }
ASF_FreeObject_bitrate_mutual_exclusion(asf_object_t * p_obj)1228 static void ASF_FreeObject_bitrate_mutual_exclusion( asf_object_t *p_obj)
1229 {
1230 asf_object_bitrate_mutual_exclusion_t *p_ex = &p_obj->bitrate_mutual_exclusion;
1231
1232 FREENULL( p_ex->pi_stream_numbers );
1233 p_ex->i_stream_number_count = 0;
1234 }
1235
ASF_ReadObject_extended_content_description(stream_t * s,asf_object_t * p_obj)1236 static int ASF_ReadObject_extended_content_description( stream_t *s,
1237 asf_object_t *p_obj)
1238 {
1239 asf_object_extended_content_description_t *p_ec =
1240 &p_obj->extended_content_description;
1241 const uint8_t *p_peek, *p_data;
1242 uint16_t i;
1243
1244 if( p_ec->i_object_size > INT32_MAX )
1245 return VLC_EGENERIC;
1246
1247 ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_ec->i_object_size );
1248 if( i_peek < 26 )
1249 return VLC_EGENERIC;
1250
1251 p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
1252
1253 p_ec->i_count = ASF_READ2();
1254 p_ec->ppsz_name = calloc( p_ec->i_count, sizeof(char*) );
1255 p_ec->ppsz_value = calloc( p_ec->i_count, sizeof(char*) );
1256 if( !p_ec->ppsz_name || !p_ec->ppsz_value )
1257 {
1258 free( p_ec->ppsz_name );
1259 free( p_ec->ppsz_value );
1260 return VLC_ENOMEM;
1261 }
1262 for( i = 0; i < p_ec->i_count; i++ )
1263 {
1264 uint16_t i_size;
1265 uint16_t i_type;
1266
1267 if( !ASF_HAVE(2 + 2+2) )
1268 break;
1269
1270 p_ec->ppsz_name[i] = ASF_READS( ASF_READ2() );
1271
1272 /* Grrr */
1273 i_type = ASF_READ2();
1274 i_size = ASF_READ2();
1275
1276 if( i_type == ASF_METADATA_TYPE_STRING )
1277 {
1278 /* Unicode string */
1279 p_ec->ppsz_value[i] = ASF_READS( i_size );
1280 }
1281 else if( i_type == ASF_METADATA_TYPE_BYTE )
1282 {
1283 /* Byte array */
1284 static const char hex[16] = "0123456789ABCDEF";
1285
1286 p_ec->ppsz_value[i] = malloc( 2*i_size + 1 );
1287 if( p_ec->ppsz_value[i] )
1288 {
1289 char *psz_value = p_ec->ppsz_value[i];
1290 for( int j = 0; j < i_size; j++ )
1291 {
1292 const uint8_t v = ASF_READ1();
1293 psz_value[2*j+0] = hex[v>>4];
1294 psz_value[2*j+1] = hex[v&0xf];
1295 }
1296 psz_value[2*i_size] = '\0';
1297 }
1298 }
1299 else if( i_type == ASF_METADATA_TYPE_BOOL )
1300 {
1301 /* Bool */
1302 p_ec->ppsz_value[i] = strdup( ASF_READ1() ? "true" : "false" );
1303 ASF_SKIP(i_size-1);
1304 }
1305 else if( i_type == ASF_METADATA_TYPE_DWORD )
1306 {
1307 /* DWord */
1308 if( asprintf( &p_ec->ppsz_value[i], "%d", ASF_READ4() ) == -1 )
1309 p_ec->ppsz_value[i] = NULL;
1310 }
1311 else if( i_type == ASF_METADATA_TYPE_QWORD )
1312 {
1313 /* QWord */
1314 if( asprintf( &p_ec->ppsz_value[i], "%"PRId64, ASF_READ8() ) == -1 )
1315 p_ec->ppsz_value[i] = NULL;
1316 }
1317 else if( i_type == ASF_METADATA_TYPE_WORD )
1318 {
1319 /* Word */
1320 if( asprintf( &p_ec->ppsz_value[i], "%d", ASF_READ2() ) == -1 )
1321 p_ec->ppsz_value[i] = NULL;
1322 }
1323 else
1324 {
1325 p_ec->ppsz_value[i] = NULL;
1326 ASF_SKIP(i_size);
1327 }
1328 }
1329 p_ec->i_count = i;
1330
1331 #ifdef ASF_DEBUG
1332 msg_Dbg( s, "read \"extended content description object\"" );
1333 for( i = 0; i < p_ec->i_count; i++ )
1334 msg_Dbg( s, " - '%s' = '%s'",
1335 p_ec->ppsz_name[i],
1336 p_ec->ppsz_value[i] );
1337 #endif
1338 return VLC_SUCCESS;
1339 }
ASF_FreeObject_extended_content_description(asf_object_t * p_obj)1340 static void ASF_FreeObject_extended_content_description( asf_object_t *p_obj)
1341 {
1342 asf_object_extended_content_description_t *p_ec =
1343 &p_obj->extended_content_description;
1344
1345 for( uint16_t i = 0; i < p_ec->i_count; i++ )
1346 {
1347 FREENULL( p_ec->ppsz_name[i] );
1348 FREENULL( p_ec->ppsz_value[i] );
1349 }
1350 FREENULL( p_ec->ppsz_name );
1351 FREENULL( p_ec->ppsz_value );
1352 }
1353
ASF_ReadObject_marker(stream_t * s,asf_object_t * p_obj)1354 static int ASF_ReadObject_marker(stream_t *s, asf_object_t *p_obj)
1355 {
1356 asf_object_marker_t *p_mk = (asf_object_marker_t *)p_obj;
1357 const uint8_t *p_peek, *p_data;
1358
1359 if( p_mk->i_object_size > INT32_MAX )
1360 return VLC_EGENERIC;
1361
1362 ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_mk->i_object_size );
1363 if( i_peek < ASF_OBJECT_COMMON_SIZE )
1364 return VLC_EGENERIC;
1365
1366 p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
1367
1368 if( !ASF_HAVE( 16+4+2+2 ) )
1369 return VLC_EGENERIC;
1370
1371 ASF_GetGUID( &p_mk->i_reserved1, p_data );
1372 ASF_SKIP( 16 );
1373 p_mk->i_count = ASF_READ4();
1374 p_mk->i_reserved2 = ASF_READ2();
1375 p_mk->name = ASF_READS( ASF_READ2() );
1376
1377 if( p_mk->i_count > 0 )
1378 {
1379 p_mk->marker = calloc( p_mk->i_count,
1380 sizeof( asf_marker_t ) );
1381 if( !p_mk->marker )
1382 return VLC_ENOMEM;
1383
1384 for( uint32_t i = 0; i < p_mk->i_count; i++ )
1385 {
1386 asf_marker_t *p_marker = &p_mk->marker[i];
1387
1388 if( !ASF_HAVE(8+8+2+4+4+4) )
1389 break;
1390
1391 p_marker->i_offset = ASF_READ8();
1392 p_marker->i_presentation_time = ASF_READ8();
1393 p_marker->i_entry_length = ASF_READ2();
1394 p_marker->i_send_time = ASF_READ4();
1395 p_marker->i_flags = ASF_READ4();
1396 p_marker->i_marker_description_length = ASF_READ4();
1397 if( p_marker->i_marker_description_length <= (UINT32_MAX / 2) )
1398 p_marker->p_marker_description = ASF_READS( p_marker->i_marker_description_length * 2 );
1399 else
1400 p_marker->i_marker_description_length = 0;
1401 }
1402 }
1403
1404 #ifdef ASF_DEBUG
1405 msg_Dbg( s, "Read \"marker object\": %"PRIu32" chapters: %s", p_mk->i_count, p_mk->name );
1406
1407 for( unsigned i = 0; i < p_mk->i_count; i++ )
1408 msg_Dbg( s, "New chapter named: %s", p_mk->marker[i].p_marker_description );
1409 #endif
1410 return VLC_SUCCESS;
1411 }
ASF_FreeObject_marker(asf_object_t * p_obj)1412 static void ASF_FreeObject_marker( asf_object_t *p_obj)
1413 {
1414 asf_object_marker_t *p_mk = (asf_object_marker_t *)p_obj;
1415
1416 for( uint32_t i = 0; i < p_mk->i_count; i++ )
1417 {
1418 FREENULL( p_mk->marker[i].p_marker_description );
1419 }
1420 FREENULL( p_mk->marker );
1421 FREENULL( p_mk->name );
1422 }
1423
ASF_ReadObject_Raw(stream_t * s,asf_object_t * p_obj)1424 static int ASF_ReadObject_Raw(stream_t *s, asf_object_t *p_obj)
1425 {
1426 VLC_UNUSED(s);
1427 VLC_UNUSED(p_obj);
1428 return VLC_SUCCESS;
1429 }
1430
1431 /* */
1432 static const struct ASF_Object_Function_entry
1433 {
1434 const guid_t *p_id;
1435 int i_type;
1436 int (*ASF_ReadObject_function)( stream_t *, asf_object_t *p_obj );
1437 void (*ASF_FreeObject_function)( asf_object_t *p_obj );
1438
1439 } ASF_Object_Function [] =
1440 {
1441 { &asf_object_header_guid, ASF_OBJECT_HEADER,
1442 ASF_ReadObject_Header, ASF_FreeObject_Null },
1443 { &asf_object_data_guid, ASF_OBJECT_DATA,
1444 ASF_ReadObject_Data, ASF_FreeObject_Null },
1445 { &asf_object_simple_index_guid, ASF_OBJECT_INDEX,
1446 ASF_ReadObject_Index, ASF_FreeObject_Index },
1447 { &asf_object_file_properties_guid, ASF_OBJECT_FILE_PROPERTIES,
1448 ASF_ReadObject_file_properties, ASF_FreeObject_Null },
1449 { &asf_object_stream_properties_guid, ASF_OBJECT_STREAM_PROPERTIES,
1450 ASF_ReadObject_stream_properties,ASF_FreeObject_stream_properties },
1451 { &asf_object_header_extension_guid, ASF_OBJECT_HEADER_EXTENSION,
1452 ASF_ReadObject_header_extension, ASF_FreeObject_header_extension},
1453 { &asf_object_metadata_guid, ASF_OBJECT_METADATA,
1454 ASF_ReadObject_metadata, ASF_FreeObject_metadata},
1455 { &asf_object_codec_list_guid, ASF_OBJECT_CODEC_LIST,
1456 ASF_ReadObject_codec_list, ASF_FreeObject_codec_list },
1457 { &asf_object_marker_guid, ASF_OBJECT_MARKER,
1458 ASF_ReadObject_marker, ASF_FreeObject_marker },
1459 { &asf_object_padding, ASF_OBJECT_PADDING, NULL, NULL },
1460 { &asf_object_compatibility_guid, ASF_OBJECT_OTHER, NULL, NULL },
1461 { &asf_object_content_description_guid, ASF_OBJECT_CONTENT_DESCRIPTION,
1462 ASF_ReadObject_content_description, ASF_FreeObject_content_description },
1463 { &asf_object_language_list, ASF_OBJECT_OTHER,
1464 ASF_ReadObject_language_list, ASF_FreeObject_language_list },
1465 { &asf_object_stream_bitrate_properties, ASF_OBJECT_OTHER,
1466 ASF_ReadObject_stream_bitrate_properties,
1467 ASF_FreeObject_stream_bitrate_properties },
1468 { &asf_object_extended_stream_properties_guid, ASF_OBJECT_OTHER,
1469 ASF_ReadObject_extended_stream_properties,
1470 ASF_FreeObject_extended_stream_properties },
1471 { &asf_object_advanced_mutual_exclusion, ASF_OBJECT_OTHER,
1472 ASF_ReadObject_advanced_mutual_exclusion,
1473 ASF_FreeObject_advanced_mutual_exclusion },
1474 { &asf_object_stream_prioritization, ASF_OBJECT_OTHER,
1475 ASF_ReadObject_stream_prioritization,
1476 ASF_FreeObject_stream_prioritization },
1477 { &asf_object_bitrate_mutual_exclusion_guid, ASF_OBJECT_OTHER,
1478 ASF_ReadObject_bitrate_mutual_exclusion,
1479 ASF_FreeObject_bitrate_mutual_exclusion },
1480 { &asf_object_extended_content_description, ASF_OBJECT_OTHER,
1481 ASF_ReadObject_extended_content_description,
1482 ASF_FreeObject_extended_content_description },
1483 { &asf_object_content_encryption_guid, ASF_OBJECT_OTHER,
1484 ASF_ReadObject_Raw, ASF_FreeObject_Null },
1485 { &asf_object_advanced_content_encryption_guid, ASF_OBJECT_OTHER,
1486 ASF_ReadObject_Raw, ASF_FreeObject_Null },
1487 { &asf_object_extended_content_encryption_guid, ASF_OBJECT_OTHER,
1488 ASF_ReadObject_Raw, ASF_FreeObject_Null },
1489 };
1490
ASF_ParentObject(asf_object_t * p_father,asf_object_t * p_obj)1491 static void ASF_ParentObject( asf_object_t *p_father, asf_object_t *p_obj )
1492 {
1493 if( p_father )
1494 {
1495 if( p_father->common.p_first )
1496 {
1497 p_father->common.p_last->common.p_next = p_obj;
1498 }
1499 else
1500 {
1501 p_father->common.p_first = p_obj;
1502 }
1503 p_father->common.p_last = p_obj;
1504 }
1505 }
1506
ASF_GetObject_Function(const guid_t * id)1507 static const struct ASF_Object_Function_entry * ASF_GetObject_Function( const guid_t *id )
1508 {
1509 for( size_t i = 0; i < ARRAY_SIZE(ASF_Object_Function); i++ )
1510 {
1511 if( guidcmp( ASF_Object_Function[i].p_id, id ) )
1512 return &ASF_Object_Function[i];
1513 }
1514 return NULL;
1515 }
1516
ASF_ReadObject(stream_t * s,asf_object_t * p_obj,asf_object_t * p_father)1517 static int ASF_ReadObject( stream_t *s, asf_object_t *p_obj,
1518 asf_object_t *p_father )
1519 {
1520 int i_result = VLC_SUCCESS;
1521
1522 if( !p_obj )
1523 return VLC_SUCCESS;
1524
1525 memset( p_obj, 0, sizeof( *p_obj ) );
1526
1527 if( ASF_ReadObjectCommon( s, p_obj ) )
1528 {
1529 msg_Warn( s, "cannot read one asf object" );
1530 return VLC_EGENERIC;
1531 }
1532 p_obj->common.p_father = p_father;
1533 p_obj->common.p_first = NULL;
1534 p_obj->common.p_next = NULL;
1535 p_obj->common.p_last = NULL;
1536 p_obj->common.i_type = 0;
1537
1538 if( p_obj->common.i_object_size < ASF_OBJECT_COMMON_SIZE )
1539 {
1540 msg_Warn( s, "found a corrupted asf object (size<24)" );
1541 return VLC_EGENERIC;
1542 }
1543
1544 const struct ASF_Object_Function_entry *p_reader =
1545 ASF_GetObject_Function( &p_obj->common.i_object_id );
1546 if( p_reader )
1547 {
1548 p_obj->common.i_type = p_reader->i_type;
1549
1550 /* Now load this object */
1551 if( p_reader->ASF_ReadObject_function != NULL )
1552 i_result = p_reader->ASF_ReadObject_function( s, p_obj );
1553 }
1554 else
1555 {
1556 msg_Warn( s, "unknown asf object (not loaded): " GUID_FMT,
1557 GUID_PRINT( p_obj->common.i_object_id ) );
1558 }
1559
1560 /* link this object with father */
1561 if ( i_result == VLC_SUCCESS )
1562 ASF_ParentObject( p_father, p_obj );
1563
1564 return i_result;
1565 }
1566
ASF_FreeObject(stream_t * s,asf_object_t * p_obj)1567 static void ASF_FreeObject( stream_t *s, asf_object_t *p_obj )
1568 {
1569 asf_object_t *p_child;
1570
1571 if( !p_obj )
1572 return;
1573
1574 /* Free all child object */
1575 p_child = p_obj->common.p_first;
1576 while( p_child )
1577 {
1578 asf_object_t *p_next;
1579 p_next = p_child->common.p_next;
1580 ASF_FreeObject( s, p_child );
1581 p_child = p_next;
1582 }
1583
1584 /* find this object */
1585 const struct ASF_Object_Function_entry *p_entry =
1586 ASF_GetObject_Function( &p_obj->common.i_object_id );
1587 if( p_entry && p_entry->ASF_FreeObject_function )
1588 {
1589 /* Now free this object */
1590 #ifdef ASF_DEBUG
1591 msg_Dbg( s,
1592 "freing asf object " GUID_FMT,
1593 GUID_PRINT( p_obj->common.i_object_id ) );
1594 #endif
1595 p_entry->ASF_FreeObject_function( p_obj );
1596 }
1597
1598 free( p_obj );
1599 }
1600
1601 /*****************************************************************************
1602 * ASF_ObjectDumpDebug:
1603 *****************************************************************************/
1604 static const struct
1605 {
1606 const guid_t *p_id;
1607 const char *psz_name;
1608 } ASF_ObjectDumpDebugInfo[] =
1609 {
1610 { &vlc_object_root_guid, "Root" },
1611 { &asf_object_header_guid, "Header" },
1612 { &asf_object_data_guid, "Data" },
1613 { &asf_object_index_guid, "Index" },
1614 { &asf_object_simple_index_guid, "Simple Index" },
1615 { &asf_object_file_properties_guid, "File Properties" },
1616 { &asf_object_stream_properties_guid, "Stream Properties" },
1617 { &asf_object_content_description_guid, "Content Description" },
1618 { &asf_object_header_extension_guid, "Header Extension" },
1619 { &asf_object_metadata_guid, "Metadata" },
1620 { &asf_object_codec_list_guid, "Codec List" },
1621 { &asf_object_marker_guid, "Marker" },
1622 { &asf_object_stream_type_audio, "Stream Type Audio" },
1623 { &asf_object_stream_type_video, "Stream Type Video" },
1624 { &asf_object_stream_type_command, "Stream Type Command" },
1625 { &asf_object_language_list, "Language List" },
1626 { &asf_object_stream_bitrate_properties, "Stream Bitrate Properties" },
1627 { &asf_object_padding, "Padding" },
1628 { &asf_object_extended_stream_properties_guid, "Extended Stream Properties" },
1629 { &asf_object_advanced_mutual_exclusion, "Advanced Mutual Exclusion" },
1630 { &asf_object_stream_prioritization, "Stream Prioritization" },
1631 { &asf_object_bitrate_mutual_exclusion_guid, "Bitrate Mutual Exclusion" },
1632 { &asf_object_extended_content_description, "Extended content description"},
1633 { &asf_object_content_encryption_guid, "Content Encryption"},
1634 { &asf_object_advanced_content_encryption_guid, "Advanced Content Encryption"},
1635 { &asf_object_extended_content_encryption_guid, "Entended Content Encryption"},
1636 /* Non Readable from this point */
1637 { &nonasf_object_index_placeholder_guid, "Index Placeholder"},
1638 { &nonasf_object_compatibility, "Object Compatibility"},
1639
1640 { NULL, "Unknown" },
1641 };
1642
1643
ASF_ObjectDumpDebug(vlc_object_t * p_obj,asf_object_common_t * p_node,unsigned i_level)1644 static void ASF_ObjectDumpDebug( vlc_object_t *p_obj,
1645 asf_object_common_t *p_node, unsigned i_level )
1646 {
1647 unsigned i;
1648 union asf_object_u *p_child;
1649 const char *psz_name;
1650
1651 /* Find the name */
1652 for( i = 0; ASF_ObjectDumpDebugInfo[i].p_id != NULL; i++ )
1653 {
1654 if( guidcmp( ASF_ObjectDumpDebugInfo[i].p_id,
1655 &p_node->i_object_id ) )
1656 break;
1657 }
1658 psz_name = ASF_ObjectDumpDebugInfo[i].psz_name;
1659
1660 char str[512];
1661 if( i_level >= (sizeof(str) - 1)/5 )
1662 return;
1663
1664 memset( str, ' ', sizeof( str ) );
1665 for( i = 0; i < i_level; i++ )
1666 {
1667 str[i * 4] = '|';
1668 }
1669 snprintf( &str[4*i_level], sizeof(str) - 5*i_level,
1670 "+ '%s'"
1671 #ifdef ASF_DEBUG
1672 "GUID "GUID_FMT" size:%"PRIu64" pos:%"PRIu64
1673 #endif
1674 , psz_name
1675
1676 #ifdef ASF_DEBUG
1677 , GUID_PRINT( p_node->i_object_id ),
1678 p_node->i_object_size, p_node->i_object_pos
1679 #endif
1680 );
1681
1682
1683 msg_Dbg( p_obj, "%s", str );
1684
1685 for( p_child = p_node->p_first; p_child != NULL;
1686 p_child = p_child->common.p_next )
1687 {
1688 ASF_ObjectDumpDebug( p_obj, &p_child->common, i_level + 1 );
1689 }
1690 }
1691
1692 /*****************************************************************************
1693 * ASF_ReadObjetRoot : parse the entire stream/file
1694 *****************************************************************************/
ASF_ReadObjectRoot(stream_t * s,int b_seekable)1695 asf_object_root_t *ASF_ReadObjectRoot( stream_t *s, int b_seekable )
1696 {
1697 asf_object_root_t *p_root = malloc( sizeof( asf_object_root_t ) );
1698 asf_object_t *p_obj;
1699 uint64_t i_boundary = 0;
1700
1701 if( !p_root )
1702 return NULL;
1703
1704 p_root->i_type = ASF_OBJECT_ROOT;
1705 memcpy( &p_root->i_object_id, &vlc_object_root_guid, sizeof( guid_t ) );
1706 p_root->i_object_pos = vlc_stream_Tell( s );
1707 p_root->i_object_size = 0;
1708 p_root->p_first = NULL;
1709 p_root->p_last = NULL;
1710 p_root->p_next = NULL;
1711 p_root->p_hdr = NULL;
1712 p_root->p_data = NULL;
1713 p_root->p_fp = NULL;
1714 p_root->p_index = NULL;
1715 p_root->p_metadata = NULL;
1716
1717 for( ; ; )
1718 {
1719 p_obj = malloc( sizeof( asf_object_t ) );
1720
1721 if( !p_obj || ASF_ReadObject( s, p_obj, (asf_object_t*)p_root ) )
1722 {
1723 free( p_obj );
1724 break;
1725 }
1726 switch( p_obj->common.i_type )
1727 {
1728 case( ASF_OBJECT_HEADER ):
1729 if ( p_root->p_index || p_root->p_data || p_root->p_hdr ) break;
1730 p_root->p_hdr = (asf_object_header_t*)p_obj;
1731 break;
1732 case( ASF_OBJECT_DATA ):
1733 if ( p_root->p_index || p_root->p_data ) break;
1734 p_root->p_data = (asf_object_data_t*)p_obj;
1735 break;
1736 case( ASF_OBJECT_INDEX ):
1737 if ( p_root->p_index ) break;
1738 p_root->p_index = (asf_object_index_t*)p_obj;
1739 break;
1740 default:
1741 msg_Warn( s, "unknown top-level object found: " GUID_FMT,
1742 GUID_PRINT( p_obj->common.i_object_id ) );
1743 break;
1744 }
1745
1746 /* Set a limit to avoid junk when possible */
1747 if ( guidcmp( &p_obj->common.i_object_id, &asf_object_file_properties_guid ) )
1748 {
1749 i_boundary = p_obj->file_properties.i_file_size;
1750 }
1751
1752 if( p_obj->common.i_type == ASF_OBJECT_DATA &&
1753 p_obj->common.i_object_size <= 50 )
1754 {
1755 /* probably a dump of broadcasted asf */
1756 break;
1757 }
1758 if( !b_seekable && p_root->p_hdr && p_root->p_data )
1759 {
1760 /* For unseekable stream it's enough to play */
1761 break;
1762 }
1763
1764 if( ASF_NextObject( s, p_obj, i_boundary ) ) /* Go to the next object */
1765 break;
1766 }
1767
1768 if( p_root->p_hdr != NULL && p_root->p_data != NULL )
1769 {
1770 p_root->p_fp = ASF_FindObject( p_root->p_hdr,
1771 &asf_object_file_properties_guid, 0 );
1772
1773 if( p_root->p_fp )
1774 {
1775 asf_object_t *p_hdr_ext =
1776 ASF_FindObject( p_root->p_hdr,
1777 &asf_object_header_extension_guid, 0 );
1778 if( p_hdr_ext )
1779 {
1780 int i_ext_stream;
1781
1782 p_root->p_metadata =
1783 ASF_FindObject( p_hdr_ext,
1784 &asf_object_metadata_guid, 0 );
1785 /* Special case for broken designed file format :( */
1786 i_ext_stream = ASF_CountObject( p_hdr_ext,
1787 &asf_object_extended_stream_properties_guid );
1788 for( int i = 0; i < i_ext_stream; i++ )
1789 {
1790 asf_object_t *p_esp =
1791 ASF_FindObject( p_hdr_ext,
1792 &asf_object_extended_stream_properties_guid, i );
1793 if( p_esp->ext_stream.p_sp )
1794 {
1795 asf_object_t *p_sp =
1796 (asf_object_t*)p_esp->ext_stream.p_sp;
1797
1798 /* Insert this p_sp */
1799 p_root->p_hdr->p_last->common.p_next = p_sp;
1800 p_root->p_hdr->p_last = p_sp;
1801
1802 p_sp->common.p_father = (asf_object_t*)p_root->p_hdr;
1803 }
1804 }
1805 }
1806
1807 ASF_ObjectDumpDebug( VLC_OBJECT(s),
1808 (asf_object_common_t*)p_root, 0 );
1809 return p_root;
1810 }
1811 msg_Warn( s, "cannot find file properties object" );
1812 }
1813
1814 /* Invalid file */
1815 ASF_FreeObjectRoot( s, p_root );
1816 return NULL;
1817 }
1818
ASF_FreeObjectRoot(stream_t * s,asf_object_root_t * p_root)1819 void ASF_FreeObjectRoot( stream_t *s, asf_object_root_t *p_root )
1820 {
1821 asf_object_t *p_obj;
1822
1823 p_obj = p_root->p_first;
1824 while( p_obj )
1825 {
1826 asf_object_t *p_next;
1827 p_next = p_obj->common.p_next;
1828 ASF_FreeObject( s, p_obj );
1829 p_obj = p_next;
1830 }
1831 free( p_root );
1832 }
1833
ASF_CountObject(void * _p_obj,const guid_t * p_guid)1834 int ASF_CountObject( void *_p_obj, const guid_t *p_guid )
1835 {
1836 int i_count;
1837 asf_object_t *p_child, *p_obj;
1838
1839 p_obj = (asf_object_t *)_p_obj;
1840 if( !p_obj )
1841 return 0;
1842
1843 i_count = 0;
1844 p_child = p_obj->common.p_first;
1845 while( p_child )
1846 {
1847 if( guidcmp( &p_child->common.i_object_id, p_guid ) )
1848 i_count++;
1849
1850 p_child = p_child->common.p_next;
1851 }
1852 return i_count;
1853 }
1854
ASF_FindObject(void * _p_obj,const guid_t * p_guid,int i_number)1855 void *ASF_FindObject( void *_p_obj, const guid_t *p_guid,
1856 int i_number )
1857 {
1858 asf_object_t *p_child, *p_obj;
1859
1860 p_obj = (asf_object_t *)_p_obj;
1861 p_child = p_obj->common.p_first;
1862
1863 while( p_child )
1864 {
1865 if( guidcmp( &p_child->common.i_object_id, p_guid ) )
1866 {
1867 if( i_number == 0 )
1868 return p_child;
1869
1870 i_number--;
1871 }
1872 p_child = p_child->common.p_next;
1873 }
1874 return NULL;
1875 }
1876