]> git.sesse.net Git - vlc/blob - modules/access/rtsp/real_sdpplin.c
Update LGPL license blurb, choosing v2.1+.
[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
189   desc = calloc( 1, sizeof(sdpplin_t) );
190   if( !desc )
191     return NULL;
192
193   buf = malloc( BUFLEN );
194   if( !buf )
195   {
196     free( desc );
197     return NULL;
198   }
199
200   decoded = malloc( BUFLEN );
201   if( !decoded )
202   {
203     free( buf );
204     free( desc );
205     return NULL;
206   }
207   desc->stream = NULL;
208
209   while (data && *data) {
210     handled=0;
211
212     if (filter(data, "m=", &buf, BUFLEN)) {
213         if ( !desc->stream ) {
214             fprintf(stderr, "sdpplin.c: stream identifier found before stream count, skipping.");
215             continue;
216         }
217         stream=sdpplin_parse_stream(&data);
218         lprintf("got data for stream id %u\n", stream->stream_id);
219         if ( stream->stream_id >= desc->stream_count )
220             lprintf("stream id %u is greater than stream count %u\n", stream->stream_id, desc->stream_count);
221         else
222             desc->stream[stream->stream_id]=stream;
223         continue;
224     }
225     if(filter(data,"a=Title:buffer;",&buf, BUFLEN)) {
226       desc->title=vlc_b64_decode(buf);
227       if(desc->title) {
228         handled=1;
229         data=nl(data);
230       }
231     }
232     if(filter(data,"a=Author:buffer;",&buf, BUFLEN)) {
233       desc->author=vlc_b64_decode(buf);
234       if(desc->author) {
235         handled=1;
236         data=nl(data);
237       }
238     }
239     if(filter(data,"a=Copyright:buffer;",&buf, BUFLEN)) {
240       desc->copyright=vlc_b64_decode(buf);
241       if(desc->copyright) {
242         handled=1;
243         data=nl(data);
244       }
245     }
246     if(filter(data,"a=Abstract:buffer;",&buf, BUFLEN)) {
247       desc->abstract=vlc_b64_decode(buf);
248       if(desc->abstract) {
249         handled=1;
250         data=nl(data);
251       }
252     }
253     if(filter(data,"a=StreamCount:integer;",&buf, BUFLEN)) {
254         /* This way negative values are mapped to unfeasibly high
255          * values, and will be discarded afterward
256          */
257         unsigned long tmp = strtoul(buf, NULL, 10);
258         if ( tmp > UINT16_MAX )
259             lprintf("stream count out of bound: %lu\n", tmp);
260         else
261             desc->stream_count = tmp;
262         desc->stream = malloc(sizeof(sdpplin_stream_t*)*desc->stream_count);
263         handled=1;
264         data=nl(data);
265     }
266     if(filter(data,"a=Flags:integer;",&buf, BUFLEN)) {
267       desc->flags=atoi(buf);
268       handled=1;
269       data=nl(data);
270     }
271
272     if(!handled) {
273 #ifdef LOG
274       int len=strchr(data,'\n')-data;
275       memcpy(buf, data, len+1);
276       buf[len]=0;
277       printf("libreal: sdpplin: not handled: '%s'\n", buf);
278 #endif
279       data=nl(data);
280     }
281   }
282
283   free( decoded );
284   free( buf );
285   return desc;
286 }
287
288 void sdpplin_free(sdpplin_t *description) {
289
290   int i;
291
292   if( !description ) return;
293
294   for( i=0; i<description->stream_count; i++ ) {
295     if( description->stream[i] ) {
296       free( description->stream[i]->id );
297       free( description->stream[i]->bandwidth );
298       free( description->stream[i]->range );
299       free( description->stream[i]->length );
300       free( description->stream[i]->rtpmap );
301       free( description->stream[i]->mimetype );
302       free( description->stream[i]->stream_name );
303       free( description->stream[i]->mime_type );
304       free( description->stream[i]->mlti_data );
305       free( description->stream[i]->rmff_flags );
306       free( description->stream[i]->asm_rule_book );
307       free( description->stream[i] );
308     }
309   }
310   if( description->stream_count )
311     free( description->stream );
312
313   free( description->owner );
314   free( description->session_name );
315   free( description->session_info );
316   free( description->uri );
317   free( description->email );
318   free( description->phone );
319   free( description->connection );
320   free( description->bandwidth );
321   free( description->title );
322   free( description->author );
323   free( description->copyright );
324   free( description->keywords );
325   free( description->asm_rule_book );
326   free( description->abstract );
327   free( description->range );
328   free( description );
329 }
330