Coverage Report

Created: 2026-02-05 06:37

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
1.92M
{
51
1.92M
    if( i_wanted > i_peek )
52
1.34k
        return false;
53
1.92M
    return &p_current[i_wanted] <= &p_peek[i_peek];
54
1.92M
}
55
1.04M
#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
881k
{
61
881k
    if( AsfObjectHelperHave( p_peek, i_peek, *pp_data, i_wanted ) )
62
772k
        *pp_data += i_wanted;
63
108k
    else
64
108k
        *pp_data = (uint8_t*)&p_peek[i_peek];
65
881k
}
66
881k
#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
670k
static inline type AsfObjectHelperRead##x( const uint8_t *p_peek, size_t i_peek, uint8_t **pp_data ) { \
72
670k
    uint8_t *p_data = *pp_data; \
73
670k
    type i_ret = 0;  \
74
670k
    if( ASF_HAVE(x) )   \
75
670k
        i_ret = cmd;    \
76
670k
    ASF_SKIP(x);        \
77
670k
    *pp_data = p_data;  \
78
670k
    return i_ret;   }
libasf.c:AsfObjectHelperRead2
Line
Count
Source
71
318k
static inline type AsfObjectHelperRead##x( const uint8_t *p_peek, size_t i_peek, uint8_t **pp_data ) { \
72
318k
    uint8_t *p_data = *pp_data; \
73
318k
    type i_ret = 0;  \
74
318k
    if( ASF_HAVE(x) )   \
75
318k
        i_ret = cmd;    \
76
318k
    ASF_SKIP(x);        \
77
318k
    *pp_data = p_data;  \
78
318k
    return i_ret;   }
libasf.c:AsfObjectHelperRead4
Line
Count
Source
71
16.4k
static inline type AsfObjectHelperRead##x( const uint8_t *p_peek, size_t i_peek, uint8_t **pp_data ) { \
72
16.4k
    uint8_t *p_data = *pp_data; \
73
16.4k
    type i_ret = 0;  \
74
16.4k
    if( ASF_HAVE(x) )   \
75
16.4k
        i_ret = cmd;    \
76
16.4k
    ASF_SKIP(x);        \
77
16.4k
    *pp_data = p_data;  \
78
16.4k
    return i_ret;   }
libasf.c:AsfObjectHelperRead8
Line
Count
Source
71
793
static inline type AsfObjectHelperRead##x( const uint8_t *p_peek, size_t i_peek, uint8_t **pp_data ) { \
72
793
    uint8_t *p_data = *pp_data; \
73
793
    type i_ret = 0;  \
74
793
    if( ASF_HAVE(x) )   \
75
793
        i_ret = cmd;    \
76
793
    ASF_SKIP(x);        \
77
793
    *pp_data = p_data;  \
78
793
    return i_ret;   }
libasf.c:AsfObjectHelperRead1
Line
Count
Source
71
334k
static inline type AsfObjectHelperRead##x( const uint8_t *p_peek, size_t i_peek, uint8_t **pp_data ) { \
72
334k
    uint8_t *p_data = *pp_data; \
73
334k
    type i_ret = 0;  \
74
334k
    if( ASF_HAVE(x) )   \
75
334k
        i_ret = cmd;    \
76
334k
    ASF_SKIP(x);        \
77
334k
    *pp_data = p_data;  \
78
334k
    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
299k
#define ASF_READ1() AsfObjectHelperRead1( p_peek, i_peek, (uint8_t**)&p_data )
84
199k
#define ASF_READ2() AsfObjectHelperRead2( p_peek, i_peek, (uint8_t**)&p_data )
85
15.4k
#define ASF_READ4() AsfObjectHelperRead4( p_peek, i_peek, (uint8_t**)&p_data )
86
782
#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
196k
{
93
196k
    uint8_t *p_data = *pp_data;
94
196k
    char *psz_string = NULL;
95
196k
    if( ASF_HAVE(i_size) )
96
195k
    {
97
195k
        psz_string = FromCharset( "UTF-16LE", p_data, i_size );
98
195k
    }
99
196k
    ASF_SKIP(i_size);
100
196k
    *pp_data = p_data;
101
196k
    return psz_string;
102
196k
}
103
196k
#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
988k
{
116
988k
    asf_object_common_t *p_common = &p_obj->common;
117
988k
    const uint8_t *p_peek;
118
119
988k
    if( vlc_stream_Peek( s, &p_peek, ASF_OBJECT_COMMON_SIZE ) < ASF_OBJECT_COMMON_SIZE )
120
234k
        return VLC_EGENERIC;
121
122
754k
    ASF_GetGUID( &p_common->i_object_id, p_peek );
123
754k
    p_common->i_object_size = GetQWLE( p_peek + 16 );
124
754k
    p_common->i_object_pos  = vlc_stream_Tell( s );
125
754k
    p_common->p_next = NULL;
126
127
754k
#ifdef ASF_DEBUG
128
754k
    msg_Dbg( s,
129
754k
             "found object guid: " GUID_FMT " size:%"PRIu64" at %"PRIu64,
130
754k
             GUID_PRINT( p_common->i_object_id ),
131
754k
             p_common->i_object_size, p_common->i_object_pos );
132
754k
#endif
133
134
754k
    return VLC_SUCCESS;
135
988k
}
136
137
static int ASF_NextObject( stream_t *s, asf_object_t *p_obj, uint64_t i_boundary )
138
752k
{
139
752k
    asf_object_t obj;
140
141
752k
    int64_t i_pos = vlc_stream_Tell( s );
142
752k
    if ( i_boundary && i_pos >= 0 && (uint64_t) i_pos >= i_boundary )
143
9
    {
144
9
        return VLC_EGENERIC;
145
9
    }
146
147
752k
    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
752k
    if( p_obj->common.i_object_size <= 0 )
156
0
        return VLC_EGENERIC;
157
158
752k
    if( ( UINT64_MAX - p_obj->common.i_object_pos ) < p_obj->common.i_object_size )
159
48
        return VLC_EGENERIC;
160
161
752k
    if( p_obj->common.p_father &&
162
752k
        p_obj->common.p_father->common.i_object_size != 0 )
163
736k
    {
164
736k
        if( p_obj->common.p_father->common.i_object_pos +
165
736k
            p_obj->common.p_father->common.i_object_size <
166
736k
                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
474k
        {
169
474k
            return VLC_EGENERIC;
170
474k
        }
171
172
736k
    }
173
174
278k
    return vlc_stream_Seek( s, p_obj->common.i_object_pos +
175
278k
                        p_obj->common.i_object_size );
176
752k
}
177
178
static void ASF_FreeObject_Null( asf_object_t *pp_obj )
179
716k
{
180
716k
    VLC_UNUSED(pp_obj);
181
716k
}
182
183
static int  ASF_ReadObject_Header( stream_t *s, asf_object_t *p_obj )
184
701k
{
185
701k
    asf_object_header_t *p_hdr = &p_obj->header;
186
701k
    asf_object_t        *p_subobj;
187
701k
    const uint8_t       *p_peek;
188
189
701k
    if( vlc_stream_Peek( s, &p_peek, 30 ) < 30 )
190
2
       return VLC_EGENERIC;
191
192
701k
    p_hdr->i_sub_object_count = GetDWLE( p_peek + ASF_OBJECT_COMMON_SIZE );
193
701k
    p_hdr->i_reserved1 = p_peek[28];
194
701k
    p_hdr->i_reserved2 = p_peek[29];
195
701k
    p_hdr->p_first = NULL;
196
701k
    p_hdr->p_last  = NULL;
197
198
701k
#ifdef ASF_DEBUG
199
701k
    msg_Dbg( s,
200
701k
             "read \"header object\" subobj:%u, reserved1:%u, reserved2:%u",
201
701k
             p_hdr->i_sub_object_count,
202
701k
             p_hdr->i_reserved1,
203
701k
             p_hdr->i_reserved2 );
204
701k
#endif
205
206
701k
    if( vlc_stream_Read( s, NULL, 30 ) != 30 )
207
0
        return VLC_EGENERIC;
208
209
    /* Now load sub object */
210
701k
    for( ; ; )
211
958k
    {
212
958k
        p_subobj = malloc( sizeof( asf_object_t ) );
213
214
958k
        if( !p_subobj || ASF_ReadObject( s, p_subobj, (asf_object_t*)p_hdr ) )
215
228k
        {
216
228k
            free( p_subobj );
217
228k
            break;
218
228k
        }
219
730k
        if( ASF_NextObject( s, p_subobj, 0 ) ) /* Go to the next object */
220
473k
            break;
221
730k
    }
222
701k
    return VLC_SUCCESS;
223
701k
}
224
225
static int ASF_ReadObject_Data( stream_t *s, asf_object_t *p_obj )
226
7.14k
{
227
7.14k
    asf_object_data_t *p_data = &p_obj->data;
228
7.14k
    const uint8_t     *p_peek;
229
230
7.14k
    if( vlc_stream_Peek( s, &p_peek, 50 ) < 50 )
231
2
       return VLC_EGENERIC;
232
233
7.14k
    ASF_GetGUID( &p_data->i_file_id, p_peek + ASF_OBJECT_COMMON_SIZE );
234
7.14k
    p_data->i_total_data_packets = GetQWLE( p_peek + 40 );
235
7.14k
    p_data->i_reserved = GetWLE( p_peek + 48 );
236
237
7.14k
#ifdef ASF_DEBUG
238
7.14k
    msg_Dbg( s,
239
7.14k
             "read \"data object\" file_id:" GUID_FMT " total data packet:"
240
7.14k
             "%"PRIu64" reserved:%u",
241
7.14k
             GUID_PRINT( p_data->i_file_id ),
242
7.14k
             p_data->i_total_data_packets,
243
7.14k
             p_data->i_reserved );
244
7.14k
#endif
245
246
7.14k
    return VLC_SUCCESS;
247
7.14k
}
248
249
static int ASF_ReadObject_Index( stream_t *s, asf_object_t *p_obj )
250
12
{
251
12
    asf_object_index_t *p_index = &p_obj->index;
252
12
    const uint8_t      *p_peek;
253
12
    unsigned int       i;
254
255
    /* We just ignore error on the index */
256
12
    if( p_index->i_object_size < 56
257
11
     || p_index->i_object_size > INT32_MAX
258
10
     || vlc_stream_Peek( s, &p_peek, p_index->i_object_size )
259
10
        < (int64_t)p_index->i_object_size )
260
6
        return VLC_SUCCESS;
261
262
6
    ASF_GetGUID( &p_index->i_file_id, p_peek + ASF_OBJECT_COMMON_SIZE );
263
6
    p_index->i_index_entry_time_interval = GetQWLE( p_peek + 40 );
264
6
    p_index->i_max_packet_count = GetDWLE( p_peek + 48 );
265
6
    p_index->i_index_entry_count = GetDWLE( p_peek + 52 );
266
6
    p_index->index_entry = NULL;
267
268
6
#ifdef ASF_DEBUG
269
6
    msg_Dbg( s,
270
6
            "read \"index object\" file_id:" GUID_FMT
271
6
            " index_entry_time_interval:%"PRId64" max_packet_count:%u "
272
6
            "index_entry_count:%u",
273
6
            GUID_PRINT( p_index->i_file_id ),
274
6
            p_index->i_index_entry_time_interval,
275
6
            p_index->i_max_packet_count,
276
6
            p_index->i_index_entry_count );
277
6
#endif
278
279
    /* Sanity checking */
280
6
    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
6
    if( p_index->i_index_entry_count > (p_index->i_object_size - 56) / 6 )
287
1
        p_index->i_index_entry_count = (p_index->i_object_size - 56) / 6;
288
289
6
    p_index->index_entry = calloc( p_index->i_index_entry_count,
290
6
                                   sizeof(asf_index_entry_t) );
291
6
    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
176
    for( i = 0, p_peek += 56; i < p_index->i_index_entry_count; i++, p_peek += 6 )
298
170
    {
299
170
        p_index->index_entry[i].i_packet_number = GetDWLE( p_peek );
300
170
        p_index->index_entry[i].i_packet_count = GetWLE( p_peek + 4 );
301
170
    }
302
303
6
    return VLC_SUCCESS;
304
6
}
305
306
static void ASF_FreeObject_Index( asf_object_t *p_obj )
307
12
{
308
12
    asf_object_index_t *p_index = &p_obj->index;
309
310
12
    FREENULL( p_index->index_entry );
311
12
}
312
313
static int ASF_ReadObject_file_properties( stream_t *s, asf_object_t *p_obj )
314
7.56k
{
315
7.56k
    asf_object_file_properties_t *p_fp = &p_obj->file_properties;
316
7.56k
    const uint8_t *p_peek;
317
318
7.56k
    if( vlc_stream_Peek( s, &p_peek,  104 ) < 104 )
319
3
       return VLC_EGENERIC;
320
321
7.55k
    ASF_GetGUID( &p_fp->i_file_id, p_peek + ASF_OBJECT_COMMON_SIZE );
322
7.55k
    p_fp->i_file_size = GetQWLE( p_peek + 40 );
323
7.55k
    p_fp->i_creation_date = GetQWLE( p_peek + 48 );
324
7.55k
    p_fp->i_data_packets_count = GetQWLE( p_peek + 56 );
325
7.55k
    p_fp->i_play_duration = GetQWLE( p_peek + 64 );
326
7.55k
    p_fp->i_send_duration = GetQWLE( p_peek + 72 );
327
7.55k
    uint64_t preroll = GetQWLE( p_peek + 80 );
328
7.55k
    if (unlikely(preroll > INT32_MAX)) // sanity check on "appropriate" value
329
6
        return VLC_EINVAL;
330
7.55k
    p_fp->i_preroll = VLC_TICK_FROM_MS(preroll);
331
7.55k
    p_fp->i_flags = GetDWLE( p_peek + 88 );
332
7.55k
    p_fp->i_min_data_packet_size = __MAX( GetDWLE( p_peek + 92 ), (uint32_t) 1 );
333
7.55k
    p_fp->i_max_data_packet_size = __MAX( GetDWLE( p_peek + 96 ), (uint32_t) 1 );
334
7.55k
    p_fp->i_max_bitrate = GetDWLE( p_peek + 100 );
335
336
7.55k
#ifdef ASF_DEBUG
337
7.55k
    msg_Dbg( s,
338
7.55k
            "read \"file properties object\" file_id:" GUID_FMT
339
7.55k
            " file_size:%"PRIu64" creation_date:%"PRIu64" data_packets_count:"
340
7.55k
            "%"PRIu64" play_duration:%"PRId64" send_duration:%"PRId64" preroll:%"PRIu64
341
7.55k
            " flags:%u min_data_packet_size:%d "
342
7.55k
            " max_data_packet_size:%u max_bitrate:%u",
343
7.55k
            GUID_PRINT( p_fp->i_file_id ), p_fp->i_file_size,
344
7.55k
            p_fp->i_creation_date, p_fp->i_data_packets_count,
345
7.55k
            p_fp->i_play_duration, p_fp->i_send_duration,
346
7.55k
            preroll, p_fp->i_flags,
347
7.55k
            p_fp->i_min_data_packet_size, p_fp->i_max_data_packet_size,
348
7.55k
            p_fp->i_max_bitrate );
349
7.55k
#endif
350
351
7.55k
    return VLC_SUCCESS;
352
7.55k
}
353
354
static void ASF_FreeObject_metadata( asf_object_t *p_obj )
355
1.14k
{
356
1.14k
    asf_object_metadata_t *p_meta = &p_obj->metadata;
357
358
5.36k
    for( uint32_t i = 0; i < p_meta->i_record_entries_count; i++ )
359
4.22k
    {
360
4.22k
        free( p_meta->record[i].psz_name );
361
4.22k
        free( p_meta->record[i].p_data );
362
4.22k
    }
363
1.14k
    free( p_meta->record );
364
1.14k
}
365
366
static int ASF_ReadObject_metadata( stream_t *s, asf_object_t *p_obj )
367
1.15k
{
368
1.15k
    asf_object_metadata_t *p_meta = &p_obj->metadata;
369
370
1.15k
    uint32_t i;
371
1.15k
    const uint8_t *p_peek, *p_data;
372
373
1.15k
    if( p_meta->i_object_size < 26 || p_meta->i_object_size > INT32_MAX )
374
1
        return VLC_EGENERIC;
375
376
1.15k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_meta->i_object_size );
377
1.15k
    if( i_peek < (int64_t)p_meta->i_object_size )
378
8
       return VLC_EGENERIC;
379
380
1.14k
    p_meta->i_record_entries_count = GetWLE( p_peek + ASF_OBJECT_COMMON_SIZE );
381
382
1.14k
    p_data = p_peek + 26;
383
384
1.14k
    p_meta->record = calloc( p_meta->i_record_entries_count,
385
1.14k
                             sizeof(asf_metadata_record_t) );
386
1.14k
    if( !p_meta->record )
387
0
    {
388
0
        p_meta->i_record_entries_count = 0;
389
0
        return VLC_ENOMEM;
390
0
    }
391
392
5.36k
    for( i = 0; i < p_meta->i_record_entries_count; i++ )
393
4.60k
    {
394
4.60k
        asf_metadata_record_t *p_record = &p_meta->record[i];
395
4.60k
        uint16_t i_name;
396
4.60k
        uint32_t i_data;
397
398
4.60k
        if( !ASF_HAVE( 2+2+2+2+4 ) )
399
0
            break;
400
401
4.60k
        if( ASF_READ2() != 0 )
402
54
            break;
403
404
4.54k
        p_record->i_stream = ASF_READ2();
405
4.54k
        i_name = ASF_READ2();
406
4.54k
        p_record->i_type = ASF_READ2();
407
4.54k
        i_data = ASF_READ4();
408
409
4.54k
        if( UINT32_MAX - i_name < i_data ||
410
4.54k
            !ASF_HAVE( i_name + i_data ) )
411
329
            break;
412
413
        /* Read name */
414
4.22k
        p_record->psz_name = ASF_READS( i_name );
415
416
        /* Read data */
417
4.22k
        if( p_record->i_type == ASF_METADATA_TYPE_STRING )
418
2.19k
        {
419
2.19k
            p_record->p_data = (uint8_t *)ASF_READS( i_data );
420
2.19k
            if( p_record->p_data )
421
2.19k
                p_record->i_data = i_data/2; /* FIXME Is that needed ? */
422
2.19k
        }
423
2.02k
        else if( p_record->i_type == ASF_METADATA_TYPE_BYTE )
424
397
        {
425
397
            p_record->p_data = malloc( i_data );
426
397
            if( p_record->p_data )
427
397
            {
428
397
                p_record->i_data = i_data;
429
397
                if( p_record->p_data && i_data > 0 )
430
396
                    memcpy( p_record->p_data, p_data, i_data );
431
397
            }
432
397
            p_data += i_data;
433
397
        }
434
1.62k
        else if( p_record->i_type == ASF_METADATA_TYPE_QWORD )
435
0
        {
436
0
            p_record->i_val = ASF_READ8();
437
0
        }
438
1.62k
        else if( p_record->i_type == ASF_METADATA_TYPE_DWORD )
439
175
        {
440
175
            p_record->i_val = ASF_READ4();
441
175
        }
442
1.45k
        else if( p_record->i_type == ASF_METADATA_TYPE_WORD )
443
0
        {
444
0
            p_record->i_val = ASF_READ2();
445
0
        }
446
1.45k
        else if( p_record->i_type == ASF_METADATA_TYPE_BOOL )
447
647
        {
448
647
            p_record->i_val = ASF_READ2();
449
647
        }
450
803
        else
451
803
        {
452
            /* Unknown */
453
803
            p_data += i_data;
454
803
        }
455
4.22k
    }
456
1.14k
    p_meta->i_record_entries_count = i;
457
458
1.14k
#ifdef ASF_DEBUG
459
1.14k
    msg_Dbg( s,
460
1.14k
             "read \"metadata object\" %"PRIu32" entries",
461
1.14k
            p_meta->i_record_entries_count );
462
5.36k
    for( uint32_t j = 0; j < p_meta->i_record_entries_count; j++ )
463
4.22k
    {
464
4.22k
        asf_metadata_record_t *p_rec = &p_meta->record[j];
465
466
4.22k
        if( p_rec->i_type == ASF_METADATA_TYPE_STRING )
467
4.22k
            msg_Dbg( s, "  - %s=%s",
468
2.02k
                     p_rec->psz_name, p_rec->p_data );
469
2.02k
        else if( p_rec->i_type == ASF_METADATA_TYPE_BYTE )
470
2.02k
            msg_Dbg( s, "  - %s (%u bytes)",
471
1.62k
                     p_rec->psz_name, p_rec->i_data );
472
1.62k
        else
473
1.62k
            msg_Dbg( s, "  - %s=%"PRIu64,
474
4.22k
                     p_rec->psz_name, p_rec->i_val );
475
4.22k
    }
476
1.14k
#endif
477
478
1.14k
    return VLC_SUCCESS;
479
1.14k
}
480
481
static int ASF_ReadObject_header_extension( stream_t *s, asf_object_t *p_obj )
482
6.67k
{
483
6.67k
    asf_object_header_extension_t *p_he = &p_obj->header_extension;
484
6.67k
    const uint8_t *p_peek;
485
486
6.67k
    if( p_he->i_object_size > INT32_MAX )
487
3
        return VLC_EGENERIC;
488
489
6.66k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_he->i_object_size );
490
6.66k
    if( i_peek < 46 )
491
1
       return VLC_EGENERIC;
492
493
6.66k
    ASF_GetGUID( &p_he->i_reserved1, p_peek + ASF_OBJECT_COMMON_SIZE );
494
6.66k
    p_he->i_reserved2 = GetWLE( p_peek + 40 );
495
6.66k
    p_he->i_header_extension_size = GetDWLE( p_peek + 42 );
496
6.66k
    if( p_he->i_header_extension_size )
497
1.25k
    {
498
1.25k
        if( (unsigned int)(i_peek-46) < p_he->i_header_extension_size )
499
3
            return VLC_EGENERIC;
500
501
1.25k
        p_he->p_header_extension_data =
502
1.25k
            malloc( p_he->i_header_extension_size );
503
1.25k
        if( !p_he->p_header_extension_data )
504
0
            return VLC_ENOMEM;
505
506
1.25k
        memcpy( p_he->p_header_extension_data, p_peek + 46,
507
1.25k
                p_he->i_header_extension_size );
508
1.25k
    }
509
5.41k
    else
510
5.41k
    {
511
5.41k
        p_he->p_header_extension_data = NULL;
512
5.41k
        p_he->i_header_extension_size = 0;
513
5.41k
    }
514
515
6.66k
#ifdef ASF_DEBUG
516
6.66k
    msg_Dbg( s,
517
6.66k
            "read \"header extension object\" reserved1:" GUID_FMT
518
6.66k
            " reserved2:%u header_extension_size:%"PRIu32,
519
6.66k
            GUID_PRINT( p_he->i_reserved1 ), p_he->i_reserved2,
520
6.66k
            p_he->i_header_extension_size );
521
6.66k
#endif
522
523
6.66k
    if( !p_he->i_header_extension_size ) return VLC_SUCCESS;
524
525
    /* Read the extension objects */
526
1.25k
    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
1.25k
    for( ; ; )
533
6.22k
    {
534
6.22k
        asf_object_t *p_child = malloc( sizeof( asf_object_t ) );
535
536
6.22k
        if( p_child == NULL
537
6.22k
         || ASF_ReadObject( s, p_child, (asf_object_t*)p_he ) )
538
148
        {
539
148
            free( p_child );
540
148
            break;
541
148
        }
542
543
6.08k
        if( ASF_NextObject( s, p_child, 0 ) ) /* Go to the next object */
544
1.10k
        {
545
1.10k
            break;
546
1.10k
        }
547
6.08k
    }
548
549
1.25k
    return VLC_SUCCESS;
550
1.25k
}
551
552
static void ASF_FreeObject_header_extension( asf_object_t *p_obj )
553
6.66k
{
554
6.66k
    asf_object_header_extension_t *p_he = &p_obj->header_extension;
555
556
6.66k
    FREENULL( p_he->p_header_extension_data );
557
6.66k
}
558
559
static int ASF_ReadObject_stream_properties( stream_t *s, asf_object_t *p_obj )
560
7.72k
{
561
7.72k
    asf_object_stream_properties_t *p_sp = &p_obj->stream_properties;
562
7.72k
    const uint8_t *p_peek;
563
564
7.72k
#if UINT64_MAX > SSIZE_MAX
565
7.72k
    if( p_sp->i_object_size > SSIZE_MAX )
566
9
    {
567
9
        msg_Err( s, "unable to peek: object size is too large" );
568
9
        return VLC_EGENERIC;
569
9
    }
570
7.71k
#endif
571
572
7.71k
    if( p_sp->i_object_size > INT32_MAX )
573
6
        return VLC_EGENERIC;
574
575
7.71k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_sp->i_object_size );
576
7.71k
    if( i_peek < 78 )
577
0
       return VLC_EGENERIC;
578
579
7.71k
    ASF_GetGUID( &p_sp->i_stream_type, p_peek + ASF_OBJECT_COMMON_SIZE );
580
7.71k
    ASF_GetGUID( &p_sp->i_error_correction_type, p_peek + 40 );
581
7.71k
    p_sp->i_time_offset = GetQWLE( p_peek + 56 );
582
7.71k
    p_sp->i_type_specific_data_length = GetDWLE( p_peek + 64 );
583
7.71k
    p_sp->i_error_correction_data_length = GetDWLE( p_peek + 68 );
584
7.71k
    p_sp->i_flags = GetWLE( p_peek + 72 );
585
7.71k
    p_sp->i_stream_number = p_sp->i_flags&0x07f;
586
7.71k
    if ( p_sp->i_stream_number > ASF_MAX_STREAMNUMBER )
587
0
        return VLC_EGENERIC;
588
7.71k
    p_sp->i_reserved = GetDWLE( p_peek + 74 );
589
7.71k
    i_peek -= 78;
590
591
7.71k
    if( p_sp->i_type_specific_data_length )
592
7.68k
    {
593
7.68k
        if( i_peek < p_sp->i_type_specific_data_length )
594
16
            return VLC_EGENERIC;
595
596
7.66k
        p_sp->p_type_specific_data =
597
7.66k
            malloc( p_sp->i_type_specific_data_length );
598
7.66k
        if( !p_sp->p_type_specific_data )
599
0
            return VLC_ENOMEM;
600
601
7.66k
        memcpy( p_sp->p_type_specific_data, p_peek + 78,
602
7.66k
                p_sp->i_type_specific_data_length );
603
7.66k
        i_peek -= p_sp->i_type_specific_data_length;
604
7.66k
    }
605
606
7.69k
    if( p_sp->i_error_correction_data_length )
607
780
    {
608
780
        if( i_peek < p_sp->i_error_correction_data_length )
609
4
        {
610
4
            free( p_sp->p_type_specific_data );
611
4
            return VLC_EGENERIC;
612
4
        }
613
614
776
        p_sp->p_error_correction_data =
615
776
            malloc( p_sp->i_error_correction_data_length );
616
776
        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
776
        memcpy( p_sp->p_error_correction_data,
622
776
                p_peek + 78 + p_sp->i_type_specific_data_length,
623
776
                p_sp->i_error_correction_data_length );
624
776
    }
625
626
7.69k
#ifdef ASF_DEBUG
627
7.69k
    msg_Dbg( s,
628
7.69k
            "read \"stream Properties object\" stream_type:" GUID_FMT
629
7.69k
            " error_correction_type:" GUID_FMT " time_offset:%"PRIu64
630
7.69k
            " type_specific_data_length:%"PRIu32" error_correction_data_length:%"PRIu32
631
7.69k
            " flags:0x%x stream_number:%u",
632
7.69k
            GUID_PRINT( p_sp->i_stream_type ),
633
7.69k
            GUID_PRINT( p_sp->i_error_correction_type ),
634
7.69k
            p_sp->i_time_offset,
635
7.69k
            p_sp->i_type_specific_data_length,
636
7.69k
            p_sp->i_error_correction_data_length,
637
7.69k
            p_sp->i_flags,
638
7.69k
            p_sp->i_stream_number );
639
640
7.69k
#endif
641
7.69k
    return VLC_SUCCESS;
642
7.69k
}
643
644
static void ASF_FreeObject_stream_properties( asf_object_t *p_obj )
645
7.69k
{
646
7.69k
    asf_object_stream_properties_t *p_sp = &p_obj->stream_properties;
647
648
7.69k
    FREENULL( p_sp->p_type_specific_data );
649
7.69k
    FREENULL( p_sp->p_error_correction_data );
650
7.69k
}
651
652
static void ASF_FreeObject_codec_list( asf_object_t *p_obj )
653
1.04k
{
654
1.04k
    asf_object_codec_list_t *p_cl = &p_obj->codec_list;
655
656
1.04k
    for( asf_codec_entry_t *codec = p_cl->codecs, *next;
657
3.15k
         codec != NULL;
658
2.10k
         codec = next )
659
2.10k
    {
660
2.10k
        next = codec->p_next;
661
2.10k
        free( codec->psz_name );
662
2.10k
        free( codec->psz_description );
663
2.10k
        free( codec->p_information );
664
2.10k
        free( codec );
665
2.10k
    }
666
1.04k
}
667
668
static int ASF_ReadObject_codec_list( stream_t *s, asf_object_t *p_obj )
669
1.04k
{
670
1.04k
    asf_object_codec_list_t *p_cl = &p_obj->codec_list;
671
1.04k
    const uint8_t *p_peek, *p_data;
672
673
1.04k
    if( p_cl->i_object_size > INT32_MAX )
674
2
        return VLC_EGENERIC;
675
676
1.04k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_cl->i_object_size );
677
1.04k
    if( i_peek < 44 )
678
0
       return VLC_EGENERIC;
679
680
1.04k
    ASF_GetGUID( &p_cl->i_reserved, p_peek + ASF_OBJECT_COMMON_SIZE );
681
1.04k
    uint32_t count = GetDWLE( p_peek + 40 );
682
1.04k
#ifdef ASF_DEBUG
683
1.04k
    msg_Dbg( s, "read \"codec list object\" reserved_guid:" GUID_FMT
684
1.04k
             " codec_entries_count:%u", GUID_PRINT( p_cl->i_reserved ),
685
1.04k
             count );
686
1.04k
#endif
687
688
1.04k
    p_data = p_peek + 44;
689
690
1.04k
    asf_codec_entry_t **pp = &p_cl->codecs;
691
692
3.15k
    for( uint32_t i = 0; i < count; i++ )
693
2.11k
    {
694
2.11k
        asf_codec_entry_t *p_codec = malloc( sizeof( *p_codec ) );
695
696
2.11k
        if( unlikely(p_codec == NULL) || !ASF_HAVE( 2+2+2 ) )
697
12
        {
698
12
            free( p_codec );
699
12
            *pp = NULL;
700
12
            goto error;
701
12
        }
702
703
        /* */
704
2.10k
        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
2.10k
        p_codec->psz_name = ASF_READS( 2*ASF_READ2() );
711
712
        /* description */
713
2.10k
        p_codec->psz_description = ASF_READS( 2*ASF_READ2() );
714
715
        /* opaque information */
716
2.10k
        p_codec->i_information_length = ASF_READ2();
717
2.10k
        if( ASF_HAVE( p_codec->i_information_length ) )
718
1.79k
        {
719
1.79k
            p_codec->p_information = malloc( p_codec->i_information_length );
720
1.79k
            if( likely(p_codec->p_information != NULL) )
721
1.79k
                memcpy( p_codec->p_information, p_data,
722
1.79k
                        p_codec->i_information_length );
723
1.79k
            p_data += p_codec->i_information_length;
724
1.79k
        }
725
314
        else
726
314
            p_codec->p_information = NULL;
727
728
2.10k
#ifdef ASF_DEBUG
729
2.10k
        msg_Dbg( s, "  - codec[%"PRIu32"] %s name:\"%s\" "
730
2.10k
                 "description:\"%s\" information_length:%u", i,
731
2.10k
                 ( p_codec->i_type == ASF_CODEC_TYPE_VIDEO ) ? "video"
732
2.10k
                 : ( ( p_codec->i_type == ASF_CODEC_TYPE_AUDIO ) ? "audio"
733
2.10k
                 : "unknown" ), p_codec->psz_name,
734
2.10k
                 p_codec->psz_description, p_codec->i_information_length );
735
2.10k
#endif
736
2.10k
        *pp = p_codec;
737
2.10k
        pp = &p_codec->p_next;
738
2.10k
    }
739
740
1.03k
    *pp = NULL;
741
1.03k
    return VLC_SUCCESS;
742
743
12
error:
744
12
    ASF_FreeObject_codec_list( p_obj );
745
12
    return VLC_EGENERIC;
746
1.04k
}
747
748
static inline char *get_wstring( const uint8_t *p_data, size_t i_size )
749
4.30k
{
750
4.30k
    char *psz_str = FromCharset( "UTF-16LE", p_data, i_size );
751
4.30k
    if( psz_str )
752
4.18k
        p_data += i_size;
753
4.30k
    return psz_str;
754
4.30k
}
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
861
{
760
861
    asf_object_content_description_t *p_cd = &p_obj->content_description;
761
861
    const uint8_t *p_peek, *p_data;
762
861
    uint16_t i_title, i_artist, i_copyright, i_description, i_rating;
763
764
861
    if( p_cd->i_object_size > INT32_MAX )
765
0
        return VLC_EGENERIC;
766
767
861
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_cd->i_object_size );
768
861
    if( i_peek < 34 )
769
0
       return VLC_EGENERIC;
770
771
861
    p_data = p_peek + ASF_OBJECT_COMMON_SIZE;
772
773
861
    i_title         = ASF_READ2();
774
861
    i_artist        = ASF_READ2();
775
861
    i_copyright     = ASF_READ2();
776
861
    i_description   = ASF_READ2();
777
861
    i_rating        = ASF_READ2();
778
779
861
    if( !ASF_HAVE( i_title+i_artist+i_copyright+i_description+i_rating ) )
780
1
        return VLC_EGENERIC;
781
782
860
    p_cd->psz_title = get_wstring( p_data, i_title );
783
860
    p_cd->psz_artist = get_wstring( p_data, i_artist );
784
860
    p_cd->psz_copyright = get_wstring( p_data, i_copyright );
785
860
    p_cd->psz_description = get_wstring( p_data, i_description );
786
860
    p_cd->psz_rating = get_wstring( p_data, i_rating );
787
788
860
#ifdef ASF_DEBUG
789
860
    msg_Dbg( s,
790
860
             "read \"content description object\" title:\"%s\" artist:\"%s\" copyright:\"%s\" description:\"%s\" rating:\"%s\"",
791
860
             p_cd->psz_title,
792
860
             p_cd->psz_artist,
793
860
             p_cd->psz_copyright,
794
860
             p_cd->psz_description,
795
860
             p_cd->psz_rating );
796
860
#endif
797
798
860
    return VLC_SUCCESS;
799
861
}
800
801
static void ASF_FreeObject_content_description( asf_object_t *p_obj)
802
860
{
803
860
    asf_object_content_description_t *p_cd = &p_obj->content_description;
804
805
860
    FREENULL( p_cd->psz_title );
806
860
    FREENULL( p_cd->psz_artist );
807
860
    FREENULL( p_cd->psz_copyright );
808
860
    FREENULL( p_cd->psz_description );
809
860
    FREENULL( p_cd->psz_rating );
810
860
}
811
812
/* Language list: */
813
static int ASF_ReadObject_language_list(stream_t *s, asf_object_t *p_obj)
814
953
{
815
953
    asf_object_language_list_t *p_ll = &p_obj->language_list;
816
953
    const uint8_t *p_peek, *p_data;
817
953
    uint16_t i;
818
819
953
    if( p_ll->i_object_size > INT32_MAX )
820
28
        return VLC_EGENERIC;
821
822
925
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_ll->i_object_size );
823
925
    if( i_peek < 26 )
824
4
       return VLC_EGENERIC;
825
826
921
    p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
827
828
921
    p_ll->i_language = ASF_READ2();
829
921
    if( p_ll->i_language > 0 )
830
919
    {
831
919
        p_ll->ppsz_language = calloc( p_ll->i_language, sizeof( char *) );
832
919
        if( !p_ll->ppsz_language )
833
0
            return VLC_ENOMEM;
834
835
35.5k
        for( i = 0; i < p_ll->i_language; i++ )
836
34.6k
        {
837
34.6k
            if( !ASF_HAVE(1) )
838
55
                break;
839
34.6k
            p_ll->ppsz_language[i] = ASF_READS( ASF_READ1() );
840
34.6k
        }
841
919
        p_ll->i_language = i;
842
919
    }
843
844
921
#ifdef ASF_DEBUG
845
921
    msg_Dbg( s, "read \"language list object\" %u entries",
846
921
             p_ll->i_language );
847
35.5k
    for( i = 0; i < p_ll->i_language; i++ )
848
34.6k
        msg_Dbg( s, "  - '%s'",
849
921
                 p_ll->ppsz_language[i] );
850
921
#endif
851
921
    return VLC_SUCCESS;
852
921
}
853
854
static void ASF_FreeObject_language_list( asf_object_t *p_obj)
855
921
{
856
921
    asf_object_language_list_t *p_ll = &p_obj->language_list;
857
921
    uint16_t i;
858
859
35.5k
    for( i = 0; i < p_ll->i_language; i++ )
860
34.6k
        FREENULL( p_ll->ppsz_language[i] );
861
921
    FREENULL( p_ll->ppsz_language );
862
921
}
863
864
/* Stream bitrate properties */
865
static int ASF_ReadObject_stream_bitrate_properties( stream_t *s,
866
                                                     asf_object_t *p_obj)
867
677
{
868
677
    asf_object_stream_bitrate_properties_t *p_sb = &p_obj->stream_bitrate;
869
677
    const uint8_t *p_peek, *p_data;
870
677
    uint16_t i;
871
872
677
    if( p_sb->i_object_size > INT32_MAX )
873
5
        return VLC_EGENERIC;
874
875
672
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_sb->i_object_size );
876
672
    if( i_peek < 26 )
877
0
       return VLC_EGENERIC;
878
879
672
    p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
880
881
672
    p_sb->i_bitrate = ASF_READ2();
882
672
    if( p_sb->i_bitrate > ASF_MAX_STREAMNUMBER )
883
22
        p_sb->i_bitrate = ASF_MAX_STREAMNUMBER;  /* Buggy ? */
884
2.09k
    for( i = 0; i < p_sb->i_bitrate; i++ )
885
1.44k
    {
886
1.44k
        if( !ASF_HAVE(2 + 4) )
887
22
            break;
888
1.42k
        p_sb->bitrate[i].i_stream_number = (uint8_t) ASF_READ2()& 0x7f;
889
1.42k
        if ( p_sb->bitrate[i].i_stream_number > ASF_MAX_STREAMNUMBER )
890
0
            return VLC_EGENERIC;
891
1.42k
        p_sb->bitrate[i].i_avg_bitrate = ASF_READ4();
892
1.42k
    }
893
672
    p_sb->i_bitrate = i;
894
895
672
#ifdef ASF_DEBUG
896
672
    msg_Dbg( s,"read \"stream bitrate properties object\"" );
897
2.09k
    for( i = 0; i < p_sb->i_bitrate; i++ )
898
1.42k
    {
899
1.42k
        msg_Dbg( s,"  - stream=%u bitrate=%"PRIu32,
900
1.42k
                 p_sb->bitrate[i].i_stream_number,
901
1.42k
                 p_sb->bitrate[i].i_avg_bitrate );
902
1.42k
    }
903
672
#endif
904
672
    return VLC_SUCCESS;
905
672
}
906
static void ASF_FreeObject_stream_bitrate_properties( asf_object_t *p_obj)
907
672
{
908
672
    VLC_UNUSED(p_obj);
909
672
}
910
911
static void ASF_FreeObject_extended_stream_properties( asf_object_t *p_obj)
912
624
{
913
624
    asf_object_extended_stream_properties_t *p_esp = &p_obj->ext_stream;
914
915
624
    if ( p_esp->p_ext )
916
624
    {
917
8.61k
        for( uint16_t i = 0; i < p_esp->i_payload_extension_system_count; i++ )
918
7.99k
            free( p_esp->p_ext[i].pi_info );
919
624
        FREENULL( p_esp->p_ext );
920
624
    }
921
71.0k
    for( uint16_t i = 0; i < p_esp->i_stream_name_count; i++ )
922
70.4k
        FREENULL( p_esp->ppsz_stream_name[i] );
923
624
    FREENULL( p_esp->pi_stream_name_language );
924
624
    FREENULL( p_esp->ppsz_stream_name );
925
624
}
926
927
static int ASF_ReadObject_extended_stream_properties( stream_t *s,
928
                                                      asf_object_t *p_obj)
929
637
{
930
637
    asf_object_extended_stream_properties_t *p_esp = &p_obj->ext_stream;
931
637
    const uint8_t *p_peek, *p_data;
932
637
    uint16_t i;
933
934
637
    if( p_esp->i_object_size > INT32_MAX )
935
1
        return VLC_EGENERIC;
936
937
636
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_esp->i_object_size );
938
636
    if( i_peek < 88 )
939
7
       return VLC_EGENERIC;
940
941
629
    p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
942
943
629
    p_esp->i_start_time = GetQWLE( &p_data[0] );
944
629
    p_esp->i_end_time = GetQWLE( &p_data[8] );
945
629
    p_esp->i_data_bitrate = GetDWLE( &p_data[16] );
946
629
    p_esp->i_buffer_size = GetDWLE( &p_data[20] );
947
629
    p_esp->i_initial_buffer_fullness = GetDWLE( &p_data[ASF_OBJECT_COMMON_SIZE] );
948
629
    p_esp->i_alternate_data_bitrate = GetDWLE( &p_data[28] );
949
629
    p_esp->i_alternate_buffer_size = GetDWLE( &p_data[32] );
950
629
    p_esp->i_alternate_initial_buffer_fullness = GetDWLE( &p_data[36] );
951
629
    p_esp->i_maximum_object_size = GetDWLE( &p_data[40] );
952
629
    p_esp->i_flags = GetDWLE( &p_data[44] );
953
629
    p_esp->i_stream_number = GetWLE( &p_data[48] );
954
629
    if ( p_esp->i_stream_number > ASF_MAX_STREAMNUMBER )
955
5
        return VLC_EGENERIC;
956
624
    p_esp->i_language_index = GetWLE( &p_data[50] );
957
624
    p_esp->i_average_time_per_frame= GetQWLE( &p_data[52] );
958
624
    p_esp->i_stream_name_count = GetWLE( &p_data[60] );
959
624
    p_esp->i_payload_extension_system_count = GetWLE( &p_data[62] );
960
961
624
    p_data += 64;
962
963
624
    p_esp->pi_stream_name_language = calloc( p_esp->i_stream_name_count,
964
624
                                             sizeof(*p_esp->pi_stream_name_language) );
965
624
    p_esp->ppsz_stream_name = calloc( p_esp->i_stream_name_count,
966
624
                                      sizeof(*p_esp->ppsz_stream_name) );
967
624
    if( !p_esp->pi_stream_name_language ||
968
624
        !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
71.0k
    for( i = 0; i < p_esp->i_stream_name_count; i++ )
975
70.5k
    {
976
70.5k
        if( !ASF_HAVE( 2+2 ) )
977
64
            break;
978
70.4k
        p_esp->pi_stream_name_language[i] = ASF_READ2();
979
70.4k
        p_esp->ppsz_stream_name[i] = ASF_READS( ASF_READ2() );
980
70.4k
    }
981
624
    p_esp->i_stream_name_count = i;
982
983
624
    p_esp->p_ext = calloc( p_esp->i_payload_extension_system_count,
984
624
                           sizeof( asf_payload_extension_system_t ) );
985
624
    if ( p_esp->p_ext )
986
624
    {
987
8.61k
        for( i = 0; i < p_esp->i_payload_extension_system_count; i++ )
988
8.24k
        {
989
8.24k
            asf_payload_extension_system_t *p_ext = & p_esp->p_ext[i];
990
8.24k
            if( !ASF_HAVE( 16+2+4 ) ) break;
991
8.14k
            ASF_GetGUID( &p_ext->i_extension_id, p_data );
992
8.14k
            ASF_SKIP( 16 );   // GUID
993
8.14k
            p_ext->i_data_size = ASF_READ2();
994
8.14k
            p_ext->i_info_length = ASF_READ4();
995
8.14k
            if ( p_ext->i_info_length )
996
327
            {
997
327
                if( !ASF_HAVE( p_ext->i_info_length ) ) break;
998
181
                p_ext->pi_info = malloc( p_ext->i_info_length );
999
181
                if ( p_ext->pi_info )
1000
181
                    memcpy( p_ext->pi_info, p_data, p_ext->i_info_length );
1001
181
                ASF_SKIP( p_ext->i_info_length );
1002
181
            }
1003
8.14k
        }
1004
624
        p_esp->i_payload_extension_system_count = i;
1005
624
    } else p_esp->i_payload_extension_system_count = 0;
1006
1007
624
    p_esp->p_sp = NULL;
1008
1009
    /* Read tail objects */
1010
624
    if( p_data < &p_peek[i_peek] )
1011
169
    {
1012
169
        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
169
        asf_object_t *p_sp = malloc( sizeof( asf_object_t ) );
1019
169
        if( !p_sp || ASF_ReadObject( s, p_sp, NULL ) )
1020
60
        {
1021
60
            free( p_sp );
1022
60
        }
1023
109
        else
1024
109
        {
1025
            /* This p_sp will be inserted by ReadRoot later */
1026
109
            p_esp->p_sp = (asf_object_stream_properties_t*)p_sp;
1027
109
            ASF_ParentObject( p_obj, p_sp );
1028
109
        }
1029
169
    }
1030
1031
624
#ifdef ASF_DEBUG
1032
624
    msg_Dbg( s, "read \"extended stream properties object\":" );
1033
624
    msg_Dbg( s, "  - start=%"PRIu64" end=%"PRIu64,
1034
624
             p_esp->i_start_time, p_esp->i_end_time );
1035
624
    msg_Dbg( s, "  - data bitrate=%"PRId32" buffer=%"PRId32" initial fullness=%"PRId32,
1036
624
             p_esp->i_data_bitrate,
1037
624
             p_esp->i_buffer_size,
1038
624
             p_esp->i_initial_buffer_fullness );
1039
624
    msg_Dbg( s, "  - alternate data bitrate=%"PRId32" buffer=%"PRId32" initial fullness=%"PRId32,
1040
624
             p_esp->i_alternate_data_bitrate,
1041
624
             p_esp->i_alternate_buffer_size,
1042
624
             p_esp->i_alternate_initial_buffer_fullness );
1043
624
    msg_Dbg( s, "  - maximum object size=%"PRId32, p_esp->i_maximum_object_size );
1044
624
    msg_Dbg( s, "  - flags=0x%x", p_esp->i_flags );
1045
624
    msg_Dbg( s, "  - stream number=%u language=%u",
1046
624
             p_esp->i_stream_number, p_esp->i_language_index );
1047
624
    msg_Dbg( s, "  - average time per frame=%"PRIu64,
1048
624
             p_esp->i_average_time_per_frame );
1049
624
    msg_Dbg( s, "  - stream name count=%u", p_esp->i_stream_name_count );
1050
71.0k
    for( i = 0; i < p_esp->i_stream_name_count; i++ )
1051
70.4k
        msg_Dbg( s, "     - lang id=%u name=%s",
1052
624
                 p_esp->pi_stream_name_language[i],
1053
624
                 p_esp->ppsz_stream_name[i] );
1054
624
    msg_Dbg( s, "  - payload extension system count=%u",
1055
624
             p_esp->i_payload_extension_system_count );
1056
8.61k
    for( i = 0; i < p_esp->i_payload_extension_system_count; i++ )
1057
7.99k
        msg_Dbg( s, "  - %u  - payload extension: " GUID_FMT, i,
1058
624
                 GUID_PRINT( p_esp->p_ext[i].i_extension_id ) );
1059
624
#endif
1060
624
    return VLC_SUCCESS;
1061
624
}
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
0
{
1127
0
    asf_object_stream_prioritization_t *p_sp = &p_obj->stream_prioritization;
1128
0
    const uint8_t *p_peek, *p_data;
1129
0
    uint16_t i;
1130
1131
0
    if( p_sp->i_object_size > INT32_MAX )
1132
0
        return VLC_EGENERIC;
1133
1134
0
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_sp->i_object_size );
1135
0
    if( i_peek < 26 )
1136
0
       return VLC_EGENERIC;
1137
1138
0
    p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
1139
1140
0
    p_sp->i_priority_count = ASF_READ2();
1141
1142
0
    p_sp->pi_priority_flag = calloc( p_sp->i_priority_count,
1143
0
                                     sizeof(*p_sp->pi_priority_flag) );
1144
0
    p_sp->pi_priority_stream_number = calloc( p_sp->i_priority_count,
1145
0
                                              sizeof(*p_sp->pi_priority_stream_number) );
1146
1147
0
    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
0
    for( i = 0; i < p_sp->i_priority_count; i++ )
1155
0
    {
1156
0
        if( !ASF_HAVE(2+2) )
1157
0
            break;
1158
0
        p_sp->pi_priority_stream_number[i] = ASF_READ2();
1159
0
        p_sp->pi_priority_flag[i] = ASF_READ2();
1160
0
    }
1161
0
    p_sp->i_priority_count = i;
1162
1163
0
#ifdef ASF_DEBUG
1164
0
    msg_Dbg( s, "read \"stream prioritization object\"" );
1165
0
    for( i = 0; i < p_sp->i_priority_count; i++ )
1166
0
        msg_Dbg( s, "  - Stream:%u flags=0x%x",
1167
0
                 p_sp->pi_priority_stream_number[i],
1168
0
                 p_sp->pi_priority_flag[i] );
1169
0
#endif
1170
0
    return VLC_SUCCESS;
1171
0
}
1172
static void ASF_FreeObject_stream_prioritization( asf_object_t *p_obj)
1173
0
{
1174
0
    asf_object_stream_prioritization_t *p_sp = &p_obj->stream_prioritization;
1175
1176
0
    FREENULL( p_sp->pi_priority_stream_number );
1177
0
    FREENULL( p_sp->pi_priority_flag );
1178
0
}
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
1.32k
{
1245
1.32k
    asf_object_extended_content_description_t *p_ec =
1246
1.32k
                                        &p_obj->extended_content_description;
1247
1.32k
    const uint8_t *p_peek, *p_data;
1248
1.32k
    uint16_t i;
1249
1250
1.32k
    if( p_ec->i_object_size > INT32_MAX )
1251
2
        return VLC_EGENERIC;
1252
1253
1.32k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_ec->i_object_size );
1254
1.32k
    if( i_peek < 26 )
1255
0
       return VLC_EGENERIC;
1256
1257
1.32k
    p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
1258
1259
1.32k
    p_ec->i_count = ASF_READ2();
1260
1.32k
    p_ec->ppsz_name  = calloc( p_ec->i_count, sizeof(char*) );
1261
1.32k
    p_ec->ppsz_value = calloc( p_ec->i_count, sizeof(char*) );
1262
1.32k
    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
45.7k
    for( i = 0; i < p_ec->i_count; i++ )
1269
44.6k
    {
1270
44.6k
        uint16_t i_size;
1271
44.6k
        uint16_t i_type;
1272
1273
44.6k
        if( !ASF_HAVE(2 + 2+2) )
1274
265
            break;
1275
1276
44.3k
        p_ec->ppsz_name[i] = ASF_READS( ASF_READ2() );
1277
1278
        /* Grrr */
1279
44.3k
        i_type = ASF_READ2();
1280
44.3k
        i_size = ASF_READ2();
1281
1282
44.3k
        if( i_type == ASF_METADATA_TYPE_STRING )
1283
35.9k
        {
1284
            /* Unicode string */
1285
35.9k
            p_ec->ppsz_value[i] = ASF_READS( i_size );
1286
35.9k
        }
1287
8.39k
        else if( i_type == ASF_METADATA_TYPE_BYTE )
1288
1.21k
        {
1289
            /* Byte array */
1290
1.21k
            static const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
1291
1.21k
                                         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
1292
1293
1.21k
            p_ec->ppsz_value[i] = malloc( 2*i_size + 1 );
1294
1.21k
            if( p_ec->ppsz_value[i] )
1295
1.21k
            {
1296
1.21k
                char *psz_value = p_ec->ppsz_value[i];
1297
299k
                for( int j = 0; j < i_size; j++ )
1298
298k
                {
1299
298k
                    const uint8_t v = ASF_READ1();
1300
298k
                    psz_value[2*j+0] = hex[v>>4];
1301
298k
                    psz_value[2*j+1] = hex[v&0xf];
1302
298k
                }
1303
1.21k
                psz_value[2*i_size] = '\0';
1304
1.21k
            }
1305
1.21k
        }
1306
7.18k
        else if( i_type == ASF_METADATA_TYPE_BOOL )
1307
1.80k
        {
1308
            /* Bool */
1309
1.80k
            p_ec->ppsz_value[i] = strdup( ASF_READ1() ? "true" : "false" );
1310
1.80k
            ASF_SKIP(i_size-1);
1311
1.80k
        }
1312
5.37k
        else if( i_type == ASF_METADATA_TYPE_DWORD )
1313
943
        {
1314
            /* DWord */
1315
943
            if( asprintf( &p_ec->ppsz_value[i], "%u", ASF_READ4() ) == -1 )
1316
0
                p_ec->ppsz_value[i] = NULL;
1317
943
        }
1318
4.42k
        else if( i_type == ASF_METADATA_TYPE_QWORD )
1319
11
        {
1320
            /* QWord */
1321
11
            if( asprintf( &p_ec->ppsz_value[i], "%"PRIu64, ASF_READ8() ) == -1 )
1322
0
                p_ec->ppsz_value[i] = NULL;
1323
11
        }
1324
4.41k
        else if( i_type == ASF_METADATA_TYPE_WORD )
1325
225
        {
1326
            /* Word */
1327
225
            if( asprintf( &p_ec->ppsz_value[i], "%u", ASF_READ2() ) == -1 )
1328
0
                p_ec->ppsz_value[i] = NULL;
1329
225
        }
1330
4.19k
        else
1331
4.19k
        {
1332
4.19k
            p_ec->ppsz_value[i] = NULL;
1333
4.19k
            ASF_SKIP(i_size);
1334
4.19k
        }
1335
44.3k
    }
1336
1.32k
    p_ec->i_count = i;
1337
1338
1.32k
#ifdef ASF_DEBUG
1339
1.32k
    msg_Dbg( s, "read \"extended content description object\"" );
1340
45.7k
    for( i = 0; i < p_ec->i_count; i++ )
1341
44.3k
        msg_Dbg( s, "  - '%s' = '%s'",
1342
1.32k
                 p_ec->ppsz_name[i],
1343
1.32k
                 p_ec->ppsz_value[i] );
1344
1.32k
#endif
1345
1.32k
    return VLC_SUCCESS;
1346
1.32k
}
1347
static void ASF_FreeObject_extended_content_description( asf_object_t *p_obj)
1348
1.32k
{
1349
1.32k
    asf_object_extended_content_description_t *p_ec =
1350
1.32k
                                        &p_obj->extended_content_description;
1351
1352
45.7k
    for( uint16_t i = 0; i < p_ec->i_count; i++ )
1353
44.3k
    {
1354
44.3k
        FREENULL( p_ec->ppsz_name[i] );
1355
44.3k
        FREENULL( p_ec->ppsz_value[i] );
1356
44.3k
    }
1357
1.32k
    FREENULL( p_ec->ppsz_name );
1358
1.32k
    FREENULL( p_ec->ppsz_value );
1359
1.32k
}
1360
1361
static int ASF_ReadObject_marker(stream_t *s, asf_object_t *p_obj)
1362
21
{
1363
21
    asf_object_marker_t *p_mk = (asf_object_marker_t *)p_obj;
1364
21
    const uint8_t *p_peek, *p_data;
1365
1366
21
    if( p_mk->i_object_size > INT32_MAX )
1367
0
        return VLC_EGENERIC;
1368
1369
21
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_mk->i_object_size );
1370
21
    if( i_peek < ASF_OBJECT_COMMON_SIZE )
1371
0
       return VLC_EGENERIC;
1372
1373
21
    p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
1374
1375
21
    if( !ASF_HAVE( 16+4+2+2 ) )
1376
0
        return VLC_EGENERIC;
1377
1378
21
    ASF_GetGUID( &p_mk->i_reserved1, p_data );
1379
21
    ASF_SKIP( 16 );
1380
21
    p_mk->i_count = ASF_READ4();
1381
21
    p_mk->i_reserved2 = ASF_READ2();
1382
21
    p_mk->name = ASF_READS( ASF_READ2() );
1383
1384
21
    if( p_mk->i_count > 0 )
1385
21
    {
1386
21
        p_mk->marker = calloc( p_mk->i_count,
1387
21
                              sizeof( asf_marker_t ) );
1388
21
        if( !p_mk->marker )
1389
0
            return VLC_ENOMEM;
1390
1391
412
        for( uint32_t i = 0; i < p_mk->i_count; i++ )
1392
412
        {
1393
412
            asf_marker_t *p_marker = &p_mk->marker[i];
1394
1395
412
            if( !ASF_HAVE(8+8+2+4+4+4) )
1396
21
                break;
1397
1398
391
            p_marker->i_offset = ASF_READ8();
1399
391
            p_marker->i_presentation_time = ASF_READ8();
1400
391
            p_marker->i_entry_length = ASF_READ2();
1401
391
            p_marker->i_send_time = ASF_READ4();
1402
391
            p_marker->i_flags = ASF_READ4();
1403
391
            p_marker->i_marker_description_length = ASF_READ4();
1404
391
            if( p_marker->i_marker_description_length <= (UINT32_MAX / 2) )
1405
362
                p_marker->p_marker_description = ASF_READS( p_marker->i_marker_description_length * 2 );
1406
29
            else
1407
29
                p_marker->i_marker_description_length = 0;
1408
391
        }
1409
21
    }
1410
1411
21
#ifdef ASF_DEBUG
1412
21
    msg_Dbg( s, "Read \"marker object\": %"PRIu32" chapters: %s", p_mk->i_count, p_mk->name );
1413
1414
839k
    for( unsigned i = 0; i < p_mk->i_count; i++ )
1415
839k
        msg_Dbg( s, "New chapter named: %s", p_mk->marker[i].p_marker_description );
1416
21
#endif
1417
21
    return VLC_SUCCESS;
1418
21
}
1419
static void ASF_FreeObject_marker( asf_object_t *p_obj)
1420
21
{
1421
21
    asf_object_marker_t *p_mk = (asf_object_marker_t *)p_obj;
1422
1423
839k
    for( uint32_t i = 0; i < p_mk->i_count; i++ )
1424
839k
    {
1425
839k
        FREENULL( p_mk->marker[i].p_marker_description  );
1426
839k
    }
1427
21
    FREENULL( p_mk->marker );
1428
21
    FREENULL( p_mk->name );
1429
21
}
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
753k
{
1500
753k
    if( p_father )
1501
753k
    {
1502
753k
        if( p_father->common.p_first )
1503
49.9k
        {
1504
49.9k
            p_father->common.p_last->common.p_next = p_obj;
1505
49.9k
        }
1506
703k
        else
1507
703k
        {
1508
703k
            p_father->common.p_first = p_obj;
1509
703k
        }
1510
753k
        p_father->common.p_last = p_obj;
1511
753k
    }
1512
753k
}
1513
1514
static const struct ASF_Object_Function_entry * ASF_GetObject_Function( const vlc_guid_t *id )
1515
1.50M
{
1516
2.50M
    for( size_t i = 0; i < ARRAY_SIZE(ASF_Object_Function); i++ )
1517
2.47M
    {
1518
2.47M
        if( guidcmp( ASF_Object_Function[i].p_id, id ) )
1519
1.47M
            return &ASF_Object_Function[i];
1520
2.47M
    }
1521
28.6k
    return NULL;
1522
1.50M
}
1523
1524
static int ASF_ReadObject( stream_t *s, asf_object_t *p_obj,
1525
                           asf_object_t *p_father )
1526
988k
{
1527
988k
    int i_result = VLC_SUCCESS;
1528
1529
988k
    if( !p_obj )
1530
0
        return VLC_SUCCESS;
1531
1532
988k
    memset( p_obj, 0, sizeof( *p_obj ) );
1533
1534
988k
    if( ASF_ReadObjectCommon( s, p_obj ) )
1535
234k
    {
1536
234k
        msg_Warn( s, "cannot read one asf object at %"PRIu64, vlc_stream_Tell(s) );
1537
234k
        return VLC_EGENERIC;
1538
234k
    }
1539
754k
    p_obj->common.p_father = p_father;
1540
754k
    p_obj->common.p_first = NULL;
1541
754k
    p_obj->common.p_next = NULL;
1542
754k
    p_obj->common.p_last = NULL;
1543
754k
    p_obj->common.i_type = 0;
1544
1545
754k
    if( p_obj->common.i_object_size < ASF_OBJECT_COMMON_SIZE )
1546
881
    {
1547
881
        msg_Warn( s, "found a corrupted asf object (size<24) at %"PRIu64, vlc_stream_Tell(s) );
1548
881
        return VLC_EGENERIC;
1549
881
    }
1550
1551
753k
    const struct ASF_Object_Function_entry *p_reader =
1552
753k
            ASF_GetObject_Function( &p_obj->common.i_object_id );
1553
753k
    if( p_reader )
1554
738k
    {
1555
738k
        p_obj->common.i_type = p_reader->i_type;
1556
1557
        /* Now load this object */
1558
738k
        if( p_reader->ASF_ReadObject_function != NULL )
1559
737k
            i_result = p_reader->ASF_ReadObject_function( s, p_obj );
1560
738k
    }
1561
14.3k
    else
1562
14.3k
    {
1563
14.3k
        msg_Warn( s, "unknown asf object (not loaded): " GUID_FMT,
1564
14.3k
                GUID_PRINT( p_obj->common.i_object_id ) );
1565
14.3k
    }
1566
1567
    /* link this object with father */
1568
753k
    if ( i_result == VLC_SUCCESS )
1569
753k
        ASF_ParentObject( p_father, p_obj );
1570
1571
753k
    return i_result;
1572
754k
}
1573
1574
static void ASF_FreeObject( stream_t *s, asf_object_t *p_obj )
1575
753k
{
1576
753k
    asf_object_t *p_child;
1577
1578
753k
    if( !p_obj )
1579
0
        return;
1580
1581
    /* Free all child object */
1582
753k
    p_child = p_obj->common.p_first;
1583
1.48M
    while( p_child )
1584
736k
    {
1585
736k
        asf_object_t *p_next;
1586
736k
        p_next = p_child->common.p_next;
1587
736k
        ASF_FreeObject( s, p_child );
1588
736k
        p_child = p_next;
1589
736k
    }
1590
1591
    /* find this object */
1592
753k
    const struct ASF_Object_Function_entry *p_entry =
1593
753k
            ASF_GetObject_Function( &p_obj->common.i_object_id );
1594
753k
    if( p_entry && p_entry->ASF_FreeObject_function )
1595
737k
    {
1596
        /* Now free this object */
1597
737k
#ifdef ASF_DEBUG
1598
737k
        msg_Dbg( s,
1599
737k
                  "freing asf object " GUID_FMT,
1600
737k
                  GUID_PRINT( p_obj->common.i_object_id ) );
1601
737k
#endif
1602
737k
        p_entry->ASF_FreeObject_function( p_obj );
1603
737k
    }
1604
1605
753k
    free( p_obj );
1606
753k
}
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
63.5k
{
1654
63.5k
    unsigned i;
1655
63.5k
    union asf_object_u *p_child;
1656
63.5k
    const char *psz_name;
1657
1658
    /* Find the name */
1659
580k
    for( i = 0; ASF_ObjectDumpDebugInfo[i].p_id != NULL; i++ )
1660
570k
    {
1661
570k
        if( guidcmp( ASF_ObjectDumpDebugInfo[i].p_id,
1662
570k
                          &p_node->i_object_id ) )
1663
53.9k
            break;
1664
570k
    }
1665
63.5k
    psz_name = ASF_ObjectDumpDebugInfo[i].psz_name;
1666
1667
63.5k
    char str[512];
1668
63.5k
    if( i_level >= (sizeof(str) - 1)/5 )
1669
69
        return;
1670
1671
63.4k
    memset( str, ' ', sizeof( str ) );
1672
446k
    for( i = 0; i < i_level; i++ )
1673
383k
    {
1674
383k
        str[i * 4] = '|';
1675
383k
    }
1676
63.4k
    snprintf( &str[4*i_level], sizeof(str) - 5*i_level,
1677
63.4k
             "+ '%s'"
1678
63.4k
#ifdef ASF_DEBUG
1679
63.4k
             "GUID "GUID_FMT" size:%"PRIu64" pos:%"PRIu64
1680
63.4k
#endif
1681
63.4k
             , psz_name
1682
1683
63.4k
#ifdef ASF_DEBUG
1684
63.4k
             , GUID_PRINT( p_node->i_object_id ),
1685
63.4k
             p_node->i_object_size, p_node->i_object_pos
1686
63.4k
#endif
1687
63.4k
             );
1688
1689
1690
63.4k
    msg_Dbg( p_obj, "%s", str );
1691
1692
120k
    for( p_child = p_node->p_first; p_child != NULL;
1693
63.4k
                                             p_child = p_child->common.p_next )
1694
56.5k
    {
1695
56.5k
        ASF_ObjectDumpDebug( p_obj, &p_child->common, i_level + 1 );
1696
56.5k
    }
1697
63.4k
}
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
7.30k
{
1704
7.30k
    asf_object_root_t *p_root = malloc( sizeof( asf_object_root_t ) );
1705
7.30k
    asf_object_t *p_obj;
1706
7.30k
    uint64_t i_boundary = 0;
1707
1708
7.30k
    if( !p_root )
1709
0
        return NULL;
1710
1711
7.30k
    p_root->i_type = ASF_OBJECT_ROOT;
1712
7.30k
    memcpy( &p_root->i_object_id, &vlc_object_root_guid, sizeof( vlc_guid_t ) );
1713
7.30k
    p_root->i_object_pos = vlc_stream_Tell( s );
1714
7.30k
    p_root->i_object_size = 0;
1715
7.30k
    p_root->p_first = NULL;
1716
7.30k
    p_root->p_last  = NULL;
1717
7.30k
    p_root->p_next  = NULL;
1718
7.30k
    p_root->p_hdr   = NULL;
1719
7.30k
    p_root->p_data  = NULL;
1720
7.30k
    p_root->p_fp    = NULL;
1721
7.30k
    p_root->p_index = NULL;
1722
7.30k
    p_root->p_metadata = NULL;
1723
1724
7.30k
    for( ; ; )
1725
23.4k
    {
1726
23.4k
        p_obj = malloc( sizeof( asf_object_t ) );
1727
1728
23.4k
        if( !p_obj || ASF_ReadObject( s, p_obj, (asf_object_t*)p_root ) )
1729
7.10k
        {
1730
7.10k
            free( p_obj );
1731
7.10k
            break;
1732
7.10k
        }
1733
16.3k
        switch( p_obj->common.i_type )
1734
16.3k
        {
1735
8.26k
            case( ASF_OBJECT_HEADER ):
1736
8.26k
                if ( p_root->p_index || p_root->p_data || p_root->p_hdr ) break;
1737
7.30k
                p_root->p_hdr = (asf_object_header_t*)p_obj;
1738
7.30k
                break;
1739
7.12k
            case( ASF_OBJECT_DATA ):
1740
7.12k
                if ( p_root->p_index || p_root->p_data ) break;
1741
7.04k
                p_root->p_data = (asf_object_data_t*)p_obj;
1742
7.04k
            break;
1743
11
            case( ASF_OBJECT_INDEX ):
1744
11
                if ( p_root->p_index ) break;
1745
11
                p_root->p_index = (asf_object_index_t*)p_obj;
1746
11
                break;
1747
979
            default:
1748
979
                msg_Warn( s, "unknown top-level object found: " GUID_FMT,
1749
979
                      GUID_PRINT( p_obj->common.i_object_id ) );
1750
979
                break;
1751
16.3k
        }
1752
1753
        /* Set a limit to avoid junk when possible */
1754
16.3k
        if ( guidcmp( &p_obj->common.i_object_id, &asf_object_file_properties_guid ) )
1755
35
        {
1756
35
            i_boundary = p_obj->file_properties.i_file_size;
1757
35
        }
1758
1759
16.3k
        if( p_obj->common.i_type == ASF_OBJECT_DATA &&
1760
7.12k
            p_obj->common.i_object_size <= 50 )
1761
142
        {
1762
            /* probably a dump of broadcasted asf */
1763
142
            break;
1764
142
        }
1765
16.2k
        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
16.2k
        if( ASF_NextObject( s, p_obj, i_boundary ) ) /* Go to the next object */
1772
55
            break;
1773
16.2k
    }
1774
1775
7.30k
    if( p_root->p_hdr != NULL && p_root->p_data != NULL )
1776
7.04k
    {
1777
7.04k
        p_root->p_fp = ASF_FindObject( p_root->p_hdr,
1778
7.04k
                                       &asf_object_file_properties_guid, 0 );
1779
1780
7.04k
        if( p_root->p_fp )
1781
7.03k
        {
1782
7.03k
            asf_object_t *p_hdr_ext =
1783
7.03k
                ASF_FindObject( p_root->p_hdr,
1784
7.03k
                                &asf_object_header_extension_guid, 0 );
1785
7.03k
            if( p_hdr_ext )
1786
6.20k
            {
1787
6.20k
                p_root->p_metadata =
1788
6.20k
                    ASF_FindObject( p_hdr_ext,
1789
6.20k
                                    &asf_object_metadata_guid, 0 );
1790
6.20k
            }
1791
1792
7.03k
            ASF_ObjectDumpDebug( VLC_OBJECT(s),
1793
7.03k
                                 (asf_object_common_t*)p_root, 0 );
1794
7.03k
            return p_root;
1795
7.03k
        }
1796
12
        msg_Warn( s, "cannot find file properties object" );
1797
12
    }
1798
1799
    /* Invalid file */
1800
271
    ASF_FreeObjectRoot( s, p_root );
1801
271
    return NULL;
1802
7.30k
}
1803
1804
void ASF_FreeObjectRoot( stream_t *s, asf_object_root_t *p_root )
1805
7.30k
{
1806
7.30k
    asf_object_t *p_obj;
1807
1808
7.30k
    p_obj = p_root->p_first;
1809
23.6k
    while( p_obj )
1810
16.3k
    {
1811
16.3k
        asf_object_t *p_next;
1812
16.3k
        p_next = p_obj->common.p_next;
1813
16.3k
        ASF_FreeObject( s, p_obj );
1814
16.3k
        p_obj = p_next;
1815
16.3k
    }
1816
7.30k
    free( p_root );
1817
7.30k
}
1818
1819
int ASF_CountObject( void *_p_obj, const vlc_guid_t *p_guid )
1820
13.7k
{
1821
13.7k
    int i_count;
1822
13.7k
    asf_object_t *p_child, *p_obj;
1823
1824
13.7k
    p_obj = (asf_object_t *)_p_obj;
1825
13.7k
    if( !p_obj )
1826
0
        return 0;
1827
1828
13.7k
    i_count = 0;
1829
13.7k
    p_child = p_obj->common.p_first;
1830
50.9k
    while( p_child )
1831
37.2k
    {
1832
37.2k
        if( guidcmp( &p_child->common.i_object_id, p_guid ) )
1833
8.23k
            i_count++;
1834
1835
37.2k
        p_child = p_child->common.p_next;
1836
37.2k
    }
1837
13.7k
    return i_count;
1838
13.7k
}
1839
1840
void *ASF_FindObject( void *_p_obj, const vlc_guid_t *p_guid,
1841
                        int i_number )
1842
95.9k
{
1843
95.9k
    asf_object_t *p_child, *p_obj;
1844
1845
95.9k
    p_obj = (asf_object_t *)_p_obj;
1846
95.9k
    p_child = p_obj->common.p_first;
1847
1848
315k
    while( p_child )
1849
249k
    {
1850
249k
        if( guidcmp( &p_child->common.i_object_id, p_guid ) )
1851
30.8k
        {
1852
30.8k
            if( i_number == 0 )
1853
30.0k
                return p_child;
1854
1855
779
            i_number--;
1856
779
        }
1857
219k
        p_child = p_child->common.p_next;
1858
219k
    }
1859
65.9k
    return NULL;
1860
95.9k
}