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 * SPDX-License-Identifier: GPL-2.0-or-later
14 */
15
16 #include "config.h"
17
18 #include <string.h>
19 #include <glib.h>
20
21 #include <epan/media_params.h>
22
23 static const char *
ws_get_next_media_type_parameter(const char * pos,gsize * retnamelen,const char ** retvalue,gsize * retvaluelen,const char ** nextp)24 ws_get_next_media_type_parameter(const char *pos, gsize *retnamelen,
25 const char **retvalue, gsize *retvaluelen,
26 const char **nextp)
27 {
28 const char *p, *namep, *valuep;
29 char c;
30
31 p = pos;
32 while ((c = *p) != '\0' && g_ascii_isspace(c))
33 p++; /* Skip white space */
34
35 if (c == '\0') {
36 /* No more parameters left */
37 return NULL;
38 }
39
40 namep = p;
41
42 /* Look for a '\0' (end of string), '=' (end of parameter name,
43 beginning of parameter value), or ';' (end of parameter). */
44 while ((c = *p) != '\0' && c != '=' && c != ';')
45 p++;
46 *retnamelen = (gsize) (p - namep);
47 if (c == '\0') {
48 /* End of string, so end of parameter, no parameter value */
49 if (retvalue != NULL)
50 *retvalue = NULL;
51 if (retvaluelen != NULL)
52 *retvaluelen = 0;
53 *nextp = p;
54 return namep;
55 }
56 if (c == ';') {
57 /* End of parameter, no parameter value */
58 if (retvalue != NULL)
59 *retvalue = NULL;
60 if (retvaluelen != NULL)
61 *retvaluelen = 0;
62 *nextp = p + 1;
63 return namep;
64 }
65 /* The parameter has a value. Skip the '=' */
66 p++;
67 valuep = p;
68 if (retvalue != NULL)
69 *retvalue = valuep;
70 /* Is the value a quoted string? */
71 if (*p == '"') {
72 /* Yes. Skip the opening quote, and scan forward looking for
73 a non-escaped closing quote. */
74 p++;
75 for (;;) {
76 c = *p;
77 if (c == '\0') {
78 /* End-of-string. We're done.
79 (XXX - this is an error.) */
80 if (retvaluelen != NULL) {
81 *retvaluelen = (gsize) (p - valuep);
82 }
83 *nextp = p;
84 return namep;
85 }
86 if (c == '"') {
87 /* Closing quote. Skip it; we're done with
88 the quoted-string. */
89 p++;
90 break;
91 }
92 if (c == '\\') {
93 /* Backslash; this escapes the next character
94 (quoted-pair). Skip the backslash, and make
95 sure there *is* a next character. */
96 p++;
97 if (*p == '\0') {
98 /* Nothing left; we're done.
99 (XXX - this is an error.) */
100 break;
101 }
102 }
103 /* Skip the character we just processed. */
104 p++;
105 }
106 /* Now scan forward looking for a '\0' (end of string)
107 or ';' (end of parameter), in case there's any
108 extra cruft after the quoted-string. */
109 while ((c = *p) != '\0' && c != ';')
110 p++;
111 } else {
112 /* No. Just scan forward looking for a '\0' (end
113 of string) or ';' (end of parameter). */
114 while ((c = *p) != '\0' && c != ';')
115 p++;
116 }
117 if (c == '\0') {
118 /* End of string, so end of parameter */
119 if (retvaluelen != NULL) {
120 *retvaluelen = (gsize) (p - valuep);
121 }
122 *nextp = p;
123 return namep;
124 }
125 /* End of parameter; point past the terminating ';' */
126 if (retvaluelen != NULL) {
127 *retvaluelen = (gsize) (p - valuep);
128 }
129 *nextp = p + 1;
130 return namep;
131 }
132
133 char *
ws_find_media_type_parameter(wmem_allocator_t * scope,const char * parameters,const char * key)134 ws_find_media_type_parameter(wmem_allocator_t *scope, const char *parameters, const char *key)
135 {
136 const char *p, *name, *value;
137 char c;
138 gsize keylen, namelen, valuelen;
139 char *valuestr, *vp;
140
141 if (parameters == NULL || key == NULL)
142 /* we won't be able to find anything */
143 return NULL;
144
145 keylen = (gsize) strlen(key);
146 if (keylen == 0) {
147 /* There's no parameter name to searh for */
148 return NULL;
149 }
150 p = parameters;
151 if (*p == '\0') {
152 /* There are no parameters in which to search */
153 return NULL;
154 }
155
156 do {
157 /* Get the next parameter. */
158 name = ws_get_next_media_type_parameter(p, &namelen, &value,
159 &valuelen, &p);
160 if (name == NULL) {
161 /* No more parameters - not found. */
162 return NULL;
163 }
164
165 /* Is it the parameter we're looking for? */
166 if (namelen == keylen && g_ascii_strncasecmp(name, key, keylen) == 0) {
167 /* Yes. */
168 break;
169 }
170 } while (*p);
171
172 if (value == NULL) {
173 /* The parameter doesn't have a value. */
174 return NULL;
175 }
176
177 /* We found the parameter with that name; now extract the value. */
178 valuestr = (char *)wmem_alloc(scope, valuelen + 1);
179 vp = valuestr;
180 p = value;
181 /* Is the value a quoted string? */
182 if (*p == '"') {
183 /* Yes. Skip the opening quote, and scan forward looking for
184 a non-escaped closing quote, copying characters. */
185 p++;
186 for (;;) {
187 c = *p;
188 if (c == '\0') {
189 /* End-of-string. We're done.
190 (XXX - this is an error.) */
191 *vp = '\0';
192 return valuestr;
193 }
194 if (c == '"') {
195 /* Closing quote. Skip it; we're done with
196 the quoted-string. */
197 p++;
198 break;
199 }
200 if (c == '\\') {
201 /* Backslash; this escapes the next character
202 (quoted-pair). Skip the backslash, and make
203 sure there *is* a next character. */
204 p++;
205 if (*p == '\0') {
206 /* Nothing left; we're done.
207 (XXX - this is an error.) */
208 break;
209 }
210 }
211 /* Copy the character. */
212 *vp++ = *p++;
213 }
214 } else {
215 /* No. Just scan forward until we see a '\0' (end of
216 string or a non-token character, copying characters. */
217 while ((c = *p) != '\0' && g_ascii_isgraph(c) && c != '(' &&
218 c != ')' && c != '<' && c != '>' && c != '@' &&
219 c != ',' && c != ';' && c != ':' && c != '\\' &&
220 c != '"' && c != '/' && c != '[' && c != ']' &&
221 c != '?' && c != '=' && c != '{' && c != '}') {
222 *vp++ = c;
223 p++;
224 }
225 }
226 *vp = '\0';
227 return valuestr;
228 }
229