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