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