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