summaryrefslogtreecommitdiff
path: root/epan/ftypes
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2016-09-18 18:48:50 -0700
committerGuy Harris <guy@alum.mit.edu>2016-09-19 02:51:13 +0000
commitd7fe514fc05e95e3a99fd211768de5abdc3f6486 (patch)
tree68b3e2a24ee11c7dd223089bc9a21ac9ccae302b /epan/ftypes
parent630b64613567c268b2b08966707c81d3ec8661a5 (diff)
downloadwireshark-d7fe514fc05e95e3a99fd211768de5abdc3f6486.tar.gz
Improve support for single-character fields and filter expressions.
Add an FT_CHAR type, which is like FT_UINT8 except that the value is displayed as a C-style character constant. Allow use of C-style character constants in filter expressions; they can be used in comparisons with all integral types, and in "contains" operators. Use that type for some fields that appear (based on the way they're displayed, or on the use of C-style character constants in their value_string tables) to be 1-byte characters rather than 8-bit numbers. Change-Id: I39a9f0dda0bd7f4fa02a9ca8373216206f4d7135 Reviewed-on: https://code.wireshark.org/review/17787 Reviewed-by: Guy Harris <guy@alum.mit.edu>
Diffstat (limited to 'epan/ftypes')
-rw-r--r--epan/ftypes/ftype-integer.c398
-rw-r--r--epan/ftypes/ftypes.h3
2 files changed, 340 insertions, 61 deletions
diff --git a/epan/ftypes/ftype-integer.c b/epan/ftypes/ftype-integer.c
index c7aae0403b..d666560915 100644
--- a/epan/ftypes/ftype-integer.c
+++ b/epan/ftypes/ftype-integer.c
@@ -62,46 +62,195 @@ get_sinteger(fvalue_t *fv)
static gboolean
+parse_charconst(const char *s, unsigned long *valuep, gchar **err_msg)
+{
+ const char *cp;
+ unsigned long value;
+
+ cp = s + 1; /* skip the leading ' */
+ if (*cp == '\\') {
+ /*
+ * Escape.
+ */
+ cp++;
+ switch (*cp) {
+
+ case '\0':
+ if (err_msg != NULL)
+ *err_msg = g_strdup_printf("\"%s\" isn't a valid character constant.", s);
+ return FALSE;
+
+ case 'a':
+ value = '\a';
+ break;
+
+ case 'b':
+ value = '\b';
+ break;
+
+ case 'f':
+ value = '\f';
+ break;
+
+ case 'n':
+ value = '\n';
+ break;
+
+ case 'r':
+ value = '\r';
+ break;
+
+ case 't':
+ value = '\t';
+ break;
+
+ case 'v':
+ value = '\v';
+ break;
+
+ case '\'':
+ value = '\'';
+ break;
+
+ case '\\':
+ value = '\\';
+ break;
+
+ case '"':
+ value = '"';
+ break;
+
+ case 'x':
+ cp++;
+ if (*cp >= '0' && *cp <= '9')
+ value = *cp - '0';
+ else if (*cp >= 'A' && *cp <= 'F')
+ value = 10 + (*cp - 'A');
+ else if (*cp >= 'a' && *cp <= 'f')
+ value = 10 + (*cp - 'a');
+ else {
+ if (err_msg != NULL)
+ *err_msg = g_strdup_printf("\"%s\" isn't a valid character constant.", s);
+ return FALSE;
+ }
+ cp++;
+ if (*cp != '\'') {
+ value <<= 4;
+ if (*cp >= '0' && *cp <= '9')
+ value |= *cp - '0';
+ else if (*cp >= 'A' && *cp <= 'F')
+ value |= 10 + (*cp - 'A');
+ else if (*cp >= 'a' && *cp <= 'f')
+ value |= 10 + (*cp - 'a');
+ else {
+ if (err_msg != NULL)
+ *err_msg = g_strdup_printf("\"%s\" isn't a valid character constant.", s);
+ return FALSE;
+ }
+ }
+ break;
+
+ default:
+ if (*cp >= '0' && *cp <= '7')
+ value = *cp - '0';
+ else {
+ if (err_msg != NULL)
+ *err_msg = g_strdup_printf("\"%s\" isn't a valid character constant.", s);
+ return FALSE;
+ }
+ cp++;
+ if (*cp != '\'') {
+ value <<= 3;
+ if (*cp >= '0' && *cp <= '7')
+ value |= *cp - '0';
+ else {
+ if (err_msg != NULL)
+ *err_msg = g_strdup_printf("\"%s\" isn't a valid character constant.", s);
+ return FALSE;
+ }
+ cp++;
+ if (*cp != '\'') {
+ value <<= 3;
+ if (*cp >= '0' && *cp <= '7')
+ value |= *cp - '0';
+ else {
+ if (err_msg != NULL)
+ *err_msg = g_strdup_printf("\"%s\" isn't a valid character constant.", s);
+ return FALSE;
+ }
+ }
+ }
+ if (value > 0xFF) {
+ if (err_msg != NULL)
+ *err_msg = g_strdup_printf("\"%s\" is too large to be a valid character constant.", s);
+ return FALSE;
+ }
+ }
+ } else {
+ value = *cp;
+ cp++;
+ if (!g_ascii_isprint(value)) {
+ if (err_msg != NULL)
+ *err_msg = g_strdup_printf("Non-printable character '\\x%02lx' in character constant.", value);
+ return FALSE;
+ }
+ }
+ *valuep = value;
+ return TRUE;
+}
+
+static gboolean
uint_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg,
guint32 max)
{
unsigned long value;
char *endptr;
- if (strchr (s, '-') && strtol(s, NULL, 0) < 0) {
+ if (s[0] == '\'') {
/*
- * Probably a negative integer, but will be
- * "converted in the obvious manner" by strtoul().
+ * Represented as a C-style character constant.
*/
- if (err_msg != NULL)
- *err_msg = g_strdup_printf("\"%s\" too small for this field, minimum 0.", s);
- return FALSE;
- }
+ if (!parse_charconst(s, &value, err_msg))
+ return FALSE;
+ } else {
+ /*
+ * Try to parse it as a number.
+ */
+ if (strchr (s, '-') && strtol(s, NULL, 0) < 0) {
+ /*
+ * Probably a negative integer, but will be
+ * "converted in the obvious manner" by strtoul().
+ */
+ if (err_msg != NULL)
+ *err_msg = g_strdup_printf("\"%s\" too small for this field, minimum 0.", s);
+ return FALSE;
+ }
- errno = 0;
- value = strtoul(s, &endptr, 0);
+ errno = 0;
+ value = strtoul(s, &endptr, 0);
- if (errno == EINVAL || endptr == s || *endptr != '\0') {
- /* This isn't a valid number. */
- if (err_msg != NULL)
- *err_msg = g_strdup_printf("\"%s\" is not a valid number.", s);
- return FALSE;
- }
- if (errno == ERANGE) {
- if (err_msg != NULL) {
- if (value == ULONG_MAX) {
- *err_msg = g_strdup_printf("\"%s\" causes an integer overflow.",
- s);
- }
- else {
- /*
- * XXX - can "strtoul()" set errno to
- * ERANGE without returning ULONG_MAX?
- */
- *err_msg = g_strdup_printf("\"%s\" is not an integer.", s);
+ if (errno == EINVAL || endptr == s || *endptr != '\0') {
+ /* This isn't a valid number. */
+ if (err_msg != NULL)
+ *err_msg = g_strdup_printf("\"%s\" is not a valid number.", s);
+ return FALSE;
+ }
+ if (errno == ERANGE) {
+ if (err_msg != NULL) {
+ if (value == ULONG_MAX) {
+ *err_msg = g_strdup_printf("\"%s\" causes an integer overflow.",
+ s);
+ }
+ else {
+ /*
+ * XXX - can "strtoul()" set errno to
+ * ERANGE without returning ULONG_MAX?
+ */
+ *err_msg = g_strdup_printf("\"%s\" is not an integer.", s);
+ }
}
+ return FALSE;
}
- return FALSE;
}
if (value > max) {
@@ -145,42 +294,54 @@ sint_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_
long value;
char *endptr;
- if (!strchr (s, '-') && strtoul(s, NULL, 0) > G_MAXINT32) {
+ if (s[0] == '\'') {
/*
- * Probably a positive integer > G_MAXINT32, but will be
- * "converted in the obvious manner" by strtol().
+ * Represented as a C-style character constant.
*/
- if (err_msg != NULL)
- *err_msg = g_strdup_printf("\"%s\" causes an integer overflow.", s);
- return FALSE;
- }
+ if (!parse_charconst(s, &value, err_msg))
+ return FALSE;
+ } else {
+ /*
+ * Try to parse it as a number.
+ */
+ if (!strchr (s, '-') && strtoul(s, NULL, 0) > G_MAXINT32) {
+ /*
+ * Probably a positive integer > G_MAXINT32, but
+ * will be "converted in the obvious manner" by
+ * strtol().
+ */
+ if (err_msg != NULL)
+ *err_msg = g_strdup_printf("\"%s\" causes an integer overflow.", s);
+ return FALSE;
+ }
- errno = 0;
- value = strtol(s, &endptr, 0);
+ errno = 0;
+ value = strtol(s, &endptr, 0);
- if (errno == EINVAL || endptr == s || *endptr != '\0') {
- /* This isn't a valid number. */
- if (err_msg != NULL)
- *err_msg = g_strdup_printf("\"%s\" is not a valid number.", s);
- return FALSE;
- }
- if (errno == ERANGE) {
- if (err_msg != NULL) {
- if (value == LONG_MAX) {
- *err_msg = g_strdup_printf("\"%s\" causes an integer overflow.", s);
- }
- else if (value == LONG_MIN) {
- *err_msg = g_strdup_printf("\"%s\" causes an integer underflow.", s);
- }
- else {
- /*
- * XXX - can "strtol()" set errno to
- * ERANGE without returning ULONG_MAX?
- */
- *err_msg = g_strdup_printf("\"%s\" is not an integer.", s);
+ if (errno == EINVAL || endptr == s || *endptr != '\0') {
+ /* This isn't a valid number. */
+ if (err_msg != NULL)
+ *err_msg = g_strdup_printf("\"%s\" is not a valid number.", s);
+ return FALSE;
+ }
+ if (errno == ERANGE) {
+ if (err_msg != NULL) {
+ if (value == LONG_MAX) {
+ *err_msg = g_strdup_printf("\"%s\" causes an integer overflow.", s);
+ }
+ else if (value == LONG_MIN) {
+ *err_msg = g_strdup_printf("\"%s\" causes an integer underflow.", s);
+ }
+ else {
+ /*
+ * XXX - can "strtol()" set errno to
+ * ERANGE without returning ULONG_MAX?
+ */
+ *err_msg = g_strdup_printf("\"%s\" is not an integer.", s);
+ }
}
+ return FALSE;
}
- return FALSE;
}
if (value > max) {
@@ -249,6 +410,12 @@ uinteger_repr_len(fvalue_t *fv _U_, ftrepr_t rtype _U_, int field_display _U_)
return 10; /* enough for 2^32-1, in decimal or 0xXXXXXXXX */
}
+static int
+char_repr_len(fvalue_t *fv _U_, ftrepr_t rtype _U_, int field_display _U_)
+{
+ return 7; /* enough for '\OOO' or '\xXX' */
+}
+
static void
uinteger_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, int field_display, char *buf, unsigned int size)
{
@@ -267,6 +434,73 @@ uinteger_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, int field_display, char *buf,
}
}
+static void
+char_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, int field_display, char *buf, unsigned int size _U_)
+{
+ /*
+ * The longest possible strings are "'\OOO'" and "'\xXX'", which
+ * take 7 bytes, including the terminating '\0'.
+ */
+ *buf++ = '\'';
+ if (g_ascii_isprint(fv->value.uinteger)) {
+ /* This perfectly fits into 4 or 5 bytes. */
+ if (fv->value.uinteger == '\\' || fv->value.uinteger == '\'')
+ *buf++ = '\\';
+ *buf++ = (char)fv->value.uinteger;
+ } else {
+ *buf++ = '\\';
+ switch (fv->value.uinteger) {
+
+ case '\0':
+ *buf++ = '0';
+ break;
+
+ case '\a':
+ *buf++ = 'a';
+ break;
+
+ case '\b':
+ *buf++ = 'b';
+ break;
+
+ case '\f':
+ *buf++ = 'f';
+ break;
+
+ case '\n':
+ *buf++ = 'n';
+ break;
+
+ case '\r':
+ *buf++ = 'r';
+ break;
+
+ case '\t':
+ *buf++ = 't';
+ break;
+
+ case '\v':
+ *buf++ = 'v';
+ break;
+
+ default:
+ if (field_display == BASE_HEX) {
+ *buf++ = 'x';
+ buf = guint8_to_hex(buf, fv->value.uinteger);
+ }
+ else
+ {
+ *buf++ = ((fv->value.uinteger >> 6) & 0x7) + '0';
+ *buf++ = ((fv->value.uinteger >> 3) & 0x7) + '0';
+ *buf++ = ((fv->value.uinteger >> 0) & 0x7) + '0';
+ }
+ break;
+ }
+ }
+ *buf++ = '\'';
+ *buf++ = '\0';
+}
+
static gboolean
ipxnet_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg)
{
@@ -780,7 +1014,50 @@ eui64_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_, char *buf
void
ftype_register_integers(void)
{
+ static ftype_t char_type = {
+ FT_CHAR, /* ftype */
+ "FT_CHAR", /* name */
+ "Character, 1 byte", /* pretty name */
+ 1, /* wire_size */
+ int_fvalue_new, /* new_value */
+ NULL, /* free_value */
+ uint8_from_unparsed, /* val_from_unparsed */
+ NULL, /* val_from_string */
+ char_to_repr, /* val_to_string_repr */
+ char_repr_len, /* len_string_repr */
+ NULL, /* set_value_byte_array */
+ NULL, /* set_value_bytes */
+ NULL, /* set_value_guid */
+ NULL, /* set_value_time */
+ NULL, /* set_value_string */
+ NULL, /* set_value_protocol */
+ set_uinteger, /* set_value_uinteger */
+ NULL, /* set_value_sinteger */
+ NULL, /* set_value_uinteger64 */
+ NULL, /* set_value_sinteger64 */
+ NULL, /* set_value_floating */
+
+ NULL, /* get_value */
+ get_uinteger, /* get_value_uinteger */
+ NULL, /* get_value_sinteger */
+ NULL, /* get_value_uinteger64 */
+ NULL, /* get_value_sinteger64 */
+ NULL, /* get_value_floating */
+
+ cmp_eq,
+ cmp_ne,
+ u_cmp_gt,
+ u_cmp_ge,
+ u_cmp_lt,
+ u_cmp_le,
+ cmp_bitwise_and,
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ NULL, /* len */
+ NULL, /* slice */
+ };
static ftype_t uint8_type = {
FT_UINT8, /* ftype */
"FT_UINT8", /* name */
@@ -799,14 +1076,14 @@ ftype_register_integers(void)
NULL, /* set_value_time */
NULL, /* set_value_string */
NULL, /* set_value_protocol */
- set_uinteger, /* set_value_uinteger */
+ set_uinteger, /* set_value_uinteger */
NULL, /* set_value_sinteger */
NULL, /* set_value_uinteger64 */
NULL, /* set_value_sinteger64 */
NULL, /* set_value_floating */
NULL, /* get_value */
- get_uinteger, /* get_value_uinteger */
+ get_uinteger, /* get_value_uinteger */
NULL, /* get_value_sinteger */
NULL, /* get_value_uinteger64 */
NULL, /* get_value_sinteger64 */
@@ -1665,6 +1942,7 @@ ftype_register_integers(void)
NULL,
};
+ ftype_register(FT_CHAR, &char_type);
ftype_register(FT_UINT8, &uint8_type);
ftype_register(FT_UINT16, &uint16_type);
ftype_register(FT_UINT24, &uint24_type);
diff --git a/epan/ftypes/ftypes.h b/epan/ftypes/ftypes.h
index 99153c8fa6..5a44553043 100644
--- a/epan/ftypes/ftypes.h
+++ b/epan/ftypes/ftypes.h
@@ -37,6 +37,7 @@ enum ftenum {
FT_NONE, /* used for text labels with no value */
FT_PROTOCOL,
FT_BOOLEAN, /* TRUE and FALSE come from <glib.h> */
+ FT_CHAR, /* 1-octet character as 0-255 */
FT_UINT8,
FT_UINT16,
FT_UINT24, /* really a UINT32, but displayed as 6 hex-digits if FD_HEX*/
@@ -83,7 +84,7 @@ enum ftenum {
};
#define IS_FT_INT(ft) ((ft)==FT_INT8||(ft)==FT_INT16||(ft)==FT_INT24||(ft)==FT_INT32||(ft)==FT_INT40||(ft)==FT_INT48||(ft)==FT_INT56||(ft)==FT_INT64)
-#define IS_FT_UINT(ft) ((ft)==FT_UINT8||(ft)==FT_UINT16||(ft)==FT_UINT24||(ft)==FT_UINT32||(ft)==FT_UINT40||(ft)==FT_UINT48||(ft)==FT_UINT56||(ft)==FT_UINT64||(ft)==FT_FRAMENUM)
+#define IS_FT_UINT(ft) ((ft)==FT_CHAR||(ft)==FT_UINT8||(ft)==FT_UINT16||(ft)==FT_UINT24||(ft)==FT_UINT32||(ft)==FT_UINT40||(ft)==FT_UINT48||(ft)==FT_UINT56||(ft)==FT_UINT64||(ft)==FT_FRAMENUM)
#define IS_FT_TIME(ft) ((ft)==FT_ABSOLUTE_TIME||(ft)==FT_RELATIVE_TIME)
#define IS_FT_STRING(ft) ((ft)==FT_STRING||(ft)==FT_STRINGZ||(ft)==FT_STRINGZPAD)