* asf: detect dump of broadcasted asf stream.
[vlc.git] / modules / demux / asf / libasf.c
1 /*****************************************************************************
2  * libasf.c :
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: libasf.c,v 1.17 2003/08/24 15:05:27 fenrir Exp $
6  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 #include <stdlib.h>                                      /* malloc(), free() */
24
25 #include <vlc/vlc.h>
26 #include <vlc/input.h>
27 #include "ninput.h"
28
29 #include "codecs.h"                        /* BITMAPINFOHEADER, WAVEFORMATEX */
30 #include "libasf.h"
31
32 #define ASF_DEBUG 1
33
34 #define FREE( p ) \
35     if( p ) {free( p ); p = NULL; }
36
37 #define GUID_FMT "0x%x-0x%x-0x%x-0x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x"
38 #define GUID_PRINT( guid )  \
39     (guid).v1,              \
40     (guid).v2,              \
41     (guid).v3,              \
42     (guid).v4[0],(guid).v4[1],(guid).v4[2],(guid).v4[3],    \
43     (guid).v4[4],(guid).v4[5],(guid).v4[6],(guid).v4[7]
44
45 /****************************************************************************
46  *
47  ****************************************************************************/
48 static int ASF_ReadObject( stream_t *,
49                            asf_object_t *p_obj,  asf_object_t *p_father );
50
51
52 /****************************************************************************
53  * GUID functions
54  ****************************************************************************/
55 void ASF_GetGUID( guid_t *p_guid, uint8_t *p_data )
56 {
57     p_guid->v1 = GetDWLE( p_data );
58     p_guid->v2 = GetWLE( p_data + 4);
59     p_guid->v3 = GetWLE( p_data + 6);
60     memcpy( p_guid->v4, p_data + 8, 8 );
61 }
62
63 int ASF_CmpGUID( const guid_t *p_guid1, const guid_t *p_guid2 )
64 {
65     if( (p_guid1->v1 != p_guid2->v1 )||
66         (p_guid1->v2 != p_guid2->v2 )||
67         (p_guid1->v3 != p_guid2->v3 )||
68         ( memcmp( p_guid1->v4, p_guid2->v4,8 )) )
69     {
70         return( 0 );
71     }
72     return( 1 ); /* match */
73 }
74
75 /****************************************************************************
76  *
77  ****************************************************************************/
78 static int ASF_ReadObjectCommon( stream_t *s, asf_object_t *p_obj )
79 {
80     asf_object_common_t *p_common = (asf_object_common_t*)p_obj;
81     uint8_t             *p_peek;
82
83     if( stream_Peek( s, &p_peek, 24 ) < 24 )
84     {
85         return( VLC_EGENERIC );
86     }
87     ASF_GetGUID( &p_common->i_object_id, p_peek );
88     p_common->i_object_size = GetQWLE( p_peek + 16 );
89     p_common->i_object_pos  = stream_Tell( s );
90     p_common->p_next = NULL;
91 #ifdef ASF_DEBUG
92     msg_Dbg( (vlc_object_t*)s,
93              "Found Object guid: " GUID_FMT " size:"I64Fd,
94              GUID_PRINT( p_common->i_object_id ),
95              p_common->i_object_size );
96 #endif
97
98     return( VLC_SUCCESS );
99 }
100
101 static int ASF_NextObject( stream_t *s, asf_object_t *p_obj )
102 {
103     asf_object_t obj;
104     if( p_obj == NULL )
105     {
106         if( ASF_ReadObjectCommon( s, &obj ) )
107         {
108             return( VLC_EGENERIC );
109         }
110         p_obj = &obj;
111     }
112
113     if( p_obj->common.i_object_size <= 0 )
114     {
115         return( VLC_EGENERIC );
116     }
117     if( p_obj->common.p_father && p_obj->common.p_father->common.i_object_size != 0 )
118     {
119         if( p_obj->common.p_father->common.i_object_pos + p_obj->common.p_father->common.i_object_size <
120                 p_obj->common.i_object_pos + p_obj->common.i_object_size + 24 )
121                                 /* 24 is min size of an object */
122         {
123             return( VLC_EGENERIC );
124         }
125
126     }
127
128     return stream_Seek( s,
129                         p_obj->common.i_object_pos +
130                            p_obj->common.i_object_size );
131 }
132
133 static void ASF_FreeObject_Null( asf_object_t *pp_obj )
134 {
135     return;
136 }
137
138 static int  ASF_ReadObject_Header( stream_t *s, asf_object_t *p_obj )
139 {
140     asf_object_header_t *p_hdr = (asf_object_header_t*)p_obj;
141     asf_object_t        *p_subobj;
142     int                 i_peek;
143     uint8_t             *p_peek;
144
145     if( ( i_peek = stream_Peek( s, &p_peek, 30 ) ) < 30 )
146     {
147        return( VLC_EGENERIC );
148     }
149
150     p_hdr->i_sub_object_count = GetDWLE( p_peek + 24 );
151     p_hdr->i_reserved1 = p_peek[28];
152     p_hdr->i_reserved2 = p_peek[29];
153     p_hdr->p_first = NULL;
154     p_hdr->p_last  = NULL;
155 #ifdef ASF_DEBUG
156     msg_Dbg( (vlc_object_t*)s,
157              "Read \"Header Object\" subobj:%d, reserved1:%d, reserved2:%d",
158              p_hdr->i_sub_object_count,
159              p_hdr->i_reserved1,
160              p_hdr->i_reserved2 );
161 #endif
162     /* Cannot failed as peek succeed */
163     stream_Read( s, NULL, 30 );
164
165     /* Now load sub object */
166     for( ; ; )
167     {
168         p_subobj  = malloc( sizeof( asf_object_t ) );
169
170         if( ASF_ReadObject( s, p_subobj, (asf_object_t*)p_hdr ) )
171         {
172             break;
173         }
174         if( ASF_NextObject( s, p_subobj ) ) /* Go to the next object */
175         {
176             break;
177         }
178     }
179     return VLC_SUCCESS;
180 }
181
182 static int ASF_ReadObject_Data( stream_t *s, asf_object_t *p_obj )
183 {
184     asf_object_data_t *p_data = (asf_object_data_t*)p_obj;
185     int               i_peek;
186     uint8_t           *p_peek;
187
188     if( ( i_peek = stream_Peek( s, &p_peek, 50 ) ) < 50 )
189     {
190        return VLC_EGENERIC;
191     }
192     ASF_GetGUID( &p_data->i_file_id, p_peek + 24 );
193     p_data->i_total_data_packets = GetQWLE( p_peek + 40 );
194     p_data->i_reserved = GetWLE( p_peek + 48 );
195 #ifdef ASF_DEBUG
196     msg_Dbg( (vlc_object_t*)s,
197              "Read \"Data Object\" file_id:" GUID_FMT " total data packet:"
198              I64Fd" reserved:%d",
199              GUID_PRINT( p_data->i_file_id ),
200              p_data->i_total_data_packets,
201              p_data->i_reserved );
202 #endif
203     return VLC_SUCCESS;
204 }
205
206 static int ASF_ReadObject_Index( stream_t *s, asf_object_t *p_obj )
207 {
208     asf_object_index_t *p_index = (asf_object_index_t*)p_obj;
209     int                i_peek;
210     uint8_t            *p_peek;
211
212     if( ( i_peek = stream_Peek( s, &p_peek, 56 ) ) < 56 )
213     {
214        return VLC_EGENERIC;
215     }
216     ASF_GetGUID( &p_index->i_file_id, p_peek + 24 );
217     p_index->i_index_entry_time_interval = GetQWLE( p_peek + 40 );
218     p_index->i_max_packet_count = GetDWLE( p_peek + 48 );
219     p_index->i_index_entry_count = GetDWLE( p_peek + 52 );
220     p_index->index_entry = NULL; /* FIXME */
221
222 #ifdef ASF_DEBUG
223     msg_Dbg( (vlc_object_t*)s,
224             "Read \"Index Object\" file_id:" GUID_FMT
225             " index_entry_time_interval:"I64Fd" max_packet_count:%d "
226             "index_entry_count:%ld",
227             GUID_PRINT( p_index->i_file_id ),
228             p_index->i_index_entry_time_interval,
229             p_index->i_max_packet_count,
230             (long int)p_index->i_index_entry_count );
231 #endif
232     return VLC_SUCCESS;
233 }
234 static void ASF_FreeObject_Index( asf_object_t *p_obj )
235 {
236     asf_object_index_t *p_index = (asf_object_index_t*)p_obj;
237
238     FREE( p_index->index_entry );
239 }
240
241 static int ASF_ReadObject_file_properties( stream_t *s, asf_object_t *p_obj )
242 {
243     asf_object_file_properties_t *p_fp = (asf_object_file_properties_t*)p_obj;
244     int      i_peek;
245     uint8_t  *p_peek;
246
247     if( ( i_peek = stream_Peek( s, &p_peek,  92) ) < 92 )
248     {
249        return VLC_EGENERIC;
250     }
251     ASF_GetGUID( &p_fp->i_file_id, p_peek + 24 );
252     p_fp->i_file_size = GetQWLE( p_peek + 40 );
253     p_fp->i_creation_date = GetQWLE( p_peek + 48 );
254     p_fp->i_data_packets_count = GetQWLE( p_peek + 56 );
255     p_fp->i_play_duration = GetQWLE( p_peek + 64 );
256     p_fp->i_send_duration = GetQWLE( p_peek + 72 );
257     p_fp->i_preroll = GetQWLE( p_peek + 80 );
258     p_fp->i_flags = GetDWLE( p_peek + 88 );
259     p_fp->i_min_data_packet_size = GetDWLE( p_peek + 92 );
260     p_fp->i_max_data_packet_size = GetDWLE( p_peek + 96 );
261     p_fp->i_max_bitrate = GetDWLE( p_peek + 100 );
262
263 #ifdef ASF_DEBUG
264     msg_Dbg( (vlc_object_t*)s,
265             "Read \"File Properties Object\" file_id:" GUID_FMT
266             " file_size:"I64Fd" creation_date:"I64Fd" data_packets_count:"
267             I64Fd" play_duration:"I64Fd" send_duration:"I64Fd" preroll:"
268             I64Fd" flags:%d min_data_packet_size:%d max_data_packet_size:%d "
269             "max_bitrate:%d",
270             GUID_PRINT( p_fp->i_file_id ),
271             p_fp->i_file_size,
272             p_fp->i_creation_date,
273             p_fp->i_data_packets_count,
274             p_fp->i_play_duration,
275             p_fp->i_send_duration,
276             p_fp->i_preroll,
277             p_fp->i_flags,
278             p_fp->i_min_data_packet_size,
279             p_fp->i_max_data_packet_size,
280             p_fp->i_max_bitrate );
281 #endif
282     return VLC_SUCCESS;
283 }
284
285 static int ASF_ReadObject_header_extention( stream_t *s, asf_object_t *p_obj )
286 {
287     asf_object_header_extention_t *p_he = (asf_object_header_extention_t*)p_obj;
288     int     i_peek;
289     uint8_t *p_peek;
290
291     if( ( i_peek = stream_Peek( s, &p_peek, p_he->i_object_size ) ) <  46)
292     {
293        return VLC_EGENERIC;
294     }
295     ASF_GetGUID( &p_he->i_reserved1, p_peek + 24 );
296     p_he->i_reserved2 = GetWLE( p_peek + 40 );
297     p_he->i_header_extention_size = GetDWLE( p_peek + 42 );
298     if( p_he->i_header_extention_size )
299     {
300         p_he->p_header_extention_data = malloc( p_he->i_header_extention_size );
301         memcpy( p_he->p_header_extention_data,
302                 p_peek + 46,
303                 p_he->i_header_extention_size );
304     }
305     else
306     {
307         p_he->p_header_extention_data = NULL;
308     }
309 #ifdef ASF_DEBUG
310     msg_Dbg( (vlc_object_t*)s,
311             "Read \"Header Extention Object\" reserved1:" GUID_FMT " reserved2:%d header_extention_size:%d",
312             GUID_PRINT( p_he->i_reserved1 ),
313             p_he->i_reserved2,
314             p_he->i_header_extention_size );
315 #endif
316     return VLC_SUCCESS;
317 }
318 static void ASF_FreeObject_header_extention( asf_object_t *p_obj )
319 {
320     asf_object_header_extention_t *p_he = (asf_object_header_extention_t*)p_obj;
321
322     FREE( p_he->p_header_extention_data );
323 }
324
325 static int ASF_ReadObject_stream_properties( stream_t *s, asf_object_t *p_obj )
326 {
327     asf_object_stream_properties_t *p_sp =
328                     (asf_object_stream_properties_t*)p_obj;
329     int     i_peek;
330     uint8_t *p_peek;
331
332     if( ( i_peek = stream_Peek( s, &p_peek,  p_sp->i_object_size ) ) < 74 )
333     {
334        return VLC_EGENERIC;
335     }
336     ASF_GetGUID( &p_sp->i_stream_type, p_peek + 24 );
337     ASF_GetGUID( &p_sp->i_error_correction_type, p_peek + 40 );
338     p_sp->i_time_offset = GetQWLE( p_peek + 56 );
339     p_sp->i_type_specific_data_length = GetDWLE( p_peek + 64 );
340     p_sp->i_error_correction_data_length = GetDWLE( p_peek + 68 );
341     p_sp->i_flags = GetWLE( p_peek + 72 );
342         p_sp->i_stream_number = p_sp->i_flags&0x07f;
343     p_sp->i_reserved = GetDWLE( p_peek + 74 );
344     if( p_sp->i_type_specific_data_length )
345     {
346         p_sp->p_type_specific_data = malloc( p_sp->i_type_specific_data_length );
347         memcpy( p_sp->p_type_specific_data,
348                 p_peek + 78,
349                 p_sp->i_type_specific_data_length );
350     }
351     else
352     {
353         p_sp->p_type_specific_data = NULL;
354     }
355     if( p_sp->i_error_correction_data_length )
356     {
357         p_sp->p_error_correction_data = malloc( p_sp->i_error_correction_data_length );
358         memcpy( p_sp->p_error_correction_data,
359                 p_peek + 78 + p_sp->i_type_specific_data_length,
360                 p_sp->i_error_correction_data_length );
361     }
362     else
363     {
364         p_sp->p_error_correction_data = NULL;
365     }
366
367 #ifdef ASF_DEBUG
368     msg_Dbg( (vlc_object_t*)s,
369             "Read \"Stream Properties Object\" stream_type:" GUID_FMT
370             " error_correction_type:" GUID_FMT " time_offset:"I64Fd
371             " type_specific_data_length:%d error_correction_data_length:%d"
372             " flags:0x%x stream_number:%d",
373             GUID_PRINT( p_sp->i_stream_type ),
374             GUID_PRINT( p_sp->i_error_correction_type ),
375             p_sp->i_time_offset,
376             p_sp->i_type_specific_data_length,
377             p_sp->i_error_correction_data_length,
378             p_sp->i_flags,
379             p_sp->i_stream_number );
380
381 #endif
382     return VLC_SUCCESS;
383 }
384
385 static void ASF_FreeObject_stream_properties( asf_object_t *p_obj )
386 {
387     asf_object_stream_properties_t *p_sp =
388                 (asf_object_stream_properties_t*)p_obj;
389
390     FREE( p_sp->p_type_specific_data );
391     FREE( p_sp->p_error_correction_data );
392 }
393
394
395 static int ASF_ReadObject_codec_list( stream_t *s, asf_object_t *p_obj )
396 {
397     asf_object_codec_list_t *p_cl = (asf_object_codec_list_t*)p_obj;
398     int     i_peek;
399     uint8_t *p_peek, *p_data;
400
401     unsigned int i_codec;
402
403     if( ( i_peek = stream_Peek( s, &p_peek, p_cl->i_object_size ) ) < 44 )
404     {
405        return VLC_EGENERIC;
406     }
407
408     ASF_GetGUID( &p_cl->i_reserved, p_peek + 24 );
409     p_cl->i_codec_entries_count = GetWLE( p_peek + 40 );
410     if( p_cl->i_codec_entries_count > 0 )
411     {
412
413         p_cl->codec = calloc( p_cl->i_codec_entries_count,
414                               sizeof( asf_codec_entry_t ) );
415         memset( p_cl->codec, 0,
416                 p_cl->i_codec_entries_count * sizeof( asf_codec_entry_t ) );
417
418         p_data = p_peek + 44;
419         for( i_codec = 0; i_codec < p_cl->i_codec_entries_count; i_codec++ )
420         {
421 #define codec p_cl->codec[i_codec]
422             int i_len, i;
423
424             codec.i_type = GetWLE( p_data ); p_data += 2;
425             /* codec name */
426             i_len = GetWLE( p_data ); p_data += 2;
427             codec.psz_name = calloc( sizeof( char ), i_len + 1);
428             for( i = 0; i < i_len; i++ )
429             {
430                 codec.psz_name[i] = GetWLE( p_data + 2*i );
431             }
432             codec.psz_name[i_len] = '\0';
433             p_data += 2 * i_len;
434
435             /* description */
436             i_len = GetWLE( p_data ); p_data += 2;
437             codec.psz_description = calloc( sizeof( char ), i_len + 1);
438             for( i = 0; i < i_len; i++ )
439             {
440                 codec.psz_description[i] = GetWLE( p_data + 2*i );
441             }
442             codec.psz_description[i_len] = '\0';
443             p_data += 2 * i_len;
444
445             /* opaque information */
446             codec.i_information_length = GetWLE( p_data ); p_data += 2;
447             if( codec.i_information_length > 0 )
448             {
449                 codec.p_information = malloc( codec.i_information_length );
450                 memcpy( codec.p_information, p_data, codec.i_information_length );
451                 p_data += codec.i_information_length;
452             }
453             else
454             {
455                 codec.p_information = NULL;
456             }
457 #undef  codec
458         }
459     }
460     else
461     {
462         p_cl->codec = NULL;
463     }
464
465 #ifdef ASF_DEBUG
466     msg_Dbg( (vlc_object_t*)s,
467             "Read \"Codec List Object\" reserved_guid:" GUID_FMT " codec_entries_count:%d",
468             GUID_PRINT( p_cl->i_reserved ),
469             p_cl->i_codec_entries_count );
470
471     for( i_codec = 0; i_codec < p_cl->i_codec_entries_count; i_codec++ )
472     {
473 #define codec p_cl->codec[i_codec]
474         msg_Dbg( (vlc_object_t*)s,
475                  "Read \"Codec List Object\" codec[%d] %s name:\"%s\" description:\"%s\" information_length:%d",
476                  i_codec,
477                  ( codec.i_type == ASF_CODEC_TYPE_VIDEO ) ? "video" : ( ( codec.i_type == ASF_CODEC_TYPE_AUDIO ) ? "audio" : "unknown" ),
478                  codec.psz_name,
479                  codec.psz_description,
480                  codec.i_information_length );
481     }
482 #endif
483     return VLC_SUCCESS;
484 }
485
486 static void ASF_FreeObject_codec_list( asf_object_t *p_obj )
487 {
488     asf_object_codec_list_t *p_cl = (asf_object_codec_list_t*)p_obj;
489     unsigned int i_codec;
490
491     for( i_codec = 0; i_codec < p_cl->i_codec_entries_count; i_codec++ )
492     {
493 #define codec p_cl->codec[i_codec]
494         FREE( codec.psz_name );
495         FREE( codec.psz_description );
496         FREE( codec.p_information );
497
498 #undef  codec
499     }
500     FREE( p_cl->codec );
501 }
502
503 /* Microsoft should go to hell. This time the length give number of bytes
504  * and for the some others object, length give char16 count ... */
505 static int ASF_ReadObject_content_description(stream_t *s, asf_object_t *p_obj)
506 {
507     asf_object_content_description_t *p_cd =
508                                     (asf_object_content_description_t*)p_obj;
509     int     i_peek;
510     uint8_t *p_peek, *p_data;
511
512     int i_len;
513     int i_title;
514     int i_author;
515     int i_copyright;
516     int i_description;
517     int i_rating;
518
519 #define GETSTRINGW( psz_str, i_size ) \
520    psz_str = calloc( i_size/2 + 1, sizeof( char ) ); \
521    for( i_len = 0; i_len < i_size/2; i_len++ ) \
522    { \
523        psz_str[i_len] = GetWLE( p_data + 2*i_len ); \
524    } \
525    psz_str[i_size/2] = '\0'; \
526    p_data += i_size;
527
528     if( ( i_peek = stream_Peek( s, &p_peek, p_cd->i_object_size ) ) < 34 )
529     {
530        return VLC_EGENERIC;
531     }
532     p_data = p_peek + 24;
533
534     i_title = GetWLE( p_data ); p_data += 2;
535     i_author= GetWLE( p_data ); p_data += 2;
536     i_copyright     = GetWLE( p_data ); p_data += 2;
537     i_description   = GetWLE( p_data ); p_data += 2;
538     i_rating        = GetWLE( p_data ); p_data += 2;
539
540     GETSTRINGW( p_cd->psz_title, i_title );
541     GETSTRINGW( p_cd->psz_author, i_author );
542     GETSTRINGW( p_cd->psz_copyright, i_copyright );
543     GETSTRINGW( p_cd->psz_description, i_description );
544     GETSTRINGW( p_cd->psz_rating, i_rating );
545
546 #undef  GETSTRINGW
547
548 #ifdef ASF_DEBUG
549     msg_Dbg( (vlc_object_t*)s,
550              "Read \"Content Description Object\" title:\"%s\" author:\"%s\" copyright:\"%s\" description:\"%s\" rating:\"%s\"",
551              p_cd->psz_title,
552              p_cd->psz_author,
553              p_cd->psz_copyright,
554              p_cd->psz_description,
555              p_cd->psz_rating );
556 #endif
557     return VLC_SUCCESS;
558 }
559
560 static void ASF_FreeObject_content_description( asf_object_t *p_obj)
561 {
562     asf_object_content_description_t *p_cd =
563                                     (asf_object_content_description_t*)p_obj;
564
565     FREE( p_cd->psz_title );
566     FREE( p_cd->psz_author );
567     FREE( p_cd->psz_copyright );
568     FREE( p_cd->psz_description );
569     FREE( p_cd->psz_rating );
570 }
571
572 static struct
573 {
574     const guid_t  *p_id;
575     int     i_type;
576     int     (*ASF_ReadObject_function)( stream_t *, asf_object_t *p_obj );
577     void    (*ASF_FreeObject_function)( asf_object_t *p_obj );
578 } ASF_Object_Function [] =
579 {
580     { &asf_object_header_guid,            ASF_OBJECT_TYPE_HEADER,             ASF_ReadObject_Header, ASF_FreeObject_Null },
581     { &asf_object_data_guid,              ASF_OBJECT_TYPE_DATA,               ASF_ReadObject_Data,   ASF_FreeObject_Null },
582     { &asf_object_index_guid,             ASF_OBJECT_TYPE_INDEX,              ASF_ReadObject_Index,  ASF_FreeObject_Index },
583     { &asf_object_file_properties_guid,   ASF_OBJECT_TYPE_FILE_PROPERTIES,    ASF_ReadObject_file_properties,  ASF_FreeObject_Null },
584     { &asf_object_stream_properties_guid, ASF_OBJECT_TYPE_STREAM_PROPERTIES,  ASF_ReadObject_stream_properties,ASF_FreeObject_stream_properties },
585     { &asf_object_header_extention_guid,  ASF_OBJECT_TYPE_EXTENTION_HEADER,   ASF_ReadObject_header_extention, ASF_FreeObject_header_extention},
586     { &asf_object_codec_list_guid,        ASF_OBJECT_TYPE_CODEC_LIST,         ASF_ReadObject_codec_list,       ASF_FreeObject_codec_list },
587     { &asf_object_marker_guid,            ASF_OBJECT_TYPE_MARKER,             NULL,                  NULL },
588     { &asf_object_content_description_guid, ASF_OBJECT_TYPE_CONTENT_DESCRIPTION, ASF_ReadObject_content_description, ASF_FreeObject_content_description },
589
590     { &asf_object_null_guid,   0,                      NULL,                  NULL }
591 };
592
593 static int ASF_ReadObject( stream_t *s,
594                            asf_object_t *p_obj, asf_object_t *p_father )
595 {
596     int i_result;
597     int i_index;
598
599     if( !p_obj )
600     {
601         return( 0 );
602     }
603     if( ASF_ReadObjectCommon( s, p_obj ) )
604     {
605         msg_Warn( (vlc_object_t*)s, "Cannot read one asf object" );
606         return VLC_EGENERIC;
607     }
608     p_obj->common.p_father = p_father;
609     p_obj->common.p_first = NULL;
610     p_obj->common.p_next = NULL;
611     p_obj->common.p_last = NULL;
612
613
614     if( p_obj->common.i_object_size < 24 )
615     {
616         msg_Warn( (vlc_object_t*)s, "Found a corrupted asf object (size<24)" );
617         return VLC_EGENERIC;
618     }
619     /* find this object */
620     for( i_index = 0; ; i_index++ )
621     {
622         if( ASF_CmpGUID( ASF_Object_Function[i_index].p_id,
623                      &p_obj->common.i_object_id )||
624             ASF_CmpGUID( ASF_Object_Function[i_index].p_id,
625                      &asf_object_null_guid ) )
626         {
627             break;
628         }
629     }
630     p_obj->common.i_type = ASF_Object_Function[i_index].i_type;
631
632     /* Now load this object */
633     if( ASF_Object_Function[i_index].ASF_ReadObject_function == NULL )
634     {
635         msg_Warn( (vlc_object_t*)s, "Unknown asf object (not loaded)" );
636         i_result = VLC_SUCCESS;
637     }
638     else
639     {
640         /* XXX ASF_ReadObject_function realloc *pp_obj XXX */
641         i_result =
642           (ASF_Object_Function[i_index].ASF_ReadObject_function)( s, p_obj );
643     }
644
645     /* link this object with father */
646     if( p_father )
647     {
648         if( p_father->common.p_first )
649         {
650             p_father->common.p_last->common.p_next = p_obj;
651         }
652         else
653         {
654             p_father->common.p_first = p_obj;
655         }
656         p_father->common.p_last = p_obj;
657     }
658
659     return( i_result );
660 }
661
662 static void ASF_FreeObject( stream_t *s, asf_object_t *p_obj )
663 {
664     int i_index;
665     asf_object_t *p_child;
666
667     if( !p_obj )
668     {
669         return;
670     }
671
672     /* Free all child object */
673     p_child = p_obj->common.p_first;
674     while( p_child )
675     {
676         asf_object_t *p_next;
677         p_next = p_child->common.p_next;
678         ASF_FreeObject( s, p_child );
679         p_child = p_next;
680     }
681
682     /* find this object */
683     for( i_index = 0; ; i_index++ )
684     {
685         if( ASF_CmpGUID( ASF_Object_Function[i_index].p_id,
686                      &p_obj->common.i_object_id )||
687             ASF_CmpGUID( ASF_Object_Function[i_index].p_id,
688                      &asf_object_null_guid ) )
689         {
690             break;
691         }
692     }
693
694     /* Now free this object */
695     if( ASF_Object_Function[i_index].ASF_FreeObject_function == NULL )
696     {
697         msg_Warn( (vlc_object_t*)s,
698                   "Unknown asf object " GUID_FMT,
699                   GUID_PRINT( p_obj->common.i_object_id ) );
700     }
701     else
702     {
703 #ifdef ASF_DEBUG
704         msg_Dbg( (vlc_object_t*)s,
705                   "Free asf object " GUID_FMT,
706                   GUID_PRINT( p_obj->common.i_object_id ) );
707 #endif
708         (ASF_Object_Function[i_index].ASF_FreeObject_function)( p_obj );
709     }
710     free( p_obj );
711     return;
712 }
713
714 /*****************************************************************************
715  * ASF_ReadObjetRoot : parse the entire stream/file
716  *****************************************************************************/
717 asf_object_root_t *ASF_ReadObjectRoot( stream_t *s, int b_seekable )
718 {
719     asf_object_root_t *p_root = malloc( sizeof( asf_object_root_t ) );
720     asf_object_t *p_obj;
721
722     p_root->i_type = ASF_OBJECT_TYPE_ROOT;
723     memcpy( &p_root->i_object_id, &asf_object_null_guid, sizeof( guid_t ) );
724     p_root->i_object_pos = 0;
725     p_root->i_object_size = stream_Tell( s );
726     p_root->p_first = NULL;
727     p_root->p_last  = NULL;
728     p_root->p_next  = NULL;
729     p_root->p_hdr   = NULL;
730     p_root->p_data  = NULL;
731     p_root->p_fp    = NULL;
732     p_root->p_index = NULL;
733
734     for( ; ; )
735     {
736         p_obj  = malloc( sizeof( asf_object_t ) );
737
738         if( ASF_ReadObject( s, p_obj, (asf_object_t*)p_root ) )
739         {
740             break;
741         }
742         switch( p_obj->common.i_type )
743         {
744             case( ASF_OBJECT_TYPE_HEADER ):
745                 p_root->p_hdr = (asf_object_header_t*)p_obj;
746                 break;
747             case( ASF_OBJECT_TYPE_DATA ):
748                 p_root->p_data = (asf_object_data_t*)p_obj;
749                 break;
750             case( ASF_OBJECT_TYPE_INDEX ):
751                 p_root->p_index = (asf_object_index_t*)p_obj;
752                 break;
753             default:
754                 msg_Warn( (vlc_object_t*)s, "Unknow Object found" );
755                 break;
756         }
757         if( p_obj->common.i_type == ASF_OBJECT_TYPE_DATA &&
758             p_obj->common.i_object_size <= 50 )
759         {
760             /* probably a dump of broadcasted asf */
761             break;
762         }
763         if( !b_seekable && p_root->p_hdr && p_root->p_data )
764         {
765             /* For unseekable stream it's enouth to play */
766             break;
767         }
768
769         if( ASF_NextObject( s, p_obj ) ) /* Go to the next object */
770         {
771             break;
772         }
773     }
774
775     if( p_root->p_hdr != NULL && p_root->p_data != NULL )
776     {
777         p_root->p_fp = ASF_FindObject( p_root->p_hdr,
778                                        &asf_object_file_properties_guid, 0 );
779
780         if( p_root->p_fp )
781         {
782             return p_root;
783         }
784         msg_Warn( (vlc_object_t*)s, "cannot fine file properties object" );
785     }
786
787     /* Invalid file */
788     ASF_FreeObjectRoot( s, p_root );
789     return NULL;
790 }
791
792 void ASF_FreeObjectRoot( stream_t *s, asf_object_root_t *p_root )
793 {
794     asf_object_t *p_obj;
795
796     p_obj = p_root->p_first;
797     while( p_obj )
798     {
799         asf_object_t *p_next;
800         p_next = p_obj->common.p_next;
801         ASF_FreeObject( s, p_obj );
802         p_obj = p_next;
803     }
804     free( p_root );
805 }
806
807 int  __ASF_CountObject( asf_object_t *p_obj, const guid_t *p_guid )
808 {
809     int i_count;
810     asf_object_t *p_child;
811
812     if( !p_obj )
813     {
814         return( 0 );
815     }
816
817     i_count = 0;
818     p_child = p_obj->common.p_first;
819     while( p_child )
820     {
821         if( ASF_CmpGUID( &p_child->common.i_object_id, p_guid ) )
822         {
823             i_count++;
824         }
825         p_child = p_child->common.p_next;
826     }
827     return( i_count );
828 }
829
830 void *__ASF_FindObject( asf_object_t *p_obj, const guid_t *p_guid, int i_number )
831 {
832     asf_object_t *p_child;
833
834     p_child = p_obj->common.p_first;
835
836     while( p_child )
837     {
838         if( ASF_CmpGUID( &p_child->common.i_object_id, p_guid ) )
839         {
840             if( i_number == 0 )
841             {
842                 /* We found it */
843                 return( p_child );
844             }
845
846             i_number--;
847         }
848         p_child = p_child->common.p_next;
849     }
850     return( NULL );
851 }
852