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