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