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