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