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