Coverage Report

Created: 2026-02-14 08:08

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