Snort: speed up parsing of options by avoiding g_snprintf()
[metze/wireshark/wip.git] / epan / media_params.c
1 /* media_params.c
2  * Routines for parsing media type parameters as per RFC 822 and RFC 2045
3  * Copyright 2004, Anders Broman.
4  * Copyright 2004, Olivier Biot.
5  *
6  * Refer to the AUTHORS file or the AUTHORS section in the man page
7  * for contacting the author(s) of this file.
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27
28 #include "config.h"
29
30 #include <string.h>
31
32 #include <glib.h>
33
34 #include <epan/media_params.h>
35
36 static const char *
37 ws_get_next_media_type_parameter(const char *pos, gsize *retnamelen,
38                                  const char **retvalue, gsize *retvaluelen,
39                                  const char **nextp)
40 {
41     const char *p, *namep, *valuep;
42     char c;
43
44     p = pos;
45     while ((c = *p) != '\0' && g_ascii_isspace(c))
46         p++; /* Skip white space */
47
48     if (c == '\0') {
49         /* No more parameters left */
50         return NULL;
51     }
52
53     namep = p;
54
55     /* Look for a '\0' (end of string), '=' (end of parameter name,
56        beginning of parameter value), or ';' (end of parameter). */
57     while ((c = *p) != '\0' && c != '=' && c != ';')
58         p++;
59     *retnamelen = (gsize) (p - namep);
60     if (c == '\0') {
61         /* End of string, so end of parameter, no parameter value */
62         if (retvalue != NULL)
63             *retvalue = NULL;
64         if (retvaluelen != NULL)
65             *retvaluelen = 0;
66         *nextp = p;
67         return namep;
68     }
69     if (c == ';') {
70         /* End of parameter, no parameter value */
71         if (retvalue != NULL)
72             *retvalue = NULL;
73         if (retvaluelen != NULL)
74             *retvaluelen = 0;
75         *nextp = p + 1;
76         return namep;
77     }
78     /* The parameter has a value.  Skip the '=' */
79     p++;
80     valuep = p;
81     if (retvalue != NULL)
82         *retvalue = valuep;
83     /* Is the value a quoted string? */
84     if (*p == '"') {
85         /* Yes. Skip the opening quote, and scan forward looking for
86            a non-escaped closing quote. */
87         p++;
88         for (;;) {
89             c = *p;
90             if (c == '\0') {
91                 /* End-of-string.  We're done.
92                    (XXX - this is an error.) */
93                 if (retvaluelen != NULL) {
94                     *retvaluelen = (gsize) (p - valuep);
95                 }
96                 *nextp = p;
97                 return namep;
98             }
99             if (c == '"') {
100                 /* Closing quote.  Skip it; we're done with
101                    the quoted-string. */
102                 p++;
103                 break;
104             }
105             if (c == '\\') {
106                 /* Backslash; this escapes the next character
107                    (quoted-pair). Skip the backslash, and make
108                    sure there *is* a next character. */
109                 p++;
110                 if (*p == '\0') {
111                     /* Nothing left; we're done.
112                        (XXX - this is an error.) */
113                     break;
114                 }
115             }
116             /* Skip the character we just processed. */
117             p++;
118         }
119         /* Now scan forward looking for a '\0' (end of string)
120            or ';' (end of parameter), in case there's any
121             extra cruft after the quoted-string. */
122         while ((c = *p) != '\0' && c != ';')
123            p++;
124     } else {
125         /* No.  Just scan forward looking for a '\0' (end
126            of string) or ';' (end of parameter). */
127         while ((c = *p) != '\0' && c != ';')
128             p++;
129     }
130     if (c == '\0') {
131         /* End of string, so end of parameter */
132         if (retvaluelen != NULL) {
133             *retvaluelen = (gsize) (p - valuep);
134         }
135         *nextp = p;
136         return namep;
137     }
138     /* End of parameter; point past the terminating ';' */
139     if (retvaluelen != NULL) {
140         *retvaluelen = (gsize) (p - valuep);
141     }
142     *nextp = p + 1;
143     return namep;
144 }
145
146 char *
147 ws_find_media_type_parameter(const char *parameters, const char *key)
148 {
149     const char *p, *name, *value;
150     char c;
151     gsize keylen, namelen, valuelen;
152     char *valuestr, *vp;
153
154     if (parameters == NULL || key == NULL)
155         /* we won't be able to find anything */
156         return NULL;
157
158     keylen = (gsize) strlen(key);
159     if (keylen == 0) {
160         /* There's no parameter name to searh for */
161         return NULL;
162     }
163     p = parameters;
164     if (*p == '\0') {
165         /* There are no parameters in which to search */
166         return NULL;
167     }
168
169     do {
170         /* Get the next parameter. */
171         name = ws_get_next_media_type_parameter(p, &namelen, &value,
172                                                 &valuelen, &p);
173         if (name == NULL) {
174             /* No more parameters - not found. */
175             return NULL;
176         }
177
178         /* Is it the parameter we're looking for? */
179         if (namelen == keylen && g_ascii_strncasecmp(name, key, keylen) == 0) {
180             /* Yes. */
181             break;
182         }
183     } while (*p);
184
185     if (value == NULL) {
186         /* The parameter doesn't have a value. */
187         return NULL;
188     }
189
190     /* We found the parameter with that name; now extract the value. */
191     valuestr = (char *)g_malloc(valuelen + 1);
192     vp = valuestr;
193     p = value;
194     /* Is the value a quoted string? */
195     if (*p == '"') {
196         /* Yes. Skip the opening quote, and scan forward looking for
197            a non-escaped closing quote, copying characters. */
198         p++;
199         for (;;) {
200             c = *p;
201             if (c == '\0') {
202                 /* End-of-string.  We're done.
203                    (XXX - this is an error.) */
204                 *vp = '\0';
205                 return valuestr;
206             }
207             if (c == '"') {
208                 /* Closing quote.  Skip it; we're done with
209                    the quoted-string. */
210                 p++;
211                 break;
212             }
213             if (c == '\\') {
214                 /* Backslash; this escapes the next character
215                    (quoted-pair). Skip the backslash, and make
216                    sure there *is* a next character. */
217                 p++;
218                 if (*p == '\0') {
219                     /* Nothing left; we're done.
220                        (XXX - this is an error.) */
221                     break;
222                 }
223             }
224             /* Copy the character. */
225             *vp++ = *p++;
226         }
227     } else {
228         /* No.  Just scan forward until we see a '\0' (end of
229            string or a non-token character, copying characters. */
230         while ((c = *p) != '\0' && g_ascii_isgraph(c) && c != '(' &&
231                 c != ')' && c != '<' && c != '>' && c != '@' &&
232                 c != ',' && c != ';' && c != ':' && c != '\\' &&
233                 c != '"' && c != '/' && c != '[' && c != ']' &&
234                 c != '?' && c != '=' && c != '{' && c != '}') {
235             *vp++ = c;
236             p++;
237         }
238     }
239     *vp = '\0';
240     return valuestr;
241 }