]> git.sesse.net Git - vlc/blob - modules/access/rtsp/real_sdpplin.c
Merge branch 1.0-bugfix
[vlc] / modules / access / rtsp / real_sdpplin.c
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$
21  *
22  * sdp/sdpplin parser.
23  *
24  */
25
26 #include "real.h"
27 #include "vlc_strings.h"
28 #define BUFLEN 32000
29
30 static inline char *nl(char *data) {
31   char *nlptr = (data) ? strchr(data,'\n') : NULL;
32   return (nlptr) ? nlptr + 1 : NULL;
33 }
34
35 static int filter(const char *in, const char *filter, char **out, size_t outlen) {
36
37   int flen=strlen(filter);
38   size_t len;
39
40   if (!in) return 0;
41
42   len = (strchr(in,'\n')) ? (size_t)(strchr(in,'\n')-in) : strlen(in);
43   if (!strncmp(in,filter,flen)) {
44     if(in[flen]=='"') flen++;
45     if(in[len-1]==13) len--;
46     if(in[len-1]=='"') len--;
47     if( len-flen+1 > outlen )
48     {
49         printf("Discarding end of string to avoid overflow");
50         len=outlen+flen-1;
51     }
52     memcpy(*out, in+flen, len-flen+1);
53     (*out)[len-flen]=0;
54     return len-flen;
55   }
56   return 0;
57 }
58
59 static sdpplin_stream_t *sdpplin_parse_stream(char **data) {
60
61   sdpplin_stream_t *desc;
62   char* buf = NULL;
63   char* decoded = NULL;
64   int handled;
65
66   desc = calloc( 1, sizeof(sdpplin_stream_t) );
67   if( !desc )
68     return NULL;
69
70   buf = malloc( BUFLEN );
71   if( !buf )
72     goto error;
73
74   decoded = malloc( BUFLEN );
75   if( !decoded )
76     goto error;
77
78   if (filter(*data, "m=", &buf, BUFLEN)) {
79     desc->id = strdup(buf);
80   } else {
81     lprintf("sdpplin: no m= found.\n");
82     goto error;
83   }
84   *data=nl(*data);
85
86   while (*data && **data && *data[0]!='m') {
87     handled=0;
88
89     if(filter(*data,"a=control:streamid=",&buf, BUFLEN)) {
90         /* This way negative values are mapped to unfeasibly high
91          * values, and will be discarded afterward
92          */
93         unsigned long tmp = strtoul(buf, NULL, 10);
94         if ( tmp > UINT16_MAX )
95             lprintf("stream id out of bound: %lu\n", tmp);
96         else
97             desc->stream_id=tmp;
98         handled=1;
99         *data=nl(*data);
100     }
101     if(filter(*data,"a=MaxBitRate:integer;",&buf, BUFLEN)) {
102       desc->max_bit_rate=atoi(buf);
103       if (!desc->avg_bit_rate)
104         desc->avg_bit_rate=desc->max_bit_rate;
105       handled=1;
106       *data=nl(*data);
107     }
108     if(filter(*data,"a=MaxPacketSize:integer;",&buf, BUFLEN)) {
109       desc->max_packet_size=atoi(buf);
110       if (!desc->avg_packet_size)
111         desc->avg_packet_size=desc->max_packet_size;
112       handled=1;
113       *data=nl(*data);
114     }
115     if(filter(*data,"a=StartTime:integer;",&buf, BUFLEN)) {
116       desc->start_time=atoi(buf);
117       handled=1;
118       *data=nl(*data);
119     }
120     if(filter(*data,"a=Preroll:integer;",&buf, BUFLEN)) {
121       desc->preroll=atoi(buf);
122       handled=1;
123       *data=nl(*data);
124     }
125     if(filter(*data,"a=length:npt=",&buf, BUFLEN)) {
126       desc->duration=(uint32_t)(atof(buf)*1000);
127       handled=1;
128       *data=nl(*data);
129     }
130     if(filter(*data,"a=StreamName:string;",&buf, BUFLEN)) {
131       desc->stream_name=strdup(buf);
132       desc->stream_name_size=strlen(desc->stream_name);
133       handled=1;
134       *data=nl(*data);
135     }
136     if(filter(*data,"a=mimetype:string;",&buf, BUFLEN)) {
137       desc->mime_type=strdup(buf);
138       desc->mime_type_size=strlen(desc->mime_type);
139       handled=1;
140       *data=nl(*data);
141     }
142     if(filter(*data,"a=OpaqueData:buffer;",&buf, BUFLEN)) {
143       desc->mlti_data_size =
144           vlc_b64_decode_binary_to_buffer(decoded, BUFLEN, buf );
145       if ( desc->mlti_data_size ) {
146           desc->mlti_data = malloc(desc->mlti_data_size);
147           memcpy(desc->mlti_data, decoded, desc->mlti_data_size);
148           handled=1;
149           *data=nl(*data);
150           lprintf("mlti_data_size: %i\n", desc->mlti_data_size);
151       }
152     }
153     if(filter(*data,"a=ASMRuleBook:string;",&buf, BUFLEN)) {
154       desc->asm_rule_book=strdup(buf);
155       handled=1;
156       *data=nl(*data);
157     }
158
159     if(!handled) {
160 #ifdef LOG
161       int len=strchr(*data,'\n')-(*data);
162       memcpy(buf, *data, len+1);
163       buf[len]=0;
164       printf("libreal: sdpplin: not handled: '%s'\n", buf);
165 #endif
166       *data=nl(*data);
167     }
168   }
169   free( buf );
170   free( decoded) ;
171   return desc;
172
173 error:
174   free( decoded );
175   free( desc );
176   free( buf );
177   return NULL;
178 }
179
180
181 sdpplin_t *sdpplin_parse(char *data)
182 {
183   sdpplin_t*        desc;
184   sdpplin_stream_t* stream;
185   char*             buf;
186   char*             decoded;
187   int               handled;
188   int               len;
189
190   desc = calloc( 1, sizeof(sdpplin_t) );
191   if( !desc )
192     return NULL;
193
194   buf = malloc( BUFLEN );
195   if( !buf )
196   {
197     free( desc );
198     return NULL;
199   }
200
201   decoded = malloc( BUFLEN );
202   if( !decoded )
203   {
204     free( buf );
205     free( desc );
206     return NULL;
207   }
208   desc->stream = NULL;
209
210   while (data && *data) {
211     handled=0;
212
213     if (filter(data, "m=", &buf, BUFLEN)) {
214         if ( !desc->stream ) {
215             fprintf(stderr, "sdpplin.c: stream identifier found before stream count, skipping.");
216             continue;
217         }
218         stream=sdpplin_parse_stream(&data);
219         lprintf("got data for stream id %u\n", stream->stream_id);
220         if ( stream->stream_id >= desc->stream_count )
221             lprintf("stream id %u is greater than stream count %u\n", stream->stream_id, desc->stream_count);
222         else
223             desc->stream[stream->stream_id]=stream;
224         continue;
225     }
226     if(filter(data,"a=Title:buffer;",&buf, BUFLEN)) {
227       desc->title=vlc_b64_decode(buf);
228       if(desc->title) {
229         handled=1;
230         data=nl(data);
231       }
232     }
233     if(filter(data,"a=Author:buffer;",&buf, BUFLEN)) {
234       desc->author=vlc_b64_decode(buf);
235       if(desc->author) {
236         handled=1;
237         data=nl(data);
238       }
239     }
240     if(filter(data,"a=Copyright:buffer;",&buf, BUFLEN)) {
241       desc->copyright=vlc_b64_decode(buf);
242       if(desc->copyright) {
243         handled=1;
244         data=nl(data);
245       }
246     }
247     if(filter(data,"a=Abstract:buffer;",&buf, BUFLEN)) {
248       desc->abstract=vlc_b64_decode(buf);
249       if(desc->abstract) {
250         handled=1;
251         data=nl(data);
252       }
253     }
254     if(filter(data,"a=StreamCount:integer;",&buf, BUFLEN)) {
255         /* This way negative values are mapped to unfeasibly high
256          * values, and will be discarded afterward
257          */
258         unsigned long tmp = strtoul(buf, NULL, 10);
259         if ( tmp > UINT16_MAX )
260             lprintf("stream count out of bound: %lu\n", tmp);
261         else
262             desc->stream_count = tmp;
263         desc->stream = malloc(sizeof(sdpplin_stream_t*)*desc->stream_count);
264         handled=1;
265         data=nl(data);
266     }
267     if(filter(data,"a=Flags:integer;",&buf, BUFLEN)) {
268       desc->flags=atoi(buf);
269       handled=1;
270       data=nl(data);
271     }
272
273     if(!handled) {
274 #ifdef LOG
275       int len=strchr(data,'\n')-data;
276       memcpy(buf, data, len+1);
277       buf[len]=0;
278       printf("libreal: sdpplin: not handled: '%s'\n", buf);
279 #endif
280       data=nl(data);
281     }
282   }
283
284   free( decoded );
285   free( buf );
286   return desc;
287 }
288
289 void sdpplin_free(sdpplin_t *description) {
290
291   int i;
292
293   if( !description ) return;
294
295   for( i=0; i<description->stream_count; i++ ) {
296     if( description->stream[i] ) {
297       free( description->stream[i]->id );
298       free( description->stream[i]->bandwidth );
299       free( description->stream[i]->range );
300       free( description->stream[i]->length );
301       free( description->stream[i]->rtpmap );
302       free( description->stream[i]->mimetype );
303       free( description->stream[i]->stream_name );
304       free( description->stream[i]->mime_type );
305       free( description->stream[i]->mlti_data );
306       free( description->stream[i]->rmff_flags );
307       free( description->stream[i]->asm_rule_book );
308       free( description->stream[i] );
309     }
310   }
311   if( description->stream_count )
312     free( description->stream );
313
314   free( description->owner );
315   free( description->session_name );
316   free( description->session_info );
317   free( description->uri );
318   free( description->email );
319   free( description->phone );
320   free( description->connection );
321   free( description->bandwidth );
322   free( description->title );
323   free( description->author );
324   free( description->copyright );
325   free( description->keywords );
326   free( description->asm_rule_book );
327   free( description->abstract );
328   free( description->range );
329   free( description );
330 }
331