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