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