2016-08-22 06:33:23 +00:00
|
|
|
/* media_params.c
|
2016-08-23 00:53:10 +00:00
|
|
|
* Routines for parsing media type parameters as per RFC 822 and RFC 2045
|
2016-08-22 06:33:23 +00:00
|
|
|
* Copyright 2004, Anders Broman.
|
|
|
|
* Copyright 2004, Olivier Biot.
|
|
|
|
*
|
|
|
|
* Refer to the AUTHORS file or the AUTHORS section in the man page
|
|
|
|
* for contacting the author(s) of this file.
|
|
|
|
*
|
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
2018-02-08 16:59:17 +00:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
2016-08-22 06:33:23 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <glib.h>
|
|
|
|
|
|
|
|
#include <epan/media_params.h>
|
|
|
|
|
2016-08-23 00:53:10 +00:00
|
|
|
static const char *
|
2016-08-23 03:36:24 +00:00
|
|
|
ws_get_next_media_type_parameter(const char *pos, gsize *retnamelen,
|
|
|
|
const char **retvalue, gsize *retvaluelen,
|
2016-08-23 00:53:10 +00:00
|
|
|
const char **nextp)
|
|
|
|
{
|
|
|
|
const char *p, *namep, *valuep;
|
|
|
|
char c;
|
|
|
|
|
|
|
|
p = pos;
|
|
|
|
while ((c = *p) != '\0' && g_ascii_isspace(c))
|
|
|
|
p++; /* Skip white space */
|
|
|
|
|
|
|
|
if (c == '\0') {
|
|
|
|
/* No more parameters left */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
namep = p;
|
|
|
|
|
|
|
|
/* Look for a '\0' (end of string), '=' (end of parameter name,
|
|
|
|
beginning of parameter value), or ';' (end of parameter). */
|
|
|
|
while ((c = *p) != '\0' && c != '=' && c != ';')
|
|
|
|
p++;
|
2016-08-23 03:36:24 +00:00
|
|
|
*retnamelen = (gsize) (p - namep);
|
2016-08-23 00:53:10 +00:00
|
|
|
if (c == '\0') {
|
|
|
|
/* End of string, so end of parameter, no parameter value */
|
2016-08-23 02:28:24 +00:00
|
|
|
if (retvalue != NULL)
|
|
|
|
*retvalue = NULL;
|
|
|
|
if (retvaluelen != NULL)
|
|
|
|
*retvaluelen = 0;
|
2016-08-23 00:53:10 +00:00
|
|
|
*nextp = p;
|
|
|
|
return namep;
|
|
|
|
}
|
|
|
|
if (c == ';') {
|
|
|
|
/* End of parameter, no parameter value */
|
2016-08-23 02:28:24 +00:00
|
|
|
if (retvalue != NULL)
|
|
|
|
*retvalue = NULL;
|
|
|
|
if (retvaluelen != NULL)
|
|
|
|
*retvaluelen = 0;
|
2016-08-23 00:53:10 +00:00
|
|
|
*nextp = p + 1;
|
|
|
|
return namep;
|
|
|
|
}
|
|
|
|
/* The parameter has a value. Skip the '=' */
|
|
|
|
p++;
|
|
|
|
valuep = p;
|
|
|
|
if (retvalue != NULL)
|
|
|
|
*retvalue = valuep;
|
|
|
|
/* Is the value a quoted string? */
|
|
|
|
if (*p == '"') {
|
|
|
|
/* Yes. Skip the opening quote, and scan forward looking for
|
|
|
|
a non-escaped closing quote. */
|
|
|
|
p++;
|
|
|
|
for (;;) {
|
|
|
|
c = *p;
|
|
|
|
if (c == '\0') {
|
|
|
|
/* End-of-string. We're done.
|
|
|
|
(XXX - this is an error.) */
|
|
|
|
if (retvaluelen != NULL) {
|
2016-08-23 03:36:24 +00:00
|
|
|
*retvaluelen = (gsize) (p - valuep);
|
2016-08-23 00:53:10 +00:00
|
|
|
}
|
|
|
|
*nextp = p;
|
|
|
|
return namep;
|
|
|
|
}
|
|
|
|
if (c == '"') {
|
|
|
|
/* Closing quote. Skip it; we're done with
|
|
|
|
the quoted-string. */
|
|
|
|
p++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (c == '\\') {
|
|
|
|
/* Backslash; this escapes the next character
|
|
|
|
(quoted-pair). Skip the backslash, and make
|
|
|
|
sure there *is* a next character. */
|
|
|
|
p++;
|
|
|
|
if (*p == '\0') {
|
|
|
|
/* Nothing left; we're done.
|
|
|
|
(XXX - this is an error.) */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Skip the character we just processed. */
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
/* Now scan forward looking for a '\0' (end of string)
|
|
|
|
or ';' (end of parameter), in case there's any
|
|
|
|
extra cruft after the quoted-string. */
|
|
|
|
while ((c = *p) != '\0' && c != ';')
|
|
|
|
p++;
|
|
|
|
} else {
|
|
|
|
/* No. Just scan forward looking for a '\0' (end
|
|
|
|
of string) or ';' (end of parameter). */
|
|
|
|
while ((c = *p) != '\0' && c != ';')
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (c == '\0') {
|
|
|
|
/* End of string, so end of parameter */
|
|
|
|
if (retvaluelen != NULL) {
|
2016-08-23 03:36:24 +00:00
|
|
|
*retvaluelen = (gsize) (p - valuep);
|
2016-08-23 00:53:10 +00:00
|
|
|
}
|
|
|
|
*nextp = p;
|
|
|
|
return namep;
|
|
|
|
}
|
|
|
|
/* End of parameter; point past the terminating ';' */
|
|
|
|
if (retvaluelen != NULL) {
|
2016-08-23 03:36:24 +00:00
|
|
|
*retvaluelen = (gsize) (p - valuep);
|
2016-08-23 00:53:10 +00:00
|
|
|
}
|
|
|
|
*nextp = p + 1;
|
|
|
|
return namep;
|
|
|
|
}
|
|
|
|
|
2016-08-22 06:33:23 +00:00
|
|
|
char *
|
2018-03-10 22:10:25 +00:00
|
|
|
ws_find_media_type_parameter(wmem_allocator_t *scope, const char *parameters, const char *key)
|
2016-08-22 06:33:23 +00:00
|
|
|
{
|
2016-08-23 00:53:10 +00:00
|
|
|
const char *p, *name, *value;
|
|
|
|
char c;
|
2016-08-23 03:36:24 +00:00
|
|
|
gsize keylen, namelen, valuelen;
|
2016-08-23 00:53:10 +00:00
|
|
|
char *valuestr, *vp;
|
2016-08-22 06:33:23 +00:00
|
|
|
|
2016-08-23 03:36:24 +00:00
|
|
|
if (parameters == NULL || key == NULL)
|
2016-08-22 06:33:23 +00:00
|
|
|
/* we won't be able to find anything */
|
|
|
|
return NULL;
|
|
|
|
|
2016-08-23 03:36:24 +00:00
|
|
|
keylen = (gsize) strlen(key);
|
|
|
|
if (keylen == 0) {
|
|
|
|
/* There's no parameter name to searh for */
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-08-22 06:33:23 +00:00
|
|
|
p = parameters;
|
2016-08-23 03:36:24 +00:00
|
|
|
if (*p == '\0') {
|
|
|
|
/* There are no parameters in which to search */
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-08-22 06:33:23 +00:00
|
|
|
|
2016-08-23 03:36:24 +00:00
|
|
|
do {
|
2016-08-23 00:53:10 +00:00
|
|
|
/* Get the next parameter. */
|
|
|
|
name = ws_get_next_media_type_parameter(p, &namelen, &value,
|
|
|
|
&valuelen, &p);
|
|
|
|
if (name == NULL) {
|
|
|
|
/* No more parameters - not found. */
|
2016-08-22 06:33:23 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-08-23 00:53:10 +00:00
|
|
|
/* Is it the parameter we're looking for? */
|
|
|
|
if (namelen == keylen && g_ascii_strncasecmp(name, key, keylen) == 0) {
|
|
|
|
/* Yes. */
|
|
|
|
break;
|
|
|
|
}
|
2016-08-23 03:36:24 +00:00
|
|
|
} while (*p);
|
2016-08-22 06:33:23 +00:00
|
|
|
|
2016-08-23 02:28:24 +00:00
|
|
|
if (value == NULL) {
|
|
|
|
/* The parameter doesn't have a value. */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-08-23 00:53:10 +00:00
|
|
|
/* We found the parameter with that name; now extract the value. */
|
2018-03-10 22:10:25 +00:00
|
|
|
valuestr = (char *)wmem_alloc(scope, valuelen + 1);
|
2016-08-23 00:53:10 +00:00
|
|
|
vp = valuestr;
|
|
|
|
p = value;
|
|
|
|
/* Is the value a quoted string? */
|
|
|
|
if (*p == '"') {
|
|
|
|
/* Yes. Skip the opening quote, and scan forward looking for
|
|
|
|
a non-escaped closing quote, copying characters. */
|
|
|
|
p++;
|
|
|
|
for (;;) {
|
|
|
|
c = *p;
|
|
|
|
if (c == '\0') {
|
|
|
|
/* End-of-string. We're done.
|
|
|
|
(XXX - this is an error.) */
|
|
|
|
*vp = '\0';
|
|
|
|
return valuestr;
|
|
|
|
}
|
|
|
|
if (c == '"') {
|
|
|
|
/* Closing quote. Skip it; we're done with
|
|
|
|
the quoted-string. */
|
|
|
|
p++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (c == '\\') {
|
|
|
|
/* Backslash; this escapes the next character
|
|
|
|
(quoted-pair). Skip the backslash, and make
|
|
|
|
sure there *is* a next character. */
|
|
|
|
p++;
|
|
|
|
if (*p == '\0') {
|
|
|
|
/* Nothing left; we're done.
|
|
|
|
(XXX - this is an error.) */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Copy the character. */
|
|
|
|
*vp++ = *p++;
|
2016-08-22 06:33:23 +00:00
|
|
|
}
|
|
|
|
} else {
|
2016-08-23 00:53:10 +00:00
|
|
|
/* No. Just scan forward until we see a '\0' (end of
|
|
|
|
string or a non-token character, copying characters. */
|
|
|
|
while ((c = *p) != '\0' && g_ascii_isgraph(c) && c != '(' &&
|
|
|
|
c != ')' && c != '<' && c != '>' && c != '@' &&
|
|
|
|
c != ',' && c != ';' && c != ':' && c != '\\' &&
|
|
|
|
c != '"' && c != '/' && c != '[' && c != ']' &&
|
|
|
|
c != '?' && c != '=' && c != '{' && c != '}') {
|
|
|
|
*vp++ = c;
|
2016-08-22 06:33:23 +00:00
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
2016-08-23 00:53:10 +00:00
|
|
|
*vp = '\0';
|
|
|
|
return valuestr;
|
2016-08-22 06:33:23 +00:00
|
|
|
}
|