1 /*
2 * Copyright (C) 2002-2003 the xine project
3 *
4 * This file is part of xine, a free video player.
5 *
6 * xine is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * xine is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 *
20 * $Id: 34c49de566fd27b3571770e5bedb76399c704af5 $
21 *
22 * sdp/sdpplin parser.
23 *
24 */
25
26 #include "real.h"
27 #include <vlc_strings.h>
28 #define BUFLEN 32000
29
nl(char * data)30 static inline char *nl(char *data) {
31 char *nlptr = (data) ? strchr(data,'\n') : NULL;
32 return (nlptr) ? nlptr + 1 : NULL;
33 }
34
line_length(char * data)35 static inline int line_length(char * data) {
36 char const * p = nl(data);
37 if (p) {
38 return p - data - 1;
39 }
40 return strlen(data);
41 }
42
filter(stream_t * p_access,const char * in,const char * filter,char ** out,size_t outlen)43 static int filter(stream_t *p_access, const char *in, const char *filter, char **out, size_t outlen) {
44
45 int flen=strlen(filter);
46 size_t len;
47
48 if (!in) return 0;
49
50 len = (strchr(in,'\n')) ? (size_t)(strchr(in,'\n')-in) : strlen(in);
51 if (!strncmp(in,filter,flen)) {
52 if(in[flen]=='"') flen++;
53 if(in[len-1]==13) len--;
54 if(in[len-1]=='"') len--;
55 if( len-flen+1 > outlen )
56 {
57 msg_Warn(p_access, "Discarding end of string to avoid overflow");
58 len=outlen+flen-1;
59 }
60 memcpy(*out, in+flen, len-flen+1);
61 (*out)[len-flen]=0;
62 return len-flen;
63 }
64 return 0;
65 }
66
sdpplin_parse_stream(stream_t * p_access,char ** data)67 static sdpplin_stream_t *sdpplin_parse_stream(stream_t *p_access, char **data) {
68
69 sdpplin_stream_t *desc;
70 char* buf = NULL;
71 unsigned char* decoded = NULL;
72 int handled;
73
74 desc = calloc( 1, sizeof(sdpplin_stream_t) );
75 if( !desc )
76 return NULL;
77
78 buf = malloc( BUFLEN );
79 if( !buf )
80 goto error;
81
82 decoded = malloc( BUFLEN );
83 if( !decoded )
84 goto error;
85
86 if (filter(p_access, *data, "m=", &buf, BUFLEN)) {
87 desc->id = strdup(buf);
88 } else {
89 msg_Dbg(p_access, "sdpplin: no m= found.");
90 goto error;
91 }
92 *data=nl(*data);
93
94 while (*data && **data && *data[0]!='m') {
95 handled=0;
96
97 if(filter(p_access, *data,"a=control:streamid=",&buf, BUFLEN)) {
98 /* This way negative values are mapped to unfeasibly high
99 * values, and will be discarded afterward
100 */
101 unsigned long tmp = strtoul(buf, NULL, 10);
102 if ( tmp > UINT16_MAX )
103 msg_Warn(p_access, "stream id out of bound: %lu", tmp);
104 else
105 desc->stream_id=tmp;
106 handled=1;
107 *data=nl(*data);
108 }
109 if(filter(p_access, *data,"a=MaxBitRate:integer;",&buf, BUFLEN)) {
110 desc->max_bit_rate=atoi(buf);
111 if (!desc->avg_bit_rate)
112 desc->avg_bit_rate=desc->max_bit_rate;
113 handled=1;
114 *data=nl(*data);
115 }
116 if(filter(p_access, *data,"a=MaxPacketSize:integer;",&buf, BUFLEN)) {
117 desc->max_packet_size=atoi(buf);
118 if (!desc->avg_packet_size)
119 desc->avg_packet_size=desc->max_packet_size;
120 handled=1;
121 *data=nl(*data);
122 }
123 if(filter(p_access, *data,"a=StartTime:integer;",&buf, BUFLEN)) {
124 desc->start_time=atoi(buf);
125 handled=1;
126 *data=nl(*data);
127 }
128 if(filter(p_access, *data,"a=Preroll:integer;",&buf, BUFLEN)) {
129 desc->preroll=atoi(buf);
130 handled=1;
131 *data=nl(*data);
132 }
133 if(filter(p_access, *data,"a=length:npt=",&buf, BUFLEN)) {
134 desc->duration=(uint32_t)(atof(buf)*1000);
135 handled=1;
136 *data=nl(*data);
137 }
138 if(filter(p_access, *data,"a=StreamName:string;",&buf, BUFLEN)) {
139 desc->stream_name=strdup(buf);
140 desc->stream_name_size=strlen(desc->stream_name);
141 handled=1;
142 *data=nl(*data);
143 }
144 if(filter(p_access, *data,"a=mimetype:string;",&buf, BUFLEN)) {
145 desc->mime_type=strdup(buf);
146 desc->mime_type_size=strlen(desc->mime_type);
147 handled=1;
148 *data=nl(*data);
149 }
150 if(filter(p_access, *data,"a=OpaqueData:buffer;",&buf, BUFLEN)) {
151 desc->mlti_data_size =
152 vlc_b64_decode_binary_to_buffer(decoded, BUFLEN, buf );
153 if ( desc->mlti_data_size ) {
154 desc->mlti_data = malloc(desc->mlti_data_size);
155 memcpy(desc->mlti_data, decoded, desc->mlti_data_size);
156 handled=1;
157 *data=nl(*data);
158 msg_Dbg(p_access, "mlti_data_size: %i", desc->mlti_data_size);
159 }
160 }
161 if(filter(p_access, *data,"a=ASMRuleBook:string;",&buf, BUFLEN)) {
162 desc->asm_rule_book=strdup(buf);
163 handled=1;
164 *data=nl(*data);
165 }
166
167 if(!handled) {
168 #ifdef LOG
169 int len = line_length(*data);
170 ; len = len < BUFLEN ? len : BUFLEN-1;
171 buf[len] = '\0';
172 strncpy (buf, *data, len);
173 msg_Warn(p_access, "libreal: sdpplin: not handled: '%s'", buf);
174 #endif
175 *data=nl(*data); /* always move to next line */
176 }
177 }
178 free( buf );
179 free( decoded) ;
180 return desc;
181
182 error:
183 free( decoded );
184 free( desc );
185 free( buf );
186 return NULL;
187 }
188
189
sdpplin_parse(stream_t * p_access,char * data)190 sdpplin_t *sdpplin_parse(stream_t *p_access, char *data)
191 {
192 sdpplin_t* desc;
193 sdpplin_stream_t* stream;
194 char* buf;
195 char* decoded;
196 int handled;
197
198 desc = calloc( 1, sizeof(sdpplin_t) );
199 if( !desc )
200 return NULL;
201
202 buf = malloc( BUFLEN );
203 if( !buf )
204 {
205 free( desc );
206 return NULL;
207 }
208
209 decoded = malloc( BUFLEN );
210 if( !decoded )
211 {
212 free( buf );
213 free( desc );
214 return NULL;
215 }
216 desc->stream = NULL;
217
218 while (data && *data) {
219 handled=0;
220
221 if (filter(p_access, data, "m=", &buf, BUFLEN)) {
222 if ( !desc->stream ) {
223 msg_Warn(p_access, "sdpplin.c: stream identifier found before stream count, skipping.");
224 data = nl(data);
225 continue;
226 }
227 stream=sdpplin_parse_stream(p_access, &data);
228 msg_Dbg(p_access, "got data for stream id %u", stream->stream_id);
229 if ( stream->stream_id >= desc->stream_count )
230 msg_Warn(p_access, "stream id %u is greater than stream count %u\n", stream->stream_id, desc->stream_count);
231 else
232 desc->stream[stream->stream_id]=stream;
233 continue;
234 }
235 if(filter(p_access, data,"a=Title:buffer;",&buf, BUFLEN)) {
236 desc->title=vlc_b64_decode(buf);
237 if(desc->title) {
238 handled=1;
239 data=nl(data);
240 }
241 }
242 if(filter(p_access, data,"a=Author:buffer;",&buf, BUFLEN)) {
243 desc->author=vlc_b64_decode(buf);
244 if(desc->author) {
245 handled=1;
246 data=nl(data);
247 }
248 }
249 if(filter(p_access, data,"a=Copyright:buffer;",&buf, BUFLEN)) {
250 desc->copyright=vlc_b64_decode(buf);
251 if(desc->copyright) {
252 handled=1;
253 data=nl(data);
254 }
255 }
256 if(filter(p_access, data,"a=Abstract:buffer;",&buf, BUFLEN)) {
257 desc->abstract=vlc_b64_decode(buf);
258 if(desc->abstract) {
259 handled=1;
260 data=nl(data);
261 }
262 }
263 if(filter(p_access, data,"a=StreamCount:integer;",&buf, BUFLEN)) {
264 /* This way negative values are mapped to unfeasibly high
265 * values, and will be discarded afterward
266 */
267 unsigned long tmp = strtoul(buf, NULL, 10);
268 if ( tmp > UINT16_MAX )
269 msg_Warn(p_access, "stream count out of bound: %lu\n", tmp);
270 else
271 desc->stream_count = tmp;
272 desc->stream = malloc(sizeof(sdpplin_stream_t*)*desc->stream_count);
273 handled=1;
274 data=nl(data);
275 }
276 if(filter(p_access, data,"a=Flags:integer;",&buf, BUFLEN)) {
277 desc->flags=atoi(buf);
278 handled=1;
279 data=nl(data);
280 }
281
282 if(!handled) {
283 #ifdef LOG
284 int len = line_length(data);
285 ; len = len < BUFLEN ? len : BUFLEN-1;
286 buf[len] = '\0';
287 strncpy (buf, data, len);
288 msg_Warn(p_access, "libreal: sdpplin: not handled: '%s'", buf);
289 #endif
290 data=nl(data);
291 }
292 }
293
294 free( decoded );
295 free( buf );
296 return desc;
297 }
298
sdpplin_free(sdpplin_t * description)299 void sdpplin_free(sdpplin_t *description) {
300
301 int i;
302
303 if( !description ) return;
304
305 for( i=0; i<description->stream_count; i++ ) {
306 if( description->stream[i] ) {
307 free( description->stream[i]->id );
308 free( description->stream[i]->bandwidth );
309 free( description->stream[i]->range );
310 free( description->stream[i]->length );
311 free( description->stream[i]->rtpmap );
312 free( description->stream[i]->mimetype );
313 free( description->stream[i]->stream_name );
314 free( description->stream[i]->mime_type );
315 free( description->stream[i]->mlti_data );
316 free( description->stream[i]->rmff_flags );
317 free( description->stream[i]->asm_rule_book );
318 free( description->stream[i] );
319 }
320 }
321 if( description->stream_count )
322 free( description->stream );
323
324 free( description->owner );
325 free( description->session_name );
326 free( description->session_info );
327 free( description->uri );
328 free( description->email );
329 free( description->phone );
330 free( description->connection );
331 free( description->bandwidth );
332 free( description->title );
333 free( description->author );
334 free( description->copyright );
335 free( description->keywords );
336 free( description->asm_rule_book );
337 free( description->abstract );
338 free( description->range );
339 free( description );
340 }
341
342