Coverage Report

Created: 2025-10-10 06:26

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
26.5M
{
51
26.5M
    if( i_wanted > i_peek )
52
13.3k
        return false;
53
26.5M
    return &p_current[i_wanted] <= &p_peek[i_peek];
54
26.5M
}
55
13.4M
#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
13.0M
{
61
13.0M
    if( AsfObjectHelperHave( p_peek, i_peek, *pp_data, i_wanted ) )
62
1.35M
        *pp_data += i_wanted;
63
11.7M
    else
64
11.7M
        *pp_data = (uint8_t*)&p_peek[i_peek];
65
13.0M
}
66
13.0M
#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
12.6M
static inline type AsfObjectHelperRead##x( const uint8_t *p_peek, size_t i_peek, uint8_t **pp_data ) { \
72
12.6M
    uint8_t *p_data = *pp_data; \
73
12.6M
    type i_ret = 0;  \
74
12.6M
    if( ASF_HAVE(x) )   \
75
12.6M
        i_ret = cmd;    \
76
12.6M
    ASF_SKIP(x);        \
77
12.6M
    *pp_data = p_data;  \
78
12.6M
    return i_ret;   }
libasf.c:AsfObjectHelperRead2
Line
Count
Source
71
720k
static inline type AsfObjectHelperRead##x( const uint8_t *p_peek, size_t i_peek, uint8_t **pp_data ) { \
72
720k
    uint8_t *p_data = *pp_data; \
73
720k
    type i_ret = 0;  \
74
720k
    if( ASF_HAVE(x) )   \
75
720k
        i_ret = cmd;    \
76
720k
    ASF_SKIP(x);        \
77
720k
    *pp_data = p_data;  \
78
720k
    return i_ret;   }
libasf.c:AsfObjectHelperRead4
Line
Count
Source
71
45.8k
static inline type AsfObjectHelperRead##x( const uint8_t *p_peek, size_t i_peek, uint8_t **pp_data ) { \
72
45.8k
    uint8_t *p_data = *pp_data; \
73
45.8k
    type i_ret = 0;  \
74
45.8k
    if( ASF_HAVE(x) )   \
75
45.8k
        i_ret = cmd;    \
76
45.8k
    ASF_SKIP(x);        \
77
45.8k
    *pp_data = p_data;  \
78
45.8k
    return i_ret;   }
libasf.c:AsfObjectHelperRead8
Line
Count
Source
71
5.33k
static inline type AsfObjectHelperRead##x( const uint8_t *p_peek, size_t i_peek, uint8_t **pp_data ) { \
72
5.33k
    uint8_t *p_data = *pp_data; \
73
5.33k
    type i_ret = 0;  \
74
5.33k
    if( ASF_HAVE(x) )   \
75
5.33k
        i_ret = cmd;    \
76
5.33k
    ASF_SKIP(x);        \
77
5.33k
    *pp_data = p_data;  \
78
5.33k
    return i_ret;   }
libasf.c:AsfObjectHelperRead1
Line
Count
Source
71
11.8M
static inline type AsfObjectHelperRead##x( const uint8_t *p_peek, size_t i_peek, uint8_t **pp_data ) { \
72
11.8M
    uint8_t *p_data = *pp_data; \
73
11.8M
    type i_ret = 0;  \
74
11.8M
    if( ASF_HAVE(x) )   \
75
11.8M
        i_ret = cmd;    \
76
11.8M
    ASF_SKIP(x);        \
77
11.8M
    *pp_data = p_data;  \
78
11.8M
    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
11.8M
#define ASF_READ1() AsfObjectHelperRead1( p_peek, i_peek, (uint8_t**)&p_data )
84
440k
#define ASF_READ2() AsfObjectHelperRead2( p_peek, i_peek, (uint8_t**)&p_data )
85
44.5k
#define ASF_READ4() AsfObjectHelperRead4( p_peek, i_peek, (uint8_t**)&p_data )
86
4.75k
#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
399k
{
93
399k
    uint8_t *p_data = *pp_data;
94
399k
    char *psz_string = NULL;
95
399k
    if( ASF_HAVE(i_size) )
96
393k
    {
97
393k
        psz_string = FromCharset( "UTF-16LE", p_data, i_size );
98
393k
    }
99
399k
    ASF_SKIP(i_size);
100
399k
    *pp_data = p_data;
101
399k
    return psz_string;
102
399k
}
103
399k
#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
284k
{
116
284k
    asf_object_common_t *p_common = &p_obj->common;
117
284k
    const uint8_t *p_peek;
118
119
284k
    if( vlc_stream_Peek( s, &p_peek, ASF_OBJECT_COMMON_SIZE ) < ASF_OBJECT_COMMON_SIZE )
120
33.9k
        return VLC_EGENERIC;
121
122
250k
    ASF_GetGUID( &p_common->i_object_id, p_peek );
123
250k
    p_common->i_object_size = GetQWLE( p_peek + 16 );
124
250k
    p_common->i_object_pos  = vlc_stream_Tell( s );
125
250k
    p_common->p_next = NULL;
126
127
250k
#ifdef ASF_DEBUG
128
250k
    msg_Dbg( s,
129
250k
             "found object guid: " GUID_FMT " size:%"PRIu64" at %"PRIu64,
130
250k
             GUID_PRINT( p_common->i_object_id ),
131
250k
             p_common->i_object_size, p_common->i_object_pos );
132
250k
#endif
133
134
250k
    return VLC_SUCCESS;
135
284k
}
136
137
static int ASF_NextObject( stream_t *s, asf_object_t *p_obj, uint64_t i_boundary )
138
226k
{
139
226k
    asf_object_t obj;
140
141
226k
    int64_t i_pos = vlc_stream_Tell( s );
142
226k
    if ( i_boundary && i_pos >= 0 && (uint64_t) i_pos >= i_boundary )
143
15
    {
144
15
        return VLC_EGENERIC;
145
15
    }
146
147
226k
    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
226k
    if( p_obj->common.i_object_size <= 0 )
156
0
        return VLC_EGENERIC;
157
158
226k
    if( ( UINT64_MAX - p_obj->common.i_object_pos ) < p_obj->common.i_object_size )
159
532
        return VLC_EGENERIC;
160
161
226k
    if( p_obj->common.p_father &&
162
226k
        p_obj->common.p_father->common.i_object_size != 0 )
163
211k
    {
164
211k
        if( p_obj->common.p_father->common.i_object_pos +
165
211k
            p_obj->common.p_father->common.i_object_size <
166
211k
                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
116k
        {
169
116k
            return VLC_EGENERIC;
170
116k
        }
171
172
211k
    }
173
174
110k
    return vlc_stream_Seek( s, p_obj->common.i_object_pos +
175
110k
                        p_obj->common.i_object_size );
176
226k
}
177
178
static void ASF_FreeObject_Null( asf_object_t *pp_obj )
179
171k
{
180
171k
    VLC_UNUSED(pp_obj);
181
171k
}
182
183
static int  ASF_ReadObject_Header( stream_t *s, asf_object_t *p_obj )
184
162k
{
185
162k
    asf_object_header_t *p_hdr = &p_obj->header;
186
162k
    asf_object_t        *p_subobj;
187
162k
    const uint8_t       *p_peek;
188
189
162k
    if( vlc_stream_Peek( s, &p_peek, 30 ) < 30 )
190
387
       return VLC_EGENERIC;
191
192
161k
    p_hdr->i_sub_object_count = GetDWLE( p_peek + ASF_OBJECT_COMMON_SIZE );
193
161k
    p_hdr->i_reserved1 = p_peek[28];
194
161k
    p_hdr->i_reserved2 = p_peek[29];
195
161k
    p_hdr->p_first = NULL;
196
161k
    p_hdr->p_last  = NULL;
197
198
161k
#ifdef ASF_DEBUG
199
161k
    msg_Dbg( s,
200
161k
             "read \"header object\" subobj:%u, reserved1:%u, reserved2:%u",
201
161k
             p_hdr->i_sub_object_count,
202
161k
             p_hdr->i_reserved1,
203
161k
             p_hdr->i_reserved2 );
204
161k
#endif
205
206
161k
    if( vlc_stream_Read( s, NULL, 30 ) != 30 )
207
0
        return VLC_EGENERIC;
208
209
    /* Now load sub object */
210
161k
    for( ; ; )
211
250k
    {
212
250k
        p_subobj = malloc( sizeof( asf_object_t ) );
213
214
250k
        if( !p_subobj || ASF_ReadObject( s, p_subobj, (asf_object_t*)p_hdr ) )
215
47.3k
        {
216
47.3k
            free( p_subobj );
217
47.3k
            break;
218
47.3k
        }
219
203k
        if( ASF_NextObject( s, p_subobj, 0 ) ) /* Go to the next object */
220
114k
            break;
221
203k
    }
222
161k
    return VLC_SUCCESS;
223
161k
}
224
225
static int ASF_ReadObject_Data( stream_t *s, asf_object_t *p_obj )
226
6.50k
{
227
6.50k
    asf_object_data_t *p_data = &p_obj->data;
228
6.50k
    const uint8_t     *p_peek;
229
230
6.50k
    if( vlc_stream_Peek( s, &p_peek, 50 ) < 50 )
231
2.28k
       return VLC_EGENERIC;
232
233
4.21k
    ASF_GetGUID( &p_data->i_file_id, p_peek + ASF_OBJECT_COMMON_SIZE );
234
4.21k
    p_data->i_total_data_packets = GetQWLE( p_peek + 40 );
235
4.21k
    p_data->i_reserved = GetWLE( p_peek + 48 );
236
237
4.21k
#ifdef ASF_DEBUG
238
4.21k
    msg_Dbg( s,
239
4.21k
             "read \"data object\" file_id:" GUID_FMT " total data packet:"
240
4.21k
             "%"PRIu64" reserved:%u",
241
4.21k
             GUID_PRINT( p_data->i_file_id ),
242
4.21k
             p_data->i_total_data_packets,
243
4.21k
             p_data->i_reserved );
244
4.21k
#endif
245
246
4.21k
    return VLC_SUCCESS;
247
6.50k
}
248
249
static int ASF_ReadObject_Index( stream_t *s, asf_object_t *p_obj )
250
6
{
251
6
    asf_object_index_t *p_index = &p_obj->index;
252
6
    const uint8_t      *p_peek;
253
6
    unsigned int       i;
254
255
    /* We just ignore error on the index */
256
6
    if( p_index->i_object_size < 56
257
6
     || p_index->i_object_size > INT32_MAX
258
6
     || vlc_stream_Peek( s, &p_peek, p_index->i_object_size )
259
6
        < (int64_t)p_index->i_object_size )
260
3
        return VLC_SUCCESS;
261
262
3
    ASF_GetGUID( &p_index->i_file_id, p_peek + ASF_OBJECT_COMMON_SIZE );
263
3
    p_index->i_index_entry_time_interval = GetQWLE( p_peek + 40 );
264
3
    p_index->i_max_packet_count = GetDWLE( p_peek + 48 );
265
3
    p_index->i_index_entry_count = GetDWLE( p_peek + 52 );
266
3
    p_index->index_entry = NULL;
267
268
3
#ifdef ASF_DEBUG
269
3
    msg_Dbg( s,
270
3
            "read \"index object\" file_id:" GUID_FMT
271
3
            " index_entry_time_interval:%"PRId64" max_packet_count:%u "
272
3
            "index_entry_count:%u",
273
3
            GUID_PRINT( p_index->i_file_id ),
274
3
            p_index->i_index_entry_time_interval,
275
3
            p_index->i_max_packet_count,
276
3
            p_index->i_index_entry_count );
277
3
#endif
278
279
    /* Sanity checking */
280
3
    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
3
    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
3
    p_index->index_entry = calloc( p_index->i_index_entry_count,
290
3
                                   sizeof(asf_index_entry_t) );
291
3
    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
101
    for( i = 0, p_peek += 56; i < p_index->i_index_entry_count; i++, p_peek += 6 )
298
98
    {
299
98
        p_index->index_entry[i].i_packet_number = GetDWLE( p_peek );
300
98
        p_index->index_entry[i].i_packet_count = GetWLE( p_peek + 4 );
301
98
    }
302
303
3
    return VLC_SUCCESS;
304
3
}
305
306
static void ASF_FreeObject_Index( asf_object_t *p_obj )
307
6
{
308
6
    asf_object_index_t *p_index = &p_obj->index;
309
310
6
    FREENULL( p_index->index_entry );
311
6
}
312
313
static int ASF_ReadObject_file_properties( stream_t *s, asf_object_t *p_obj )
314
5.94k
{
315
5.94k
    asf_object_file_properties_t *p_fp = &p_obj->file_properties;
316
5.94k
    const uint8_t *p_peek;
317
318
5.94k
    if( vlc_stream_Peek( s, &p_peek,  104 ) < 104 )
319
479
       return VLC_EGENERIC;
320
321
5.46k
    ASF_GetGUID( &p_fp->i_file_id, p_peek + ASF_OBJECT_COMMON_SIZE );
322
5.46k
    p_fp->i_file_size = GetQWLE( p_peek + 40 );
323
5.46k
    p_fp->i_creation_date = GetQWLE( p_peek + 48 );
324
5.46k
    p_fp->i_data_packets_count = GetQWLE( p_peek + 56 );
325
5.46k
    p_fp->i_play_duration = GetQWLE( p_peek + 64 );
326
5.46k
    p_fp->i_send_duration = GetQWLE( p_peek + 72 );
327
5.46k
    uint64_t preroll = GetQWLE( p_peek + 80 );
328
5.46k
    if (unlikely(preroll > INT32_MAX)) // sanity check on "appropriate" value
329
322
        return VLC_EINVAL;
330
5.14k
    p_fp->i_preroll = VLC_TICK_FROM_MS(preroll);
331
5.14k
    p_fp->i_flags = GetDWLE( p_peek + 88 );
332
5.14k
    p_fp->i_min_data_packet_size = __MAX( GetDWLE( p_peek + 92 ), (uint32_t) 1 );
333
5.14k
    p_fp->i_max_data_packet_size = __MAX( GetDWLE( p_peek + 96 ), (uint32_t) 1 );
334
5.14k
    p_fp->i_max_bitrate = GetDWLE( p_peek + 100 );
335
336
5.14k
#ifdef ASF_DEBUG
337
5.14k
    msg_Dbg( s,
338
5.14k
            "read \"file properties object\" file_id:" GUID_FMT
339
5.14k
            " file_size:%"PRIu64" creation_date:%"PRIu64" data_packets_count:"
340
5.14k
            "%"PRIu64" play_duration:%"PRId64" send_duration:%"PRId64" preroll:%"PRIu64
341
5.14k
            " flags:%u min_data_packet_size:%d "
342
5.14k
            " max_data_packet_size:%u max_bitrate:%u",
343
5.14k
            GUID_PRINT( p_fp->i_file_id ), p_fp->i_file_size,
344
5.14k
            p_fp->i_creation_date, p_fp->i_data_packets_count,
345
5.14k
            p_fp->i_play_duration, p_fp->i_send_duration,
346
5.14k
            preroll, p_fp->i_flags,
347
5.14k
            p_fp->i_min_data_packet_size, p_fp->i_max_data_packet_size,
348
5.14k
            p_fp->i_max_bitrate );
349
5.14k
#endif
350
351
5.14k
    return VLC_SUCCESS;
352
5.46k
}
353
354
static void ASF_FreeObject_metadata( asf_object_t *p_obj )
355
7.01k
{
356
7.01k
    asf_object_metadata_t *p_meta = &p_obj->metadata;
357
358
24.0k
    for( uint32_t i = 0; i < p_meta->i_record_entries_count; i++ )
359
17.0k
    {
360
17.0k
        free( p_meta->record[i].psz_name );
361
17.0k
        free( p_meta->record[i].p_data );
362
17.0k
    }
363
7.01k
    free( p_meta->record );
364
7.01k
}
365
366
static int ASF_ReadObject_metadata( stream_t *s, asf_object_t *p_obj )
367
7.87k
{
368
7.87k
    asf_object_metadata_t *p_meta = &p_obj->metadata;
369
370
7.87k
    uint32_t i;
371
7.87k
    const uint8_t *p_peek, *p_data;
372
373
7.87k
    if( p_meta->i_object_size < 26 || p_meta->i_object_size > INT32_MAX )
374
577
        return VLC_EGENERIC;
375
376
7.29k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_meta->i_object_size );
377
7.29k
    if( i_peek < (int64_t)p_meta->i_object_size )
378
282
       return VLC_EGENERIC;
379
380
7.01k
    p_meta->i_record_entries_count = GetWLE( p_peek + ASF_OBJECT_COMMON_SIZE );
381
382
7.01k
    p_data = p_peek + 26;
383
384
7.01k
    p_meta->record = calloc( p_meta->i_record_entries_count,
385
7.01k
                             sizeof(asf_metadata_record_t) );
386
7.01k
    if( !p_meta->record )
387
0
    {
388
0
        p_meta->i_record_entries_count = 0;
389
0
        return VLC_ENOMEM;
390
0
    }
391
392
24.0k
    for( i = 0; i < p_meta->i_record_entries_count; i++ )
393
22.1k
    {
394
22.1k
        asf_metadata_record_t *p_record = &p_meta->record[i];
395
22.1k
        uint16_t i_name;
396
22.1k
        uint32_t i_data;
397
398
22.1k
        if( !ASF_HAVE( 2+2+2+2+4 ) )
399
3.68k
            break;
400
401
18.4k
        if( ASF_READ2() != 0 )
402
418
            break;
403
404
18.0k
        p_record->i_stream = ASF_READ2();
405
18.0k
        i_name = ASF_READ2();
406
18.0k
        p_record->i_type = ASF_READ2();
407
18.0k
        i_data = ASF_READ4();
408
409
18.0k
        if( UINT32_MAX - i_name < i_data ||
410
17.7k
            !ASF_HAVE( i_name + i_data ) )
411
942
            break;
412
413
        /* Read name */
414
17.0k
        p_record->psz_name = ASF_READS( i_name );
415
416
        /* Read data */
417
17.0k
        if( p_record->i_type == ASF_METADATA_TYPE_STRING )
418
6.85k
        {
419
6.85k
            p_record->p_data = (uint8_t *)ASF_READS( i_data );
420
6.85k
            if( p_record->p_data )
421
6.42k
                p_record->i_data = i_data/2; /* FIXME Is that needed ? */
422
6.85k
        }
423
10.2k
        else if( p_record->i_type == ASF_METADATA_TYPE_BYTE )
424
1.06k
        {
425
1.06k
            p_record->p_data = malloc( i_data );
426
1.06k
            if( p_record->p_data )
427
1.06k
            {
428
1.06k
                p_record->i_data = i_data;
429
1.06k
                if( p_record->p_data && i_data > 0 )
430
854
                    memcpy( p_record->p_data, p_data, i_data );
431
1.06k
            }
432
1.06k
            p_data += i_data;
433
1.06k
        }
434
9.14k
        else if( p_record->i_type == ASF_METADATA_TYPE_QWORD )
435
524
        {
436
524
            p_record->i_val = ASF_READ8();
437
524
        }
438
8.62k
        else if( p_record->i_type == ASF_METADATA_TYPE_DWORD )
439
2.31k
        {
440
2.31k
            p_record->i_val = ASF_READ4();
441
2.31k
        }
442
6.30k
        else if( p_record->i_type == ASF_METADATA_TYPE_WORD )
443
2.39k
        {
444
2.39k
            p_record->i_val = ASF_READ2();
445
2.39k
        }
446
3.90k
        else if( p_record->i_type == ASF_METADATA_TYPE_BOOL )
447
1.77k
        {
448
1.77k
            p_record->i_val = ASF_READ2();
449
1.77k
        }
450
2.13k
        else
451
2.13k
        {
452
            /* Unknown */
453
2.13k
            p_data += i_data;
454
2.13k
        }
455
17.0k
    }
456
7.01k
    p_meta->i_record_entries_count = i;
457
458
7.01k
#ifdef ASF_DEBUG
459
7.01k
    msg_Dbg( s,
460
7.01k
             "read \"metadata object\" %"PRIu32" entries",
461
7.01k
            p_meta->i_record_entries_count );
462
24.0k
    for( uint32_t j = 0; j < p_meta->i_record_entries_count; j++ )
463
17.0k
    {
464
17.0k
        asf_metadata_record_t *p_rec = &p_meta->record[j];
465
466
17.0k
        if( p_rec->i_type == ASF_METADATA_TYPE_STRING )
467
17.0k
            msg_Dbg( s, "  - %s=%s",
468
10.2k
                     p_rec->psz_name, p_rec->p_data );
469
10.2k
        else if( p_rec->i_type == ASF_METADATA_TYPE_BYTE )
470
10.2k
            msg_Dbg( s, "  - %s (%u bytes)",
471
9.14k
                     p_rec->psz_name, p_rec->i_data );
472
9.14k
        else
473
9.14k
            msg_Dbg( s, "  - %s=%"PRIu64,
474
17.0k
                     p_rec->psz_name, p_rec->i_val );
475
17.0k
    }
476
7.01k
#endif
477
478
7.01k
    return VLC_SUCCESS;
479
7.01k
}
480
481
static int ASF_ReadObject_header_extension( stream_t *s, asf_object_t *p_obj )
482
11.8k
{
483
11.8k
    asf_object_header_extension_t *p_he = &p_obj->header_extension;
484
11.8k
    const uint8_t *p_peek;
485
486
11.8k
    if( p_he->i_object_size > INT32_MAX )
487
261
        return VLC_EGENERIC;
488
489
11.5k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_he->i_object_size );
490
11.5k
    if( i_peek < 46 )
491
7.41k
       return VLC_EGENERIC;
492
493
4.13k
    ASF_GetGUID( &p_he->i_reserved1, p_peek + ASF_OBJECT_COMMON_SIZE );
494
4.13k
    p_he->i_reserved2 = GetWLE( p_peek + 40 );
495
4.13k
    p_he->i_header_extension_size = GetDWLE( p_peek + 42 );
496
4.13k
    if( p_he->i_header_extension_size )
497
2.91k
    {
498
2.91k
        if( (unsigned int)(i_peek-46) < p_he->i_header_extension_size )
499
307
            return VLC_EGENERIC;
500
501
2.60k
        p_he->p_header_extension_data =
502
2.60k
            malloc( p_he->i_header_extension_size );
503
2.60k
        if( !p_he->p_header_extension_data )
504
0
            return VLC_ENOMEM;
505
506
2.60k
        memcpy( p_he->p_header_extension_data, p_peek + 46,
507
2.60k
                p_he->i_header_extension_size );
508
2.60k
    }
509
1.21k
    else
510
1.21k
    {
511
1.21k
        p_he->p_header_extension_data = NULL;
512
1.21k
        p_he->i_header_extension_size = 0;
513
1.21k
    }
514
515
3.82k
#ifdef ASF_DEBUG
516
3.82k
    msg_Dbg( s,
517
3.82k
            "read \"header extension object\" reserved1:" GUID_FMT
518
3.82k
            " reserved2:%u header_extension_size:%"PRIu32,
519
3.82k
            GUID_PRINT( p_he->i_reserved1 ), p_he->i_reserved2,
520
3.82k
            p_he->i_header_extension_size );
521
3.82k
#endif
522
523
3.82k
    if( !p_he->i_header_extension_size ) return VLC_SUCCESS;
524
525
    /* Read the extension objects */
526
2.60k
    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
2.60k
    for( ; ; )
533
9.65k
    {
534
9.65k
        asf_object_t *p_child = malloc( sizeof( asf_object_t ) );
535
536
9.65k
        if( p_child == NULL
537
9.65k
         || ASF_ReadObject( s, p_child, (asf_object_t*)p_he ) )
538
422
        {
539
422
            free( p_child );
540
422
            break;
541
422
        }
542
543
9.23k
        if( ASF_NextObject( s, p_child, 0 ) ) /* Go to the next object */
544
2.18k
        {
545
2.18k
            break;
546
2.18k
        }
547
9.23k
    }
548
549
2.60k
    return VLC_SUCCESS;
550
2.60k
}
551
552
static void ASF_FreeObject_header_extension( asf_object_t *p_obj )
553
3.82k
{
554
3.82k
    asf_object_header_extension_t *p_he = &p_obj->header_extension;
555
556
3.82k
    FREENULL( p_he->p_header_extension_data );
557
3.82k
}
558
559
static int ASF_ReadObject_stream_properties( stream_t *s, asf_object_t *p_obj )
560
5.61k
{
561
5.61k
    asf_object_stream_properties_t *p_sp = &p_obj->stream_properties;
562
5.61k
    const uint8_t *p_peek;
563
564
5.61k
#if UINT64_MAX > SSIZE_MAX
565
5.61k
    if( p_sp->i_object_size > SSIZE_MAX )
566
278
    {
567
278
        msg_Err( s, "unable to peek: object size is too large" );
568
278
        return VLC_EGENERIC;
569
278
    }
570
5.34k
#endif
571
572
5.34k
    if( p_sp->i_object_size > INT32_MAX )
573
255
        return VLC_EGENERIC;
574
575
5.08k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_sp->i_object_size );
576
5.08k
    if( i_peek < 78 )
577
256
       return VLC_EGENERIC;
578
579
4.83k
    ASF_GetGUID( &p_sp->i_stream_type, p_peek + ASF_OBJECT_COMMON_SIZE );
580
4.83k
    ASF_GetGUID( &p_sp->i_error_correction_type, p_peek + 40 );
581
4.83k
    p_sp->i_time_offset = GetQWLE( p_peek + 56 );
582
4.83k
    p_sp->i_type_specific_data_length = GetDWLE( p_peek + 64 );
583
4.83k
    p_sp->i_error_correction_data_length = GetDWLE( p_peek + 68 );
584
4.83k
    p_sp->i_flags = GetWLE( p_peek + 72 );
585
4.83k
    p_sp->i_stream_number = p_sp->i_flags&0x07f;
586
4.83k
    if ( p_sp->i_stream_number > ASF_MAX_STREAMNUMBER )
587
0
        return VLC_EGENERIC;
588
4.83k
    p_sp->i_reserved = GetDWLE( p_peek + 74 );
589
4.83k
    i_peek -= 78;
590
591
4.83k
    if( p_sp->i_type_specific_data_length )
592
3.96k
    {
593
3.96k
        if( i_peek < p_sp->i_type_specific_data_length )
594
295
            return VLC_EGENERIC;
595
596
3.67k
        p_sp->p_type_specific_data =
597
3.67k
            malloc( p_sp->i_type_specific_data_length );
598
3.67k
        if( !p_sp->p_type_specific_data )
599
0
            return VLC_ENOMEM;
600
601
3.67k
        memcpy( p_sp->p_type_specific_data, p_peek + 78,
602
3.67k
                p_sp->i_type_specific_data_length );
603
3.67k
        i_peek -= p_sp->i_type_specific_data_length;
604
3.67k
    }
605
606
4.53k
    if( p_sp->i_error_correction_data_length )
607
1.16k
    {
608
1.16k
        if( i_peek < p_sp->i_error_correction_data_length )
609
349
        {
610
349
            free( p_sp->p_type_specific_data );
611
349
            return VLC_EGENERIC;
612
349
        }
613
614
820
        p_sp->p_error_correction_data =
615
820
            malloc( p_sp->i_error_correction_data_length );
616
820
        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
820
        memcpy( p_sp->p_error_correction_data,
622
820
                p_peek + 78 + p_sp->i_type_specific_data_length,
623
820
                p_sp->i_error_correction_data_length );
624
820
    }
625
626
4.18k
#ifdef ASF_DEBUG
627
4.18k
    msg_Dbg( s,
628
4.18k
            "read \"stream Properties object\" stream_type:" GUID_FMT
629
4.18k
            " error_correction_type:" GUID_FMT " time_offset:%"PRIu64
630
4.18k
            " type_specific_data_length:%"PRIu32" error_correction_data_length:%"PRIu32
631
4.18k
            " flags:0x%x stream_number:%u",
632
4.18k
            GUID_PRINT( p_sp->i_stream_type ),
633
4.18k
            GUID_PRINT( p_sp->i_error_correction_type ),
634
4.18k
            p_sp->i_time_offset,
635
4.18k
            p_sp->i_type_specific_data_length,
636
4.18k
            p_sp->i_error_correction_data_length,
637
4.18k
            p_sp->i_flags,
638
4.18k
            p_sp->i_stream_number );
639
640
4.18k
#endif
641
4.18k
    return VLC_SUCCESS;
642
4.53k
}
643
644
static void ASF_FreeObject_stream_properties( asf_object_t *p_obj )
645
4.18k
{
646
4.18k
    asf_object_stream_properties_t *p_sp = &p_obj->stream_properties;
647
648
4.18k
    FREENULL( p_sp->p_type_specific_data );
649
4.18k
    FREENULL( p_sp->p_error_correction_data );
650
4.18k
}
651
652
static void ASF_FreeObject_codec_list( asf_object_t *p_obj )
653
2.76k
{
654
2.76k
    asf_object_codec_list_t *p_cl = &p_obj->codec_list;
655
656
2.76k
    for( asf_codec_entry_t *codec = p_cl->codecs, *next;
657
7.28k
         codec != NULL;
658
4.51k
         codec = next )
659
4.51k
    {
660
4.51k
        next = codec->p_next;
661
4.51k
        free( codec->psz_name );
662
4.51k
        free( codec->psz_description );
663
4.51k
        free( codec->p_information );
664
4.51k
        free( codec );
665
4.51k
    }
666
2.76k
}
667
668
static int ASF_ReadObject_codec_list( stream_t *s, asf_object_t *p_obj )
669
3.35k
{
670
3.35k
    asf_object_codec_list_t *p_cl = &p_obj->codec_list;
671
3.35k
    const uint8_t *p_peek, *p_data;
672
673
3.35k
    if( p_cl->i_object_size > INT32_MAX )
674
346
        return VLC_EGENERIC;
675
676
3.00k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_cl->i_object_size );
677
3.00k
    if( i_peek < 44 )
678
242
       return VLC_EGENERIC;
679
680
2.76k
    ASF_GetGUID( &p_cl->i_reserved, p_peek + ASF_OBJECT_COMMON_SIZE );
681
2.76k
    uint32_t count = GetDWLE( p_peek + 40 );
682
2.76k
#ifdef ASF_DEBUG
683
2.76k
    msg_Dbg( s, "read \"codec list object\" reserved_guid:" GUID_FMT
684
2.76k
             " codec_entries_count:%u", GUID_PRINT( p_cl->i_reserved ),
685
2.76k
             count );
686
2.76k
#endif
687
688
2.76k
    p_data = p_peek + 44;
689
690
2.76k
    asf_codec_entry_t **pp = &p_cl->codecs;
691
692
7.28k
    for( uint32_t i = 0; i < count; i++ )
693
5.77k
    {
694
5.77k
        asf_codec_entry_t *p_codec = malloc( sizeof( *p_codec ) );
695
696
5.77k
        if( unlikely(p_codec == NULL) || !ASF_HAVE( 2+2+2 ) )
697
1.25k
        {
698
1.25k
            free( p_codec );
699
1.25k
            *pp = NULL;
700
1.25k
            goto error;
701
1.25k
        }
702
703
        /* */
704
4.51k
        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
4.51k
        p_codec->psz_name = ASF_READS( 2*ASF_READ2() );
711
712
        /* description */
713
4.51k
        p_codec->psz_description = ASF_READS( 2*ASF_READ2() );
714
715
        /* opaque information */
716
4.51k
        p_codec->i_information_length = ASF_READ2();
717
4.51k
        if( ASF_HAVE( p_codec->i_information_length ) )
718
3.93k
        {
719
3.93k
            p_codec->p_information = malloc( p_codec->i_information_length );
720
3.93k
            if( likely(p_codec->p_information != NULL) )
721
3.93k
                memcpy( p_codec->p_information, p_data,
722
3.93k
                        p_codec->i_information_length );
723
3.93k
            p_data += p_codec->i_information_length;
724
3.93k
        }
725
583
        else
726
583
            p_codec->p_information = NULL;
727
728
4.51k
#ifdef ASF_DEBUG
729
4.51k
        msg_Dbg( s, "  - codec[%"PRIu32"] %s name:\"%s\" "
730
4.51k
                 "description:\"%s\" information_length:%u", i,
731
4.51k
                 ( p_codec->i_type == ASF_CODEC_TYPE_VIDEO ) ? "video"
732
4.51k
                 : ( ( p_codec->i_type == ASF_CODEC_TYPE_AUDIO ) ? "audio"
733
4.51k
                 : "unknown" ), p_codec->psz_name,
734
4.51k
                 p_codec->psz_description, p_codec->i_information_length );
735
4.51k
#endif
736
4.51k
        *pp = p_codec;
737
4.51k
        pp = &p_codec->p_next;
738
4.51k
    }
739
740
1.50k
    *pp = NULL;
741
1.50k
    return VLC_SUCCESS;
742
743
1.25k
error:
744
1.25k
    ASF_FreeObject_codec_list( p_obj );
745
1.25k
    return VLC_EGENERIC;
746
2.76k
}
747
748
static inline char *get_wstring( const uint8_t *p_data, size_t i_size )
749
4.72k
{
750
4.72k
    char *psz_str = FromCharset( "UTF-16LE", p_data, i_size );
751
4.72k
    if( psz_str )
752
4.66k
        p_data += i_size;
753
4.72k
    return psz_str;
754
4.72k
}
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
1.84k
{
760
1.84k
    asf_object_content_description_t *p_cd = &p_obj->content_description;
761
1.84k
    const uint8_t *p_peek, *p_data;
762
1.84k
    uint16_t i_title, i_artist, i_copyright, i_description, i_rating;
763
764
1.84k
    if( p_cd->i_object_size > INT32_MAX )
765
293
        return VLC_EGENERIC;
766
767
1.55k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_cd->i_object_size );
768
1.55k
    if( i_peek < 34 )
769
306
       return VLC_EGENERIC;
770
771
1.24k
    p_data = p_peek + ASF_OBJECT_COMMON_SIZE;
772
773
1.24k
    i_title         = ASF_READ2();
774
1.24k
    i_artist        = ASF_READ2();
775
1.24k
    i_copyright     = ASF_READ2();
776
1.24k
    i_description   = ASF_READ2();
777
1.24k
    i_rating        = ASF_READ2();
778
779
1.24k
    if( !ASF_HAVE( i_title+i_artist+i_copyright+i_description+i_rating ) )
780
301
        return VLC_EGENERIC;
781
782
945
    p_cd->psz_title = get_wstring( p_data, i_title );
783
945
    p_cd->psz_artist = get_wstring( p_data, i_artist );
784
945
    p_cd->psz_copyright = get_wstring( p_data, i_copyright );
785
945
    p_cd->psz_description = get_wstring( p_data, i_description );
786
945
    p_cd->psz_rating = get_wstring( p_data, i_rating );
787
788
945
#ifdef ASF_DEBUG
789
945
    msg_Dbg( s,
790
945
             "read \"content description object\" title:\"%s\" artist:\"%s\" copyright:\"%s\" description:\"%s\" rating:\"%s\"",
791
945
             p_cd->psz_title,
792
945
             p_cd->psz_artist,
793
945
             p_cd->psz_copyright,
794
945
             p_cd->psz_description,
795
945
             p_cd->psz_rating );
796
945
#endif
797
798
945
    return VLC_SUCCESS;
799
1.24k
}
800
801
static void ASF_FreeObject_content_description( asf_object_t *p_obj)
802
945
{
803
945
    asf_object_content_description_t *p_cd = &p_obj->content_description;
804
805
945
    FREENULL( p_cd->psz_title );
806
945
    FREENULL( p_cd->psz_artist );
807
945
    FREENULL( p_cd->psz_copyright );
808
945
    FREENULL( p_cd->psz_description );
809
945
    FREENULL( p_cd->psz_rating );
810
945
}
811
812
/* Language list: */
813
static int ASF_ReadObject_language_list(stream_t *s, asf_object_t *p_obj)
814
4.73k
{
815
4.73k
    asf_object_language_list_t *p_ll = &p_obj->language_list;
816
4.73k
    const uint8_t *p_peek, *p_data;
817
4.73k
    uint16_t i;
818
819
4.73k
    if( p_ll->i_object_size > INT32_MAX )
820
343
        return VLC_EGENERIC;
821
822
4.39k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_ll->i_object_size );
823
4.39k
    if( i_peek < 26 )
824
322
       return VLC_EGENERIC;
825
826
4.07k
    p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
827
828
4.07k
    p_ll->i_language = ASF_READ2();
829
4.07k
    if( p_ll->i_language > 0 )
830
3.80k
    {
831
3.80k
        p_ll->ppsz_language = calloc( p_ll->i_language, sizeof( char *) );
832
3.80k
        if( !p_ll->ppsz_language )
833
0
            return VLC_ENOMEM;
834
835
56.5k
        for( i = 0; i < p_ll->i_language; i++ )
836
54.0k
        {
837
54.0k
            if( !ASF_HAVE(1) )
838
1.33k
                break;
839
52.7k
            p_ll->ppsz_language[i] = ASF_READS( ASF_READ1() );
840
52.7k
        }
841
3.80k
        p_ll->i_language = i;
842
3.80k
    }
843
844
4.07k
#ifdef ASF_DEBUG
845
4.07k
    msg_Dbg( s, "read \"language list object\" %u entries",
846
4.07k
             p_ll->i_language );
847
56.7k
    for( i = 0; i < p_ll->i_language; i++ )
848
52.7k
        msg_Dbg( s, "  - '%s'",
849
4.07k
                 p_ll->ppsz_language[i] );
850
4.07k
#endif
851
4.07k
    return VLC_SUCCESS;
852
4.07k
}
853
854
static void ASF_FreeObject_language_list( asf_object_t *p_obj)
855
4.07k
{
856
4.07k
    asf_object_language_list_t *p_ll = &p_obj->language_list;
857
4.07k
    uint16_t i;
858
859
56.7k
    for( i = 0; i < p_ll->i_language; i++ )
860
52.7k
        FREENULL( p_ll->ppsz_language[i] );
861
4.07k
    FREENULL( p_ll->ppsz_language );
862
4.07k
}
863
864
/* Stream bitrate properties */
865
static int ASF_ReadObject_stream_bitrate_properties( stream_t *s,
866
                                                     asf_object_t *p_obj)
867
2.97k
{
868
2.97k
    asf_object_stream_bitrate_properties_t *p_sb = &p_obj->stream_bitrate;
869
2.97k
    const uint8_t *p_peek, *p_data;
870
2.97k
    uint16_t i;
871
872
2.97k
    if( p_sb->i_object_size > INT32_MAX )
873
364
        return VLC_EGENERIC;
874
875
2.61k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_sb->i_object_size );
876
2.61k
    if( i_peek < 26 )
877
752
       return VLC_EGENERIC;
878
879
1.86k
    p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
880
881
1.86k
    p_sb->i_bitrate = ASF_READ2();
882
1.86k
    if( p_sb->i_bitrate > ASF_MAX_STREAMNUMBER )
883
815
        p_sb->i_bitrate = ASF_MAX_STREAMNUMBER;  /* Buggy ? */
884
7.40k
    for( i = 0; i < p_sb->i_bitrate; i++ )
885
6.37k
    {
886
6.37k
        if( !ASF_HAVE(2 + 4) )
887
827
            break;
888
5.54k
        p_sb->bitrate[i].i_stream_number = (uint8_t) ASF_READ2()& 0x7f;
889
5.54k
        if ( p_sb->bitrate[i].i_stream_number > ASF_MAX_STREAMNUMBER )
890
0
            return VLC_EGENERIC;
891
5.54k
        p_sb->bitrate[i].i_avg_bitrate = ASF_READ4();
892
5.54k
    }
893
1.86k
    p_sb->i_bitrate = i;
894
895
1.86k
#ifdef ASF_DEBUG
896
1.86k
    msg_Dbg( s,"read \"stream bitrate properties object\"" );
897
7.40k
    for( i = 0; i < p_sb->i_bitrate; i++ )
898
5.54k
    {
899
5.54k
        msg_Dbg( s,"  - stream=%u bitrate=%"PRIu32,
900
5.54k
                 p_sb->bitrate[i].i_stream_number,
901
5.54k
                 p_sb->bitrate[i].i_avg_bitrate );
902
5.54k
    }
903
1.86k
#endif
904
1.86k
    return VLC_SUCCESS;
905
1.86k
}
906
static void ASF_FreeObject_stream_bitrate_properties( asf_object_t *p_obj)
907
1.86k
{
908
1.86k
    VLC_UNUSED(p_obj);
909
1.86k
}
910
911
static void ASF_FreeObject_extended_stream_properties( asf_object_t *p_obj)
912
3.56k
{
913
3.56k
    asf_object_extended_stream_properties_t *p_esp = &p_obj->ext_stream;
914
915
3.56k
    if ( p_esp->p_ext )
916
3.56k
    {
917
13.7k
        for( uint16_t i = 0; i < p_esp->i_payload_extension_system_count; i++ )
918
10.1k
            free( p_esp->p_ext[i].pi_info );
919
3.56k
        FREENULL( p_esp->p_ext );
920
3.56k
    }
921
222k
    for( uint16_t i = 0; i < p_esp->i_stream_name_count; i++ )
922
218k
        FREENULL( p_esp->ppsz_stream_name[i] );
923
3.56k
    FREENULL( p_esp->pi_stream_name_language );
924
3.56k
    FREENULL( p_esp->ppsz_stream_name );
925
3.56k
}
926
927
static int ASF_ReadObject_extended_stream_properties( stream_t *s,
928
                                                      asf_object_t *p_obj)
929
4.57k
{
930
4.57k
    asf_object_extended_stream_properties_t *p_esp = &p_obj->ext_stream;
931
4.57k
    const uint8_t *p_peek, *p_data;
932
4.57k
    uint16_t i;
933
934
4.57k
    if( p_esp->i_object_size > INT32_MAX )
935
519
        return VLC_EGENERIC;
936
937
4.05k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_esp->i_object_size );
938
4.05k
    if( i_peek < 88 )
939
275
       return VLC_EGENERIC;
940
941
3.78k
    p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
942
943
3.78k
    p_esp->i_start_time = GetQWLE( &p_data[0] );
944
3.78k
    p_esp->i_end_time = GetQWLE( &p_data[8] );
945
3.78k
    p_esp->i_data_bitrate = GetDWLE( &p_data[16] );
946
3.78k
    p_esp->i_buffer_size = GetDWLE( &p_data[20] );
947
3.78k
    p_esp->i_initial_buffer_fullness = GetDWLE( &p_data[ASF_OBJECT_COMMON_SIZE] );
948
3.78k
    p_esp->i_alternate_data_bitrate = GetDWLE( &p_data[28] );
949
3.78k
    p_esp->i_alternate_buffer_size = GetDWLE( &p_data[32] );
950
3.78k
    p_esp->i_alternate_initial_buffer_fullness = GetDWLE( &p_data[36] );
951
3.78k
    p_esp->i_maximum_object_size = GetDWLE( &p_data[40] );
952
3.78k
    p_esp->i_flags = GetDWLE( &p_data[44] );
953
3.78k
    p_esp->i_stream_number = GetWLE( &p_data[48] );
954
3.78k
    if ( p_esp->i_stream_number > ASF_MAX_STREAMNUMBER )
955
219
        return VLC_EGENERIC;
956
3.56k
    p_esp->i_language_index = GetWLE( &p_data[50] );
957
3.56k
    p_esp->i_average_time_per_frame= GetQWLE( &p_data[52] );
958
3.56k
    p_esp->i_stream_name_count = GetWLE( &p_data[60] );
959
3.56k
    p_esp->i_payload_extension_system_count = GetWLE( &p_data[62] );
960
961
3.56k
    p_data += 64;
962
963
3.56k
    p_esp->pi_stream_name_language = calloc( p_esp->i_stream_name_count,
964
3.56k
                                             sizeof(*p_esp->pi_stream_name_language) );
965
3.56k
    p_esp->ppsz_stream_name = calloc( p_esp->i_stream_name_count,
966
3.56k
                                      sizeof(*p_esp->ppsz_stream_name) );
967
3.56k
    if( !p_esp->pi_stream_name_language ||
968
3.56k
        !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
222k
    for( i = 0; i < p_esp->i_stream_name_count; i++ )
975
219k
    {
976
219k
        if( !ASF_HAVE( 2+2 ) )
977
579
            break;
978
218k
        p_esp->pi_stream_name_language[i] = ASF_READ2();
979
218k
        p_esp->ppsz_stream_name[i] = ASF_READS( ASF_READ2() );
980
218k
    }
981
3.56k
    p_esp->i_stream_name_count = i;
982
983
3.56k
    p_esp->p_ext = calloc( p_esp->i_payload_extension_system_count,
984
3.56k
                           sizeof( asf_payload_extension_system_t ) );
985
3.56k
    if ( p_esp->p_ext )
986
3.56k
    {
987
13.7k
        for( i = 0; i < p_esp->i_payload_extension_system_count; i++ )
988
11.8k
        {
989
11.8k
            asf_payload_extension_system_t *p_ext = & p_esp->p_ext[i];
990
11.8k
            if( !ASF_HAVE( 16+2+4 ) ) break;
991
10.9k
            ASF_GetGUID( &p_ext->i_extension_id, p_data );
992
10.9k
            ASF_SKIP( 16 );   // GUID
993
10.9k
            p_ext->i_data_size = ASF_READ2();
994
10.9k
            p_ext->i_info_length = ASF_READ4();
995
10.9k
            if ( p_ext->i_info_length )
996
1.55k
            {
997
1.55k
                if( !ASF_HAVE( p_ext->i_info_length ) ) break;
998
738
                p_ext->pi_info = malloc( p_ext->i_info_length );
999
738
                if ( p_ext->pi_info )
1000
738
                    memcpy( p_ext->pi_info, p_data, p_ext->i_info_length );
1001
738
                ASF_SKIP( p_ext->i_info_length );
1002
738
            }
1003
10.9k
        }
1004
3.56k
        p_esp->i_payload_extension_system_count = i;
1005
3.56k
    } else p_esp->i_payload_extension_system_count = 0;
1006
1007
3.56k
    p_esp->p_sp = NULL;
1008
1009
    /* Read tail objects */
1010
3.56k
    if( p_data < &p_peek[i_peek] )
1011
2.40k
    {
1012
2.40k
        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
2.40k
        asf_object_t *p_sp = malloc( sizeof( asf_object_t ) );
1019
2.40k
        if( !p_sp || ASF_ReadObject( s, p_sp, NULL ) )
1020
1.63k
        {
1021
1.63k
            free( p_sp );
1022
1.63k
        }
1023
768
        else
1024
768
        {
1025
            /* This p_sp will be inserted by ReadRoot later */
1026
768
            p_esp->p_sp = (asf_object_stream_properties_t*)p_sp;
1027
768
            ASF_ParentObject( p_obj, p_sp );
1028
768
        }
1029
2.40k
    }
1030
1031
3.56k
#ifdef ASF_DEBUG
1032
3.56k
    msg_Dbg( s, "read \"extended stream properties object\":" );
1033
3.56k
    msg_Dbg( s, "  - start=%"PRIu64" end=%"PRIu64,
1034
3.56k
             p_esp->i_start_time, p_esp->i_end_time );
1035
3.56k
    msg_Dbg( s, "  - data bitrate=%"PRId32" buffer=%"PRId32" initial fullness=%"PRId32,
1036
3.56k
             p_esp->i_data_bitrate,
1037
3.56k
             p_esp->i_buffer_size,
1038
3.56k
             p_esp->i_initial_buffer_fullness );
1039
3.56k
    msg_Dbg( s, "  - alternate data bitrate=%"PRId32" buffer=%"PRId32" initial fullness=%"PRId32,
1040
3.56k
             p_esp->i_alternate_data_bitrate,
1041
3.56k
             p_esp->i_alternate_buffer_size,
1042
3.56k
             p_esp->i_alternate_initial_buffer_fullness );
1043
3.56k
    msg_Dbg( s, "  - maximum object size=%"PRId32, p_esp->i_maximum_object_size );
1044
3.56k
    msg_Dbg( s, "  - flags=0x%x", p_esp->i_flags );
1045
3.56k
    msg_Dbg( s, "  - stream number=%u language=%u",
1046
3.56k
             p_esp->i_stream_number, p_esp->i_language_index );
1047
3.56k
    msg_Dbg( s, "  - average time per frame=%"PRIu64,
1048
3.56k
             p_esp->i_average_time_per_frame );
1049
3.56k
    msg_Dbg( s, "  - stream name count=%u", p_esp->i_stream_name_count );
1050
222k
    for( i = 0; i < p_esp->i_stream_name_count; i++ )
1051
218k
        msg_Dbg( s, "     - lang id=%u name=%s",
1052
3.56k
                 p_esp->pi_stream_name_language[i],
1053
3.56k
                 p_esp->ppsz_stream_name[i] );
1054
3.56k
    msg_Dbg( s, "  - payload extension system count=%u",
1055
3.56k
             p_esp->i_payload_extension_system_count );
1056
13.7k
    for( i = 0; i < p_esp->i_payload_extension_system_count; i++ )
1057
10.1k
        msg_Dbg( s, "  - %u  - payload extension: " GUID_FMT, i,
1058
3.56k
                 GUID_PRINT( p_esp->p_ext[i].i_extension_id ) );
1059
3.56k
#endif
1060
3.56k
    return VLC_SUCCESS;
1061
3.56k
}
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
4.80k
{
1245
4.80k
    asf_object_extended_content_description_t *p_ec =
1246
4.80k
                                        &p_obj->extended_content_description;
1247
4.80k
    const uint8_t *p_peek, *p_data;
1248
4.80k
    uint16_t i;
1249
1250
4.80k
    if( p_ec->i_object_size > INT32_MAX )
1251
266
        return VLC_EGENERIC;
1252
1253
4.53k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_ec->i_object_size );
1254
4.53k
    if( i_peek < 26 )
1255
235
       return VLC_EGENERIC;
1256
1257
4.30k
    p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
1258
1259
4.30k
    p_ec->i_count = ASF_READ2();
1260
4.30k
    p_ec->ppsz_name  = calloc( p_ec->i_count, sizeof(char*) );
1261
4.30k
    p_ec->ppsz_value = calloc( p_ec->i_count, sizeof(char*) );
1262
4.30k
    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
54.5k
    for( i = 0; i < p_ec->i_count; i++ )
1269
52.9k
    {
1270
52.9k
        uint16_t i_size;
1271
52.9k
        uint16_t i_type;
1272
1273
52.9k
        if( !ASF_HAVE(2 + 2+2) )
1274
2.75k
            break;
1275
1276
50.2k
        p_ec->ppsz_name[i] = ASF_READS( ASF_READ2() );
1277
1278
        /* Grrr */
1279
50.2k
        i_type = ASF_READ2();
1280
50.2k
        i_size = ASF_READ2();
1281
1282
50.2k
        if( i_type == ASF_METADATA_TYPE_STRING )
1283
42.0k
        {
1284
            /* Unicode string */
1285
42.0k
            p_ec->ppsz_value[i] = ASF_READS( i_size );
1286
42.0k
        }
1287
8.14k
        else if( i_type == ASF_METADATA_TYPE_BYTE )
1288
1.22k
        {
1289
            /* Byte array */
1290
1.22k
            static const char hex[16] = "0123456789ABCDEF";
1291
1292
1.22k
            p_ec->ppsz_value[i] = malloc( 2*i_size + 1 );
1293
1.22k
            if( p_ec->ppsz_value[i] )
1294
1.22k
            {
1295
1.22k
                char *psz_value = p_ec->ppsz_value[i];
1296
11.8M
                for( int j = 0; j < i_size; j++ )
1297
11.8M
                {
1298
11.8M
                    const uint8_t v = ASF_READ1();
1299
11.8M
                    psz_value[2*j+0] = hex[v>>4];
1300
11.8M
                    psz_value[2*j+1] = hex[v&0xf];
1301
11.8M
                }
1302
1.22k
                psz_value[2*i_size] = '\0';
1303
1.22k
            }
1304
1.22k
        }
1305
6.91k
        else if( i_type == ASF_METADATA_TYPE_BOOL )
1306
1.66k
        {
1307
            /* Bool */
1308
1.66k
            p_ec->ppsz_value[i] = strdup( ASF_READ1() ? "true" : "false" );
1309
1.66k
            ASF_SKIP(i_size-1);
1310
1.66k
        }
1311
5.24k
        else if( i_type == ASF_METADATA_TYPE_DWORD )
1312
1.32k
        {
1313
            /* DWord */
1314
1.32k
            if( asprintf( &p_ec->ppsz_value[i], "%u", ASF_READ4() ) == -1 )
1315
0
                p_ec->ppsz_value[i] = NULL;
1316
1.32k
        }
1317
3.92k
        else if( i_type == ASF_METADATA_TYPE_QWORD )
1318
582
        {
1319
            /* QWord */
1320
582
            if( asprintf( &p_ec->ppsz_value[i], "%"PRIu64, ASF_READ8() ) == -1 )
1321
0
                p_ec->ppsz_value[i] = NULL;
1322
582
        }
1323
3.34k
        else if( i_type == ASF_METADATA_TYPE_WORD )
1324
479
        {
1325
            /* Word */
1326
479
            if( asprintf( &p_ec->ppsz_value[i], "%u", ASF_READ2() ) == -1 )
1327
0
                p_ec->ppsz_value[i] = NULL;
1328
479
        }
1329
2.86k
        else
1330
2.86k
        {
1331
2.86k
            p_ec->ppsz_value[i] = NULL;
1332
2.86k
            ASF_SKIP(i_size);
1333
2.86k
        }
1334
50.2k
    }
1335
4.30k
    p_ec->i_count = i;
1336
1337
4.30k
#ifdef ASF_DEBUG
1338
4.30k
    msg_Dbg( s, "read \"extended content description object\"" );
1339
54.5k
    for( i = 0; i < p_ec->i_count; i++ )
1340
50.2k
        msg_Dbg( s, "  - '%s' = '%s'",
1341
4.30k
                 p_ec->ppsz_name[i],
1342
4.30k
                 p_ec->ppsz_value[i] );
1343
4.30k
#endif
1344
4.30k
    return VLC_SUCCESS;
1345
4.30k
}
1346
static void ASF_FreeObject_extended_content_description( asf_object_t *p_obj)
1347
4.30k
{
1348
4.30k
    asf_object_extended_content_description_t *p_ec =
1349
4.30k
                                        &p_obj->extended_content_description;
1350
1351
54.5k
    for( uint16_t i = 0; i < p_ec->i_count; i++ )
1352
50.2k
    {
1353
50.2k
        FREENULL( p_ec->ppsz_name[i] );
1354
50.2k
        FREENULL( p_ec->ppsz_value[i] );
1355
50.2k
    }
1356
4.30k
    FREENULL( p_ec->ppsz_name );
1357
4.30k
    FREENULL( p_ec->ppsz_value );
1358
4.30k
}
1359
1360
static int ASF_ReadObject_marker(stream_t *s, asf_object_t *p_obj)
1361
2.06k
{
1362
2.06k
    asf_object_marker_t *p_mk = (asf_object_marker_t *)p_obj;
1363
2.06k
    const uint8_t *p_peek, *p_data;
1364
1365
2.06k
    if( p_mk->i_object_size > INT32_MAX )
1366
245
        return VLC_EGENERIC;
1367
1368
1.82k
    ssize_t i_peek = vlc_stream_Peek( s, &p_peek, p_mk->i_object_size );
1369
1.82k
    if( i_peek < ASF_OBJECT_COMMON_SIZE )
1370
241
       return VLC_EGENERIC;
1371
1372
1.58k
    p_data = &p_peek[ASF_OBJECT_COMMON_SIZE];
1373
1374
1.58k
    if( !ASF_HAVE( 16+4+2+2 ) )
1375
238
        return VLC_EGENERIC;
1376
1377
1.34k
    ASF_GetGUID( &p_mk->i_reserved1, p_data );
1378
1.34k
    ASF_SKIP( 16 );
1379
1.34k
    p_mk->i_count = ASF_READ4();
1380
1.34k
    p_mk->i_reserved2 = ASF_READ2();
1381
1.34k
    p_mk->name = ASF_READS( ASF_READ2() );
1382
1383
1.34k
    if( p_mk->i_count > 0 )
1384
1.01k
    {
1385
1.01k
        p_mk->marker = calloc( p_mk->i_count,
1386
1.01k
                              sizeof( asf_marker_t ) );
1387
1.01k
        if( !p_mk->marker )
1388
0
            return VLC_ENOMEM;
1389
1390
3.13k
        for( uint32_t i = 0; i < p_mk->i_count; i++ )
1391
2.62k
        {
1392
2.62k
            asf_marker_t *p_marker = &p_mk->marker[i];
1393
1394
2.62k
            if( !ASF_HAVE(8+8+2+4+4+4) )
1395
509
                break;
1396
1397
2.11k
            p_marker->i_offset = ASF_READ8();
1398
2.11k
            p_marker->i_presentation_time = ASF_READ8();
1399
2.11k
            p_marker->i_entry_length = ASF_READ2();
1400
2.11k
            p_marker->i_send_time = ASF_READ4();
1401
2.11k
            p_marker->i_flags = ASF_READ4();
1402
2.11k
            p_marker->i_marker_description_length = ASF_READ4();
1403
2.11k
            if( p_marker->i_marker_description_length <= (UINT32_MAX / 2) )
1404
1.37k
                p_marker->p_marker_description = ASF_READS( p_marker->i_marker_description_length * 2 );
1405
745
            else
1406
745
                p_marker->i_marker_description_length = 0;
1407
2.11k
        }
1408
1.01k
    }
1409
1410
1.34k
#ifdef ASF_DEBUG
1411
1.34k
    msg_Dbg( s, "Read \"marker object\": %"PRIu32" chapters: %s", p_mk->i_count, p_mk->name );
1412
1413
127M
    for( unsigned i = 0; i < p_mk->i_count; i++ )
1414
127M
        msg_Dbg( s, "New chapter named: %s", p_mk->marker[i].p_marker_description );
1415
1.34k
#endif
1416
1.34k
    return VLC_SUCCESS;
1417
1.34k
}
1418
static void ASF_FreeObject_marker( asf_object_t *p_obj)
1419
1.34k
{
1420
1.34k
    asf_object_marker_t *p_mk = (asf_object_marker_t *)p_obj;
1421
1422
127M
    for( uint32_t i = 0; i < p_mk->i_count; i++ )
1423
127M
    {
1424
127M
        FREENULL( p_mk->marker[i].p_marker_description  );
1425
127M
    }
1426
1.34k
    FREENULL( p_mk->marker );
1427
1.34k
    FREENULL( p_mk->name );
1428
1.34k
}
1429
1430
static int ASF_ReadObject_Raw(stream_t *s, asf_object_t *p_obj)
1431
0
{
1432
0
    VLC_UNUSED(s);
1433
0
    VLC_UNUSED(p_obj);
1434
0
    return VLC_SUCCESS;
1435
0
}
1436
1437
/* */
1438
static const struct ASF_Object_Function_entry
1439
{
1440
    const vlc_guid_t  *p_id;
1441
    int     i_type;
1442
    int     (*ASF_ReadObject_function)( stream_t *, asf_object_t *p_obj );
1443
    void    (*ASF_FreeObject_function)( asf_object_t *p_obj );
1444
1445
} ASF_Object_Function [] =
1446
{
1447
    { &asf_object_header_guid, ASF_OBJECT_HEADER,
1448
      ASF_ReadObject_Header, ASF_FreeObject_Null },
1449
    { &asf_object_data_guid, ASF_OBJECT_DATA,
1450
      ASF_ReadObject_Data, ASF_FreeObject_Null },
1451
    { &asf_object_simple_index_guid, ASF_OBJECT_INDEX,
1452
      ASF_ReadObject_Index, ASF_FreeObject_Index },
1453
    { &asf_object_file_properties_guid, ASF_OBJECT_FILE_PROPERTIES,
1454
      ASF_ReadObject_file_properties, ASF_FreeObject_Null },
1455
    { &asf_object_stream_properties_guid, ASF_OBJECT_STREAM_PROPERTIES,
1456
      ASF_ReadObject_stream_properties,ASF_FreeObject_stream_properties },
1457
    { &asf_object_header_extension_guid, ASF_OBJECT_HEADER_EXTENSION,
1458
      ASF_ReadObject_header_extension, ASF_FreeObject_header_extension},
1459
    { &asf_object_metadata_guid, ASF_OBJECT_METADATA,
1460
      ASF_ReadObject_metadata, ASF_FreeObject_metadata},
1461
    { &asf_object_codec_list_guid, ASF_OBJECT_CODEC_LIST,
1462
      ASF_ReadObject_codec_list, ASF_FreeObject_codec_list },
1463
    { &asf_object_marker_guid, ASF_OBJECT_MARKER,
1464
      ASF_ReadObject_marker, ASF_FreeObject_marker },
1465
    { &asf_object_padding, ASF_OBJECT_PADDING, NULL, NULL },
1466
    { &asf_object_compatibility_guid, ASF_OBJECT_OTHER, NULL, NULL },
1467
    { &asf_object_content_description_guid, ASF_OBJECT_CONTENT_DESCRIPTION,
1468
      ASF_ReadObject_content_description, ASF_FreeObject_content_description },
1469
    { &asf_object_language_list, ASF_OBJECT_OTHER,
1470
      ASF_ReadObject_language_list, ASF_FreeObject_language_list },
1471
    { &asf_object_stream_bitrate_properties, ASF_OBJECT_OTHER,
1472
      ASF_ReadObject_stream_bitrate_properties,
1473
      ASF_FreeObject_stream_bitrate_properties },
1474
    { &asf_object_extended_stream_properties_guid, ASF_OBJECT_OTHER,
1475
      ASF_ReadObject_extended_stream_properties,
1476
      ASF_FreeObject_extended_stream_properties },
1477
    { &asf_object_advanced_mutual_exclusion, ASF_OBJECT_OTHER,
1478
      ASF_ReadObject_advanced_mutual_exclusion,
1479
      ASF_FreeObject_advanced_mutual_exclusion },
1480
    { &asf_object_stream_prioritization, ASF_OBJECT_OTHER,
1481
      ASF_ReadObject_stream_prioritization,
1482
      ASF_FreeObject_stream_prioritization },
1483
    { &asf_object_bitrate_mutual_exclusion_guid, ASF_OBJECT_OTHER,
1484
      ASF_ReadObject_bitrate_mutual_exclusion,
1485
      ASF_FreeObject_bitrate_mutual_exclusion },
1486
    { &asf_object_extended_content_description, ASF_OBJECT_OTHER,
1487
      ASF_ReadObject_extended_content_description,
1488
      ASF_FreeObject_extended_content_description },
1489
    { &asf_object_content_encryption_guid, ASF_OBJECT_OTHER,
1490
      ASF_ReadObject_Raw, ASF_FreeObject_Null },
1491
    { &asf_object_advanced_content_encryption_guid, ASF_OBJECT_OTHER,
1492
      ASF_ReadObject_Raw, ASF_FreeObject_Null },
1493
    { &asf_object_extended_content_encryption_guid, ASF_OBJECT_OTHER,
1494
      ASF_ReadObject_Raw, ASF_FreeObject_Null },
1495
};
1496
1497
static void ASF_ParentObject( asf_object_t *p_father, asf_object_t *p_obj )
1498
228k
{
1499
228k
    if( p_father )
1500
227k
    {
1501
227k
        if( p_father->common.p_first )
1502
72.4k
        {
1503
72.4k
            p_father->common.p_last->common.p_next = p_obj;
1504
72.4k
        }
1505
155k
        else
1506
155k
        {
1507
155k
            p_father->common.p_first = p_obj;
1508
155k
        }
1509
227k
        p_father->common.p_last = p_obj;
1510
227k
    }
1511
228k
}
1512
1513
static const struct ASF_Object_Function_entry * ASF_GetObject_Function( const vlc_guid_t *id )
1514
476k
{
1515
2.25M
    for( size_t i = 0; i < ARRAY_SIZE(ASF_Object_Function); i++ )
1516
2.21M
    {
1517
2.21M
        if( guidcmp( ASF_Object_Function[i].p_id, id ) )
1518
433k
            return &ASF_Object_Function[i];
1519
2.21M
    }
1520
42.9k
    return NULL;
1521
476k
}
1522
1523
static int ASF_ReadObject( stream_t *s, asf_object_t *p_obj,
1524
                           asf_object_t *p_father )
1525
284k
{
1526
284k
    int i_result = VLC_SUCCESS;
1527
1528
284k
    if( !p_obj )
1529
0
        return VLC_SUCCESS;
1530
1531
284k
    memset( p_obj, 0, sizeof( *p_obj ) );
1532
1533
284k
    if( ASF_ReadObjectCommon( s, p_obj ) )
1534
33.9k
    {
1535
33.9k
        msg_Warn( s, "cannot read one asf object at %"PRIu64, vlc_stream_Tell(s) );
1536
33.9k
        return VLC_EGENERIC;
1537
33.9k
    }
1538
250k
    p_obj->common.p_father = p_father;
1539
250k
    p_obj->common.p_first = NULL;
1540
250k
    p_obj->common.p_next = NULL;
1541
250k
    p_obj->common.p_last = NULL;
1542
250k
    p_obj->common.i_type = 0;
1543
1544
250k
    if( p_obj->common.i_object_size < ASF_OBJECT_COMMON_SIZE )
1545
2.49k
    {
1546
2.49k
        msg_Warn( s, "found a corrupted asf object (size<24) at %"PRIu64, vlc_stream_Tell(s) );
1547
2.49k
        return VLC_EGENERIC;
1548
2.49k
    }
1549
1550
248k
    const struct ASF_Object_Function_entry *p_reader =
1551
248k
            ASF_GetObject_Function( &p_obj->common.i_object_id );
1552
248k
    if( p_reader )
1553
226k
    {
1554
226k
        p_obj->common.i_type = p_reader->i_type;
1555
1556
        /* Now load this object */
1557
226k
        if( p_reader->ASF_ReadObject_function != NULL )
1558
224k
            i_result = p_reader->ASF_ReadObject_function( s, p_obj );
1559
226k
    }
1560
21.4k
    else
1561
21.4k
    {
1562
21.4k
        msg_Warn( s, "unknown asf object (not loaded): " GUID_FMT,
1563
21.4k
                GUID_PRINT( p_obj->common.i_object_id ) );
1564
21.4k
    }
1565
1566
    /* link this object with father */
1567
248k
    if ( i_result == VLC_SUCCESS )
1568
227k
        ASF_ParentObject( p_father, p_obj );
1569
1570
248k
    return i_result;
1571
250k
}
1572
1573
static void ASF_FreeObject( stream_t *s, asf_object_t *p_obj )
1574
227k
{
1575
227k
    asf_object_t *p_child;
1576
1577
227k
    if( !p_obj )
1578
0
        return;
1579
1580
    /* Free all child object */
1581
227k
    p_child = p_obj->common.p_first;
1582
440k
    while( p_child )
1583
213k
    {
1584
213k
        asf_object_t *p_next;
1585
213k
        p_next = p_child->common.p_next;
1586
213k
        ASF_FreeObject( s, p_child );
1587
213k
        p_child = p_next;
1588
213k
    }
1589
1590
    /* find this object */
1591
227k
    const struct ASF_Object_Function_entry *p_entry =
1592
227k
            ASF_GetObject_Function( &p_obj->common.i_object_id );
1593
227k
    if( p_entry && p_entry->ASF_FreeObject_function )
1594
203k
    {
1595
        /* Now free this object */
1596
203k
#ifdef ASF_DEBUG
1597
203k
        msg_Dbg( s,
1598
203k
                  "freing asf object " GUID_FMT,
1599
203k
                  GUID_PRINT( p_obj->common.i_object_id ) );
1600
203k
#endif
1601
203k
        p_entry->ASF_FreeObject_function( p_obj );
1602
203k
    }
1603
1604
227k
    free( p_obj );
1605
227k
}
1606
1607
/*****************************************************************************
1608
 * ASF_ObjectDumpDebug:
1609
 *****************************************************************************/
1610
static const struct
1611
{
1612
    const vlc_guid_t *p_id;
1613
    const char *psz_name;
1614
} ASF_ObjectDumpDebugInfo[] =
1615
{
1616
    { &vlc_object_root_guid, "Root" },
1617
    { &asf_object_header_guid, "Header" },
1618
    { &asf_object_data_guid, "Data" },
1619
    { &asf_object_index_guid, "Index" },
1620
    { &asf_object_simple_index_guid, "Simple Index" },
1621
    { &asf_object_file_properties_guid, "File Properties" },
1622
    { &asf_object_stream_properties_guid, "Stream Properties" },
1623
    { &asf_object_content_description_guid, "Content Description" },
1624
    { &asf_object_header_extension_guid, "Header Extension" },
1625
    { &asf_object_metadata_guid, "Metadata" },
1626
    { &asf_object_codec_list_guid, "Codec List" },
1627
    { &asf_object_marker_guid, "Marker" },
1628
    { &asf_object_stream_type_audio, "Stream Type Audio" },
1629
    { &asf_object_stream_type_video, "Stream Type Video" },
1630
    { &asf_object_stream_type_command, "Stream Type Command" },
1631
    { &asf_object_language_list, "Language List" },
1632
    { &asf_object_stream_bitrate_properties, "Stream Bitrate Properties" },
1633
    { &asf_object_padding, "Padding" },
1634
    { &asf_object_extended_stream_properties_guid, "Extended Stream Properties" },
1635
    { &asf_object_advanced_mutual_exclusion, "Advanced Mutual Exclusion" },
1636
    { &asf_object_stream_prioritization, "Stream Prioritization" },
1637
    { &asf_object_bitrate_mutual_exclusion_guid, "Bitrate Mutual Exclusion" },
1638
    { &asf_object_extended_content_description, "Extended content description"},
1639
    { &asf_object_content_encryption_guid, "Content Encryption"},
1640
    { &asf_object_advanced_content_encryption_guid, "Advanced Content Encryption"},
1641
    { &asf_object_extended_content_encryption_guid, "Extended Content Encryption"},
1642
    /* Non Readable from this point */
1643
    { &nonasf_object_index_placeholder_guid, "Index Placeholder"},
1644
    { &nonasf_object_compatibility, "Object Compatibility"},
1645
1646
    { NULL, "Unknown" },
1647
};
1648
1649
1650
static void ASF_ObjectDumpDebug( vlc_object_t *p_obj,
1651
                                 asf_object_common_t *p_node, unsigned i_level )
1652
51.0k
{
1653
51.0k
    unsigned i;
1654
51.0k
    union asf_object_u *p_child;
1655
51.0k
    const char *psz_name;
1656
1657
    /* Find the name */
1658
452k
    for( i = 0; ASF_ObjectDumpDebugInfo[i].p_id != NULL; i++ )
1659
443k
    {
1660
443k
        if( guidcmp( ASF_ObjectDumpDebugInfo[i].p_id,
1661
443k
                          &p_node->i_object_id ) )
1662
42.6k
            break;
1663
443k
    }
1664
51.0k
    psz_name = ASF_ObjectDumpDebugInfo[i].psz_name;
1665
1666
51.0k
    char str[512];
1667
51.0k
    if( i_level >= (sizeof(str) - 1)/5 )
1668
97
        return;
1669
1670
50.9k
    memset( str, ' ', sizeof( str ) );
1671
696k
    for( i = 0; i < i_level; i++ )
1672
645k
    {
1673
645k
        str[i * 4] = '|';
1674
645k
    }
1675
50.9k
    snprintf( &str[4*i_level], sizeof(str) - 5*i_level,
1676
50.9k
             "+ '%s'"
1677
50.9k
#ifdef ASF_DEBUG
1678
50.9k
             "GUID "GUID_FMT" size:%"PRIu64" pos:%"PRIu64
1679
50.9k
#endif
1680
50.9k
             , psz_name
1681
1682
50.9k
#ifdef ASF_DEBUG
1683
50.9k
             , GUID_PRINT( p_node->i_object_id ),
1684
50.9k
             p_node->i_object_size, p_node->i_object_pos
1685
50.9k
#endif
1686
50.9k
             );
1687
1688
1689
50.9k
    msg_Dbg( p_obj, "%s", str );
1690
1691
98.7k
    for( p_child = p_node->p_first; p_child != NULL;
1692
50.9k
                                             p_child = p_child->common.p_next )
1693
47.7k
    {
1694
47.7k
        ASF_ObjectDumpDebug( p_obj, &p_child->common, i_level + 1 );
1695
47.7k
    }
1696
50.9k
}
1697
1698
/*****************************************************************************
1699
 * ASF_ReadObjetRoot : parse the entire stream/file
1700
 *****************************************************************************/
1701
asf_object_root_t *ASF_ReadObjectRoot( stream_t *s, int b_seekable )
1702
7.71k
{
1703
7.71k
    asf_object_root_t *p_root = malloc( sizeof( asf_object_root_t ) );
1704
7.71k
    asf_object_t *p_obj;
1705
7.71k
    uint64_t i_boundary = 0;
1706
1707
7.71k
    if( !p_root )
1708
0
        return NULL;
1709
1710
7.71k
    p_root->i_type = ASF_OBJECT_ROOT;
1711
7.71k
    memcpy( &p_root->i_object_id, &vlc_object_root_guid, sizeof( vlc_guid_t ) );
1712
7.71k
    p_root->i_object_pos = vlc_stream_Tell( s );
1713
7.71k
    p_root->i_object_size = 0;
1714
7.71k
    p_root->p_first = NULL;
1715
7.71k
    p_root->p_last  = NULL;
1716
7.71k
    p_root->p_next  = NULL;
1717
7.71k
    p_root->p_hdr   = NULL;
1718
7.71k
    p_root->p_data  = NULL;
1719
7.71k
    p_root->p_fp    = NULL;
1720
7.71k
    p_root->p_index = NULL;
1721
7.71k
    p_root->p_metadata = NULL;
1722
1723
7.71k
    for( ; ; )
1724
22.0k
    {
1725
22.0k
        p_obj = malloc( sizeof( asf_object_t ) );
1726
1727
22.0k
        if( !p_obj || ASF_ReadObject( s, p_obj, (asf_object_t*)p_root ) )
1728
7.47k
        {
1729
7.47k
            free( p_obj );
1730
7.47k
            break;
1731
7.47k
        }
1732
14.5k
        switch( p_obj->common.i_type )
1733
14.5k
        {
1734
9.27k
            case( ASF_OBJECT_HEADER ):
1735
9.27k
                if ( p_root->p_index || p_root->p_data || p_root->p_hdr ) break;
1736
7.62k
                p_root->p_hdr = (asf_object_header_t*)p_obj;
1737
7.62k
                break;
1738
3.61k
            case( ASF_OBJECT_DATA ):
1739
3.61k
                if ( p_root->p_index || p_root->p_data ) break;
1740
3.52k
                p_root->p_data = (asf_object_data_t*)p_obj;
1741
3.52k
            break;
1742
6
            case( ASF_OBJECT_INDEX ):
1743
6
                if ( p_root->p_index ) break;
1744
6
                p_root->p_index = (asf_object_index_t*)p_obj;
1745
6
                break;
1746
1.67k
            default:
1747
1.67k
                msg_Warn( s, "unknown top-level object found: " GUID_FMT,
1748
1.67k
                      GUID_PRINT( p_obj->common.i_object_id ) );
1749
1.67k
                break;
1750
14.5k
        }
1751
1752
        /* Set a limit to avoid junk when possible */
1753
14.5k
        if ( guidcmp( &p_obj->common.i_object_id, &asf_object_file_properties_guid ) )
1754
214
        {
1755
214
            i_boundary = p_obj->file_properties.i_file_size;
1756
214
        }
1757
1758
14.5k
        if( p_obj->common.i_type == ASF_OBJECT_DATA &&
1759
3.61k
            p_obj->common.i_object_size <= 50 )
1760
172
        {
1761
            /* probably a dump of broadcasted asf */
1762
172
            break;
1763
172
        }
1764
14.3k
        if( !b_seekable && p_root->p_hdr && p_root->p_data )
1765
0
        {
1766
            /* For unseekable stream it's enough to play */
1767
0
            break;
1768
0
        }
1769
1770
14.3k
        if( ASF_NextObject( s, p_obj, i_boundary ) ) /* Go to the next object */
1771
70
            break;
1772
14.3k
    }
1773
1774
7.71k
    if( p_root->p_hdr != NULL && p_root->p_data != NULL )
1775
3.52k
    {
1776
3.52k
        p_root->p_fp = ASF_FindObject( p_root->p_hdr,
1777
3.52k
                                       &asf_object_file_properties_guid, 0 );
1778
1779
3.52k
        if( p_root->p_fp )
1780
3.32k
        {
1781
3.32k
            asf_object_t *p_hdr_ext =
1782
3.32k
                ASF_FindObject( p_root->p_hdr,
1783
3.32k
                                &asf_object_header_extension_guid, 0 );
1784
3.32k
            if( p_hdr_ext )
1785
1.68k
            {
1786
1.68k
                p_root->p_metadata =
1787
1.68k
                    ASF_FindObject( p_hdr_ext,
1788
1.68k
                                    &asf_object_metadata_guid, 0 );
1789
1.68k
            }
1790
1791
3.32k
            ASF_ObjectDumpDebug( VLC_OBJECT(s),
1792
3.32k
                                 (asf_object_common_t*)p_root, 0 );
1793
3.32k
            return p_root;
1794
3.32k
        }
1795
195
        msg_Warn( s, "cannot find file properties object" );
1796
195
    }
1797
1798
    /* Invalid file */
1799
4.38k
    ASF_FreeObjectRoot( s, p_root );
1800
4.38k
    return NULL;
1801
7.71k
}
1802
1803
void ASF_FreeObjectRoot( stream_t *s, asf_object_root_t *p_root )
1804
7.71k
{
1805
7.71k
    asf_object_t *p_obj;
1806
1807
7.71k
    p_obj = p_root->p_first;
1808
22.2k
    while( p_obj )
1809
14.5k
    {
1810
14.5k
        asf_object_t *p_next;
1811
14.5k
        p_next = p_obj->common.p_next;
1812
14.5k
        ASF_FreeObject( s, p_obj );
1813
14.5k
        p_obj = p_next;
1814
14.5k
    }
1815
7.71k
    free( p_root );
1816
7.71k
}
1817
1818
int ASF_CountObject( void *_p_obj, const vlc_guid_t *p_guid )
1819
5.23k
{
1820
5.23k
    int i_count;
1821
5.23k
    asf_object_t *p_child, *p_obj;
1822
1823
5.23k
    p_obj = (asf_object_t *)_p_obj;
1824
5.23k
    if( !p_obj )
1825
0
        return 0;
1826
1827
5.23k
    i_count = 0;
1828
5.23k
    p_child = p_obj->common.p_first;
1829
25.7k
    while( p_child )
1830
20.5k
    {
1831
20.5k
        if( guidcmp( &p_child->common.i_object_id, p_guid ) )
1832
4.24k
            i_count++;
1833
1834
20.5k
        p_child = p_child->common.p_next;
1835
20.5k
    }
1836
5.23k
    return i_count;
1837
5.23k
}
1838
1839
void *ASF_FindObject( void *_p_obj, const vlc_guid_t *p_guid,
1840
                        int i_number )
1841
39.4k
{
1842
39.4k
    asf_object_t *p_child, *p_obj;
1843
1844
39.4k
    p_obj = (asf_object_t *)_p_obj;
1845
39.4k
    p_child = p_obj->common.p_first;
1846
1847
154k
    while( p_child )
1848
127k
    {
1849
127k
        if( guidcmp( &p_child->common.i_object_id, p_guid ) )
1850
13.4k
        {
1851
13.4k
            if( i_number == 0 )
1852
12.9k
                return p_child;
1853
1854
566
            i_number--;
1855
566
        }
1856
115k
        p_child = p_child->common.p_next;
1857
115k
    }
1858
26.5k
    return NULL;
1859
39.4k
}