Coverage Report

Created: 2026-08-31 08:22

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