Coverage Report

Created: 2025-08-29 07:30

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