summaryrefslogtreecommitdiffstats
path: root/epan/ftypes
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/ftypes
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/ftypes')
-rw-r--r--epan/ftypes/.editorconfig49
-rw-r--r--epan/ftypes/CMakeLists.txt85
-rw-r--r--epan/ftypes/ftype-bytes.c1013
-rw-r--r--epan/ftypes/ftype-double.c272
-rw-r--r--epan/ftypes/ftype-guid.c174
-rw-r--r--epan/ftypes/ftype-ieee-11073-float.c1058
-rw-r--r--epan/ftypes/ftype-integer.c2209
-rw-r--r--epan/ftypes/ftype-ipv4.c246
-rw-r--r--epan/ftypes/ftype-ipv6.c275
-rw-r--r--epan/ftypes/ftype-none.c84
-rw-r--r--epan/ftypes/ftype-protocol.c440
-rw-r--r--epan/ftypes/ftype-string.c439
-rw-r--r--epan/ftypes/ftype-time.c670
-rw-r--r--epan/ftypes/ftypes-int.h205
-rw-r--r--epan/ftypes/ftypes.c1249
-rw-r--r--epan/ftypes/ftypes.h539
16 files changed, 9007 insertions, 0 deletions
diff --git a/epan/ftypes/.editorconfig b/epan/ftypes/.editorconfig
new file mode 100644
index 0000000..3072778
--- /dev/null
+++ b/epan/ftypes/.editorconfig
@@ -0,0 +1,49 @@
+#
+# Editor configuration
+#
+# https://editorconfig.org/
+#
+
+[ftype-bytes.[ch]]
+indent_style = tab
+indent_size = tab
+
+[ftype-double.[ch]]
+indent_style = tab
+indent_size = tab
+
+[ftype-integer.[ch]]
+indent_style = tab
+indent_size = tab
+
+[ftype-ipv4.[ch]]
+indent_style = tab
+indent_size = tab
+
+[ftype-ipv6.[ch]]
+indent_style = tab
+indent_size = tab
+
+[ftype-none.[ch]]
+indent_style = tab
+indent_size = tab
+
+[ftype-string.[ch]]
+indent_style = tab
+indent_size = tab
+
+[ftype-time.[ch]]
+indent_style = tab
+indent_size = tab
+
+[ftype-protocol.[ch]]
+indent_style = tab
+indent_size = tab
+
+[ftypes.[ch]]
+indent_style = tab
+indent_size = tab
+
+[ftypes-int.h]
+indent_style = tab
+indent_size = tab
diff --git a/epan/ftypes/CMakeLists.txt b/epan/ftypes/CMakeLists.txt
new file mode 100644
index 0000000..b63b55e
--- /dev/null
+++ b/epan/ftypes/CMakeLists.txt
@@ -0,0 +1,85 @@
+# CMakeLists.txt
+#
+# Wireshark - Network traffic analyzer
+# By Gerald Combs <gerald@wireshark.org>
+# Copyright 1998 Gerald Combs
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+
+set(FTYPE_PUBLIC_HEADERS
+ ftypes.h
+)
+
+set(FTYPE_HEADER_FILES
+ ${FTYPE_PUBLIC_HEADERS}
+ ftypes-int.h
+)
+
+set(FTYPE_FILES
+ ftypes.c
+ ftype-bytes.c
+ ftype-double.c
+ ftype-ieee-11073-float.c
+ ftype-integer.c
+ ftype-ipv4.c
+ ftype-ipv6.c
+ ftype-guid.c
+ ftype-none.c
+ ftype-protocol.c
+ ftype-string.c
+ ftype-time.c
+)
+source_group(ftype FILES ${FTYPE_FILES})
+
+set_source_files_properties(
+ ${FTYPE_FILES}
+ PROPERTIES
+ COMPILE_FLAGS "${WERROR_COMMON_FLAGS}"
+)
+
+add_library(ftypes OBJECT
+ #Included so that Visual Studio can properly put header files in solution
+ ${FTYPE_HEADER_FILES}
+
+ ${FTYPE_FILES}
+)
+
+target_include_directories(ftypes
+ PRIVATE
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/epan
+)
+
+set_target_properties(ftypes PROPERTIES
+ FOLDER "Libs/epan/ftypes"
+ COMPILE_DEFINITIONS "WS_BUILD_DLL"
+)
+
+install(FILES ${FTYPE_PUBLIC_HEADERS}
+ DESTINATION "${PROJECT_INSTALL_INCLUDEDIR}/epan/ftypes"
+ COMPONENT "Development"
+ EXCLUDE_FROM_ALL
+)
+
+CHECKAPI(
+ NAME
+ ftypes
+ SWITCHES
+ SOURCES
+ ${FTYPE_FILES}
+)
+
+#
+# Editor modelines - https://www.wireshark.org/tools/modelines.html
+#
+# Local variables:
+# c-basic-offset: 8
+# tab-width: 8
+# indent-tabs-mode: t
+# End:
+#
+# vi: set shiftwidth=8 tabstop=8 noexpandtab:
+# :indentSize=8:tabSize=8:noTabs=false:
+#
diff --git a/epan/ftypes/ftype-bytes.c b/epan/ftypes/ftype-bytes.c
new file mode 100644
index 0000000..39a58a3
--- /dev/null
+++ b/epan/ftypes/ftype-bytes.c
@@ -0,0 +1,1013 @@
+/*
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <ftypes-int.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <epan/addr_resolv.h>
+#include <epan/strutil.h>
+#include <epan/oids.h>
+#include <epan/osi-utils.h>
+#include <epan/to_str.h>
+
+static void
+bytes_fvalue_new(fvalue_t *fv)
+{
+ fv->value.bytes = NULL;
+}
+
+static void
+bytes_fvalue_copy(fvalue_t *dst, const fvalue_t *src)
+{
+ dst->value.bytes = g_bytes_ref(src->value.bytes);
+}
+
+static void
+bytes_fvalue_free(fvalue_t *fv)
+{
+ if (fv->value.bytes) {
+ g_bytes_unref(fv->value.bytes);
+ fv->value.bytes = NULL;
+ }
+}
+
+
+static void
+bytes_fvalue_set(fvalue_t *fv, GBytes *value)
+{
+ /* Free up the old value, if we have one */
+ bytes_fvalue_free(fv);
+
+ fv->value.bytes = g_bytes_ref(value);
+}
+
+static GBytes *
+bytes_fvalue_get(fvalue_t *fv)
+{
+ return g_bytes_ref(fv->value.bytes);
+}
+
+static char *
+oid_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ return oid_encoded2string(scope, g_bytes_get_data(fv->value.bytes, NULL), (unsigned)g_bytes_get_size(fv->value.bytes));
+}
+
+static char *
+rel_oid_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ return rel_oid_encoded2string(scope, g_bytes_get_data(fv->value.bytes, NULL), (unsigned)g_bytes_get_size(fv->value.bytes));
+}
+
+static char *
+system_id_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ return print_system_id(scope, g_bytes_get_data(fv->value.bytes, NULL), (unsigned)g_bytes_get_size(fv->value.bytes));
+}
+
+char *
+bytes_to_dfilter_repr(wmem_allocator_t *scope,
+ const uint8_t *src, size_t src_size)
+{
+ char *buf;
+ size_t max_char_size;
+ char *buf_ptr;
+
+ /* Include space for extra punct and '\0'. */
+ max_char_size = src_size * 3 + 1;
+
+ buf = wmem_alloc(scope, max_char_size);
+ buf_ptr = bytes_to_hexstr_punct(buf, src, src_size, ':');
+ if (src_size == 1)
+ *buf_ptr++ = ':';
+ *buf_ptr = '\0';
+ return buf;
+}
+
+static char *
+bytes_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display)
+{
+ char separator;
+ const uint8_t *bytes;
+ size_t bytes_size;
+
+ bytes = g_bytes_get_data(fv->value.bytes, &bytes_size);
+
+ if (rtype == FTREPR_DFILTER) {
+ if (bytes_size == 0) {
+ /* An empty byte array in a display filter is represented as "" */
+ return wmem_strdup(scope, "\"\"");
+ }
+ return bytes_to_dfilter_repr(scope, bytes, bytes_size);
+ }
+
+ switch(FIELD_DISPLAY(field_display))
+ {
+ case SEP_DOT:
+ separator = '.';
+ break;
+ case SEP_DASH:
+ separator = '-';
+ break;
+ case SEP_SPACE:
+ case SEP_COLON:
+ case BASE_NONE:
+ default:
+ separator = ':';
+ break;
+ }
+
+ if (bytes_size) {
+ return bytes_to_str_punct_maxlen(scope, bytes, bytes_size, separator, 0);
+ }
+
+ return wmem_strdup(scope, "");
+}
+
+static bool
+bytes_from_string(fvalue_t *fv, const char *s, size_t len, char **err_msg _U_)
+{
+ GByteArray *bytes;
+
+ bytes = g_byte_array_new();
+
+ if (len == 0)
+ len = strlen(s);
+
+ g_byte_array_append(bytes, (const uint8_t *)s, (unsigned)len);
+
+ /* Free up the old value, if we have one */
+ bytes_fvalue_free(fv);
+ fv->value.bytes = g_byte_array_free_to_bytes(bytes);
+
+ return true;
+}
+
+GByteArray *
+byte_array_from_literal(const char *s, char **err_msg)
+{
+ GByteArray *bytes;
+ bool res;
+
+ /* Skip leading colon if any. */
+ if (*s == ':')
+ s++;
+
+ /*
+ * Special case where the byte string is specified using a one byte
+ * hex literal. We can't allow this for byte strings that are longer
+ * than one byte, because then we'd have to know which endianness the
+ * byte string should be in.
+ */
+ if (strlen(s) == 4 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
+ s = s + 2;
+
+ bytes = g_byte_array_new();
+
+ /* Hack: If we have a binary number 0bXXXXXXXX use that as a byte array
+ * of length one. This is ambiguous because it can also be
+ * parsed (without separators) as a byte array of length 5:
+ * 0bXXXXXXXX = 0b:XX:XX:XX:XX = { 0x0b, 0xXX, 0xXX, 0xXX, 0xXX } */
+ if (strlen(s) == 10 && s[0] == '0' && (s[1] == 'b' || s[1] == 'B') &&
+ (s[2] == '0' || s[2] == '1')) {
+ errno = 0;
+ char *endptr;
+ long number = strtol(s + 2, &endptr, 2);
+ if (errno == 0 && *endptr == '\0' && number >= 0x0 && number <= 0xff) {
+ uint8_t byte = (uint8_t)number;
+ g_byte_array_append(bytes, &byte, 1);
+ return bytes;
+ }
+ }
+
+ res = hex_str_to_bytes(s, bytes, false);
+
+ if (!res) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid byte string.", s);
+ g_byte_array_free(bytes, true);
+ return NULL;
+ }
+
+ return bytes;
+}
+
+static bool
+bytes_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ GByteArray *bytes;
+
+ bytes = byte_array_from_literal(s, err_msg);
+ if (bytes == NULL)
+ return false;
+
+ /* Free up the old value, if we have one */
+ bytes_fvalue_free(fv);
+
+ fv->value.bytes = g_byte_array_free_to_bytes(bytes);
+
+ return true;
+}
+
+GByteArray *
+byte_array_from_charconst(unsigned long num, char **err_msg)
+{
+ if (num > UINT8_MAX) {
+ if (err_msg) {
+ *err_msg = ws_strdup_printf("%lu is too large for a byte value", num);
+ }
+ return NULL;
+ }
+
+ GByteArray *bytes = g_byte_array_new();
+ uint8_t one_byte = (uint8_t)num;
+ g_byte_array_append(bytes, &one_byte, 1);
+ return bytes;
+}
+
+static bool
+bytes_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg)
+{
+ GByteArray *bytes;
+
+ bytes = byte_array_from_charconst(num, err_msg);
+ if (bytes == NULL)
+ return false;
+
+ /* Free up the old value, if we have one */
+ bytes_fvalue_free(fv);
+
+ fv->value.bytes = g_byte_array_free_to_bytes(bytes);
+
+ return true;
+}
+
+static bool
+ax25_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ /*
+ * Don't request an error message if bytes_from_literal fails;
+ * if it does, we'll report an error specific to this address
+ * type.
+ */
+ if (bytes_from_literal(fv, s, true, NULL)) {
+ if (g_bytes_get_size(fv->value.bytes) > FT_AX25_ADDR_LEN) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("\"%s\" contains too many bytes to be a valid AX.25 address.",
+ s);
+ }
+ return false;
+ }
+ else if (g_bytes_get_size(fv->value.bytes) < FT_AX25_ADDR_LEN && !allow_partial_value) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("\"%s\" contains too few bytes to be a valid AX.25 address.",
+ s);
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ /*
+ * XXX - what needs to be done here is something such as:
+ *
+ * Look for a "-" in the string.
+ *
+ * If we find it, make sure that there are 1-6 alphanumeric
+ * ASCII characters before it, and that there are 2 decimal
+ * digits after it, from 00 to 15; if we don't find it, make
+ * sure that there are 1-6 alphanumeric ASCII characters
+ * in the string.
+ *
+ * If so, make the first 6 octets of the address the ASCII
+ * characters, with lower-case letters mapped to upper-case
+ * letters, shifted left by 1 bit, padded to 6 octets with
+ * spaces, also shifted left by 1 bit, and, if we found a
+ * "-", convert what's after it to a number and make the 7th
+ * octet the number, shifted left by 1 bit, otherwise make the
+ * 7th octet zero.
+ *
+ * We should also change all the comparison functions for
+ * AX.25 addresses check the upper 7 bits of all but the last
+ * octet of the address, ignoring the "end of address" bit,
+ * and compare only the 4 bits above the low-order bit for
+ * the last octet, ignoring the "end of address" bit and
+ * various reserved bits and bits used for other purposes.
+ *
+ * See section 3.12 "Address-Field Encoding" of the AX.25
+ * spec and
+ *
+ * http://www.itu.int/ITU-R/terrestrial/docs/fixedmobile/fxm-art19-sec3.pdf
+ */
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid AX.25 address.", s);
+ return false;
+}
+
+static bool
+vines_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ /*
+ * Don't request an error message if bytes_from_literal fails;
+ * if it does, we'll report an error specific to this address
+ * type.
+ */
+ if (bytes_from_literal(fv, s, true, NULL)) {
+ if (g_bytes_get_size(fv->value.bytes) > FT_VINES_ADDR_LEN) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("\"%s\" contains too many bytes to be a valid Vines address.",
+ s);
+ }
+ return false;
+ }
+ else if (g_bytes_get_size(fv->value.bytes) < FT_VINES_ADDR_LEN && !allow_partial_value) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("\"%s\" contains too few bytes to be a valid Vines address.",
+ s);
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ /* XXX - need better validation of Vines address */
+
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid Vines address.", s);
+ return false;
+}
+
+static bool
+ether_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ /*
+ * Don't request an error message if bytes_from_literal fails;
+ * if it does, we'll report an error specific to this address
+ * type.
+ */
+ if (bytes_from_literal(fv, s, true, NULL)) {
+ if (g_bytes_get_size(fv->value.bytes) > FT_ETHER_LEN) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("\"%s\" contains too many bytes to be a valid Ethernet address.",
+ s);
+ }
+ return false;
+ }
+ else if (g_bytes_get_size(fv->value.bytes) < FT_ETHER_LEN && !allow_partial_value) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("\"%s\" contains too few bytes to be a valid Ethernet address.",
+ s);
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ /* XXX - Try resolving as an Ethernet host name and parse that? */
+
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid Ethernet address.", s);
+ return false;
+}
+
+static bool
+oid_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ GByteArray *bytes;
+ bool res;
+
+
+#if 0
+ /*
+ * Don't log a message if this fails; we'll try looking it
+ * up as an OID if it does, and if that fails,
+ * we'll log a message.
+ */
+ /* do not try it as '.' is handled as valid separator for hexbytes :( */
+ if (bytes_from_literal(fv, s, true, NULL)) {
+ return true;
+ }
+#endif
+
+ bytes = g_byte_array_new();
+ res = oid_str_to_bytes(s, bytes);
+ if (!res) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid OBJECT IDENTIFIER.", s);
+ g_byte_array_free(bytes, true);
+ return false;
+ }
+
+ /* Free up the old value, if we have one */
+ bytes_fvalue_free(fv);
+ fv->value.bytes = g_byte_array_free_to_bytes(bytes);
+
+ return true;
+}
+
+static bool
+rel_oid_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ GByteArray *bytes;
+ bool res;
+
+ bytes = g_byte_array_new();
+ res = rel_oid_str_to_bytes(s, bytes, false);
+ if (!res) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid RELATIVE-OID.", s);
+ g_byte_array_free(bytes, true);
+ return false;
+ }
+
+ /* Free up the old value, if we have one */
+ bytes_fvalue_free(fv);
+ fv->value.bytes = g_byte_array_free_to_bytes(bytes);
+
+ return true;
+}
+
+static bool
+system_id_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ /*
+ * Don't request an error message if bytes_from_literal fails;
+ * if it does, we'll report an error specific to this address
+ * type.
+ */
+ if (bytes_from_literal(fv, s, true, NULL)) {
+ if (g_bytes_get_size(fv->value.bytes) > MAX_SYSTEMID_LEN) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("\"%s\" contains too many bytes to be a valid OSI System-ID.",
+ s);
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ /* XXX - need better validation of OSI System-ID address */
+
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid OSI System-ID.", s);
+ return false;
+}
+
+static bool
+fcwwn_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ /*
+ * Don't request an error message if bytes_from_literal fails;
+ * if it does, we'll report an error specific to this address
+ * type.
+ */
+ if (bytes_from_literal(fv, s, true, NULL)) {
+ if (g_bytes_get_size(fv->value.bytes) > FT_FCWWN_LEN) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("\"%s\" contains too many bytes to be a valid FCWWN.",
+ s);
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ /* XXX - need better validation of FCWWN address */
+
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid FCWWN.", s);
+ return false;
+}
+
+static unsigned
+len(fvalue_t *fv)
+{
+ return (unsigned)g_bytes_get_size(fv->value.bytes);
+}
+
+static void
+slice(fvalue_t *fv, GByteArray *bytes, unsigned offset, unsigned length)
+{
+ const uint8_t *data = (const uint8_t *)g_bytes_get_data(fv->value.bytes, NULL) + offset;
+ g_byte_array_append(bytes, data, length);
+}
+
+static enum ft_result
+cmp_order(const fvalue_t *fv_a, const fvalue_t *fv_b, int *cmp)
+{
+ *cmp = g_bytes_compare(fv_a->value.bytes, fv_b->value.bytes);
+ return FT_OK;
+}
+
+static enum ft_result
+bytes_bitwise_and(fvalue_t *fv_dst, const fvalue_t *fv_a, const fvalue_t *fv_b, char **err_ptr _U_)
+{
+ GByteArray *dst;
+ const uint8_t *p_a, *p_b;
+ size_t size_a, size_b;
+
+ p_a = g_bytes_get_data(fv_a->value.bytes, &size_a);
+ p_b = g_bytes_get_data(fv_b->value.bytes, &size_b);
+
+ size_t len = MIN(size_a, size_b);
+ if (len == 0) {
+ fv_dst->value.bytes = g_bytes_new(NULL, 0);
+ return FT_OK;
+ }
+
+ dst = g_byte_array_sized_new((unsigned)len);
+ for (size_t i = 0; i < len; i++) {
+ uint8_t byte = p_a[i] & p_b[i];
+ g_byte_array_append(dst, &byte, 1);
+ }
+ fv_dst->value.bytes = g_byte_array_free_to_bytes(dst);
+ return FT_OK;
+}
+
+static enum ft_result
+cmp_contains(const fvalue_t *fv_a, const fvalue_t *fv_b, bool *contains)
+{
+ const void *data_a, *data_b;
+ size_t size_a, size_b;
+
+ data_a = g_bytes_get_data(fv_a->value.bytes, &size_a);
+ data_b = g_bytes_get_data(fv_b->value.bytes, &size_b);
+
+ if (ws_memmem(data_a, size_a, data_b, size_b)) {
+ *contains = true;
+ }
+ else {
+ *contains = false;
+ }
+
+ return FT_OK;
+}
+
+static enum ft_result
+cmp_matches(const fvalue_t *fv, const ws_regex_t *regex, bool *matches)
+{
+ const void *data;
+ size_t data_size;
+
+ data = g_bytes_get_data(fv->value.bytes, &data_size);
+
+ *matches = ws_regex_matches_length(regex, data, data_size);
+ return FT_OK;
+}
+
+static unsigned
+bytes_hash(const fvalue_t *fv)
+{
+ return g_bytes_hash(fv->value.bytes);
+}
+
+static bool
+bytes_is_zero(const fvalue_t *fv)
+{
+ const uint8_t *data;
+ size_t data_size;
+
+ data = g_bytes_get_data(fv->value.bytes, &data_size);
+
+ if (data_size == 0)
+ return true;
+
+ for (size_t i = 0; i < data_size; i++) {
+ if (data[i] != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void
+ftype_register_bytes(void)
+{
+
+ static ftype_t bytes_type = {
+ FT_BYTES, /* ftype */
+ "FT_BYTES", /* name */
+ "Byte sequence", /* pretty_name */
+ 0, /* wire_size */
+ bytes_fvalue_new, /* new_value */
+ bytes_fvalue_copy, /* copy_value */
+ bytes_fvalue_free, /* free_value */
+ bytes_from_literal, /* val_from_literal */
+ bytes_from_string, /* val_from_string */
+ bytes_from_charconst, /* val_from_charconst */
+ bytes_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_bytes = bytes_fvalue_set }, /* union set_value */
+ { .get_value_bytes = bytes_fvalue_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains,
+ cmp_matches,
+
+ bytes_hash, /* hash */
+ bytes_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ bytes_bitwise_and, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ static ftype_t uint_bytes_type = {
+ FT_UINT_BYTES, /* ftype */
+ "FT_UINT_BYTES", /* name */
+ "Byte sequence", /* pretty_name */
+ 0, /* wire_size */
+ bytes_fvalue_new, /* new_value */
+ bytes_fvalue_copy, /* copy_value */
+ bytes_fvalue_free, /* free_value */
+ bytes_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ bytes_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_bytes = bytes_fvalue_set }, /* union set_value */
+ { .get_value_bytes = bytes_fvalue_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains,
+ NULL, /* cmp_matches */
+
+ bytes_hash, /* hash */
+ bytes_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ bytes_bitwise_and, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ static ftype_t ax25_type = {
+ FT_AX25, /* ftype */
+ "FT_AX25", /* name */
+ "AX.25 address", /* pretty_name */
+ FT_AX25_ADDR_LEN, /* wire_size */
+ bytes_fvalue_new, /* new_value */
+ bytes_fvalue_copy, /* copy_value */
+ bytes_fvalue_free, /* free_value */
+ ax25_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ bytes_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_bytes = bytes_fvalue_set }, /* union set_value */
+ { .get_value_bytes = bytes_fvalue_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains,
+ cmp_matches,
+
+ bytes_hash, /* hash */
+ bytes_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ bytes_bitwise_and, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ static ftype_t vines_type = {
+ FT_VINES, /* ftype */
+ "FT_VINES", /* name */
+ "VINES address", /* pretty_name */
+ FT_VINES_ADDR_LEN, /* wire_size */
+ bytes_fvalue_new, /* new_value */
+ bytes_fvalue_copy, /* copy_value */
+ bytes_fvalue_free, /* free_value */
+ vines_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ bytes_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_bytes = bytes_fvalue_set }, /* union set_value */
+ { .get_value_bytes = bytes_fvalue_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains,
+ cmp_matches,
+
+ bytes_hash, /* hash */
+ bytes_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ bytes_bitwise_and, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ static ftype_t ether_type = {
+ FT_ETHER, /* ftype */
+ "FT_ETHER", /* name */
+ "Ethernet or other MAC address",/* pretty_name */
+ FT_ETHER_LEN, /* wire_size */
+ bytes_fvalue_new, /* new_value */
+ bytes_fvalue_copy, /* copy_value */
+ bytes_fvalue_free, /* free_value */
+ ether_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ bytes_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_bytes = bytes_fvalue_set }, /* union set_value */
+ { .get_value_bytes = bytes_fvalue_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains,
+ cmp_matches,
+
+ bytes_hash, /* hash */
+ bytes_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ bytes_bitwise_and, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ static ftype_t oid_type = {
+ FT_OID, /* ftype */
+ "FT_OID", /* name */
+ "ASN.1 object identifier", /* pretty_name */
+ 0, /* wire_size */
+ bytes_fvalue_new, /* new_value */
+ bytes_fvalue_copy, /* copy_value */
+ bytes_fvalue_free, /* free_value */
+ oid_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ oid_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_bytes = bytes_fvalue_set }, /* union set_value */
+ { .get_value_bytes = bytes_fvalue_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains,
+ NULL, /* cmp_matches */
+
+ bytes_hash, /* hash */
+ bytes_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ bytes_bitwise_and, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ static ftype_t rel_oid_type = {
+ FT_REL_OID, /* ftype */
+ "FT_REL_OID", /* name */
+ "ASN.1 relative object identifier", /* pretty_name */
+ 0, /* wire_size */
+ bytes_fvalue_new, /* new_value */
+ bytes_fvalue_copy, /* copy_value */
+ bytes_fvalue_free, /* free_value */
+ rel_oid_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ rel_oid_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_bytes = bytes_fvalue_set }, /* union set_value */
+ { .get_value_bytes = bytes_fvalue_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains,
+ NULL, /* cmp_matches */
+
+ bytes_hash, /* hash */
+ bytes_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ bytes_bitwise_and, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ static ftype_t system_id_type = {
+ FT_SYSTEM_ID, /* ftype */
+ "FT_SYSTEM_ID", /* name */
+ "OSI System-ID", /* pretty_name */
+ 0, /* wire_size */
+ bytes_fvalue_new, /* new_value */
+ bytes_fvalue_copy, /* copy_value */
+ bytes_fvalue_free, /* free_value */
+ system_id_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ system_id_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_bytes = bytes_fvalue_set }, /* union set_value */
+ { .get_value_bytes = bytes_fvalue_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains,
+ NULL, /* cmp_matches */
+
+ bytes_hash, /* hash */
+ bytes_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ bytes_bitwise_and, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ static ftype_t fcwwn_type = {
+ FT_FCWWN, /* ftype */
+ "FT_FCWWN", /* name */
+ "Fibre Channel WWN", /* pretty_name */
+ FT_FCWWN_LEN, /* wire_size */
+ bytes_fvalue_new, /* new_value */
+ bytes_fvalue_copy, /* copy_value */
+ bytes_fvalue_free, /* free_value */
+ fcwwn_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ bytes_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_bytes = bytes_fvalue_set }, /* union set_value */
+ { .get_value_bytes = bytes_fvalue_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains,
+ cmp_matches,
+
+ bytes_hash, /* hash */
+ bytes_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ bytes_bitwise_and, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ ftype_register(FT_BYTES, &bytes_type);
+ ftype_register(FT_UINT_BYTES, &uint_bytes_type);
+ ftype_register(FT_AX25, &ax25_type);
+ ftype_register(FT_VINES, &vines_type);
+ ftype_register(FT_ETHER, &ether_type);
+ ftype_register(FT_OID, &oid_type);
+ ftype_register(FT_REL_OID, &rel_oid_type);
+ ftype_register(FT_SYSTEM_ID, &system_id_type);
+ ftype_register(FT_FCWWN, &fcwwn_type);
+}
+
+void
+ftype_register_pseudofields_bytes(int proto)
+{
+ static int hf_ft_bytes;
+ static int hf_ft_uint_bytes;
+ static int hf_ft_ax25;
+ static int hf_ft_vines;
+ static int hf_ft_ether;
+ static int hf_ft_oid;
+ static int hf_ft_rel_oid;
+ static int hf_ft_system_id;
+
+ static hf_register_info hf_ftypes[] = {
+ { &hf_ft_bytes,
+ { "FT_BYTES", "_ws.ftypes.bytes",
+ FT_BYTES, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_uint_bytes,
+ { "FT_UINT_BYTES", "_ws.ftypes.uint_bytes",
+ FT_UINT_BYTES, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_ax25,
+ { "FT_AX25", "_ws.ftypes.ax25",
+ FT_AX25, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_vines,
+ { "FT_VINES", "_ws.ftypes.vines",
+ FT_VINES, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_ether,
+ { "FT_ETHER", "_ws.ftypes.ether",
+ FT_ETHER, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_oid,
+ { "FT_OID", "_ws.ftypes.oid",
+ FT_OID, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_rel_oid,
+ { "FT_REL_OID", "_ws.ftypes.rel_oid",
+ FT_REL_OID, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_system_id,
+ { "FT_SYSTEM_ID", "_ws.ftypes.system_id",
+ FT_SYSTEM_ID, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ };
+
+ proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes));
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/epan/ftypes/ftype-double.c b/epan/ftypes/ftype-double.c
new file mode 100644
index 0000000..4bec884
--- /dev/null
+++ b/epan/ftypes/ftype-double.c
@@ -0,0 +1,272 @@
+/*
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <ftypes-int.h>
+#include <math.h>
+#include <errno.h>
+#include <float.h>
+
+#include "strutil.h"
+
+static void
+double_fvalue_new(fvalue_t *fv)
+{
+ fv->value.floating = 0.0;
+}
+
+static void
+double_fvalue_set_floating(fvalue_t *fv, double value)
+{
+ fv->value.floating = value;
+}
+
+static double
+value_get_floating(fvalue_t *fv)
+{
+ return fv->value.floating;
+}
+
+static bool
+val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ char *endptr = NULL;
+
+ fv->value.floating = g_ascii_strtod(s, &endptr);
+
+ if (endptr == s || *endptr != '\0') {
+ /* This isn't a valid number. */
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid floating-point number.", s);
+ return false;
+ }
+ if (errno == ERANGE) {
+ if (fv->value.floating == 0) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" causes floating-point underflow.", s);
+ }
+ else if (fv->value.floating == HUGE_VAL) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" causes floating-point overflow.", s);
+ }
+ else {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid floating-point number.",
+ s);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+static char *
+float_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display _U_)
+{
+ char *buf = wmem_alloc(scope, G_ASCII_DTOSTR_BUF_SIZE);
+ if (rtype == FTREPR_DFILTER)
+ g_ascii_dtostr(buf, G_ASCII_DTOSTR_BUF_SIZE, fv->value.floating);
+ else
+ g_ascii_formatd(buf, G_ASCII_DTOSTR_BUF_SIZE, "%." G_STRINGIFY(FLT_DIG) "g", fv->value.floating);
+ return buf;
+}
+
+static char *
+double_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display _U_)
+{
+ char *buf = wmem_alloc(scope, G_ASCII_DTOSTR_BUF_SIZE);
+ if (rtype == FTREPR_DFILTER)
+ g_ascii_dtostr(buf, G_ASCII_DTOSTR_BUF_SIZE, fv->value.floating);
+ else
+ g_ascii_formatd(buf, G_ASCII_DTOSTR_BUF_SIZE, "%." G_STRINGIFY(DBL_DIG) "g", fv->value.floating);
+ return buf;
+}
+
+static enum ft_result
+val_unary_minus(fvalue_t * dst, const fvalue_t *src, char **err_ptr _U_)
+{
+ dst->value.floating = -src->value.floating;
+ return FT_OK;
+}
+
+static enum ft_result
+val_add(fvalue_t * dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_)
+{
+ dst->value.floating = a->value.floating + b->value.floating;
+ return FT_OK;
+}
+
+static enum ft_result
+val_subtract(fvalue_t * dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_)
+{
+ dst->value.floating = a->value.floating - b->value.floating;
+ return FT_OK;
+}
+
+static enum ft_result
+val_multiply(fvalue_t * dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_)
+{
+ dst->value.floating = a->value.floating * b->value.floating;
+ return FT_OK;
+}
+
+static enum ft_result
+val_divide(fvalue_t * dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_)
+{
+ dst->value.floating = a->value.floating / b->value.floating;
+ return FT_OK;
+}
+
+static enum ft_result
+cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp)
+{
+ if (a->value.floating < b->value.floating)
+ *cmp = -1;
+ else if (a->value.floating > b->value.floating)
+ *cmp = 1;
+ else
+ *cmp = 0;
+ return FT_OK;
+}
+
+static bool
+val_is_zero(const fvalue_t *fv_a)
+{
+ return fv_a->value.floating == 0;
+}
+
+static bool
+val_is_negative(const fvalue_t *fv_a)
+{
+ return fv_a->value.floating < 0;
+}
+
+static unsigned
+val_hash(const fvalue_t *fv)
+{
+ return g_double_hash(&fv->value.floating);
+}
+
+void
+ftype_register_double(void)
+{
+
+ static ftype_t float_type = {
+ FT_FLOAT, /* ftype */
+ "FT_FLOAT", /* name */
+ "Floating point (single-precision)", /* pretty_name */
+ 0, /* wire_size */
+ double_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ val_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ float_val_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_floating = double_fvalue_set_floating }, /* union set_value */
+ { .get_value_floating = value_get_floating }, /* union get_value */
+
+ cmp_order,
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ val_hash, /* hash */
+ val_is_zero, /* is_zero */
+ val_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ NULL, /* bitwise_and */
+ val_unary_minus, /* unary_minus */
+ val_add, /* add */
+ val_subtract, /* subtract */
+ val_multiply, /* multiply */
+ val_divide, /* divide */
+ NULL, /* modulo */
+ };
+
+ static ftype_t double_type = {
+ FT_DOUBLE, /* ftype */
+ "FT_DOUBLE", /* name */
+ "Floating point (double-precision)", /* pretty_name */
+ 0, /* wire_size */
+ double_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ val_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ double_val_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_floating = double_fvalue_set_floating }, /* union set_value */
+ { .get_value_floating = value_get_floating }, /* union get_value */
+
+ cmp_order,
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ val_hash, /* hash */
+ val_is_zero, /* is_zero */
+ val_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ NULL, /* bitwise_and */
+ val_unary_minus, /* unary_minus */
+ val_add, /* add */
+ val_subtract, /* subtract */
+ val_multiply, /* multiply */
+ val_divide, /* divide */
+ NULL, /* modulo */
+ };
+
+ ftype_register(FT_FLOAT, &float_type);
+ ftype_register(FT_DOUBLE, &double_type);
+}
+
+void
+ftype_register_pseudofields_double(int proto)
+{
+ static int hf_ft_float;
+ static int hf_ft_double;
+
+ static hf_register_info hf_ftypes[] = {
+ { &hf_ft_float,
+ { "FT_FLOAT", "_ws.ftypes.float",
+ FT_FLOAT, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_double,
+ { "FT_DOUBLE", "_ws.ftypes.double",
+ FT_DOUBLE, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ };
+
+ proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes));
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/epan/ftypes/ftype-guid.c b/epan/ftypes/ftype-guid.c
new file mode 100644
index 0000000..311a017
--- /dev/null
+++ b/epan/ftypes/ftype-guid.c
@@ -0,0 +1,174 @@
+/*
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <ftypes-int.h>
+#include <epan/guid-utils.h>
+#include <epan/to_str.h>
+
+static void
+guid_fvalue_set_guid(fvalue_t *fv, const e_guid_t *value)
+{
+ fv->value.guid = *value;
+}
+
+static const e_guid_t *
+value_get(fvalue_t *fv)
+{
+ return &(fv->value.guid);
+}
+
+static bool
+get_guid(const char *s, e_guid_t *guid)
+{
+ size_t i, n;
+ const char *p;
+ char digits[3];
+ static const char fmt[] = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX";
+ const size_t fmtchars = sizeof(fmt) - 1;
+
+ n = strnlen(s, fmtchars);
+ if (n != fmtchars)
+ return false;
+ for (i=0; i<n; i++) {
+ if (fmt[i] == 'X') {
+ if (!g_ascii_isxdigit(s[i]))
+ return false;
+ } else {
+ if (s[i] != fmt[i])
+ return false;
+ }
+ }
+
+ p = s;
+ guid->data1 = (uint32_t)strtoul(p, NULL, 16);
+ p += 9;
+ guid->data2 = (uint16_t)strtoul(p, NULL, 16);
+ p += 5;
+ guid->data3 = (uint16_t)strtoul(p, NULL, 16);
+ p += 5;
+ for (i=0; i < sizeof(guid->data4); i++) {
+ if (*p == '-') p++;
+ digits[0] = *(p++);
+ digits[1] = *(p++);
+ digits[2] = '\0';
+ guid->data4[i] = (uint8_t)strtoul(digits, NULL, 16);
+ }
+ return true;
+}
+
+static bool
+guid_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ e_guid_t guid;
+
+ if (!get_guid(s, &guid)) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid GUID.", s);
+ return false;
+ }
+
+ fv->value.guid = guid;
+ return true;
+}
+
+static char *
+guid_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ return guid_to_str(scope, &fv->value.guid);
+}
+
+static enum ft_result
+cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp)
+{
+ *cmp = memcmp(&a->value.guid, &b->value.guid, sizeof(e_guid_t));
+ return FT_OK;
+}
+
+static unsigned
+value_hash(const fvalue_t *fv)
+{
+ return guid_hash(&fv->value.guid);
+}
+
+void
+ftype_register_guid(void)
+{
+
+ static ftype_t guid_type = {
+ FT_GUID, /* ftype */
+ "FT_GUID", /* name */
+ "Globally Unique Identifier", /* pretty_name */
+ GUID_LEN, /* wire_size */
+ NULL, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ guid_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ guid_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_guid = guid_fvalue_set_guid }, /* union set_value */
+ { .get_value_guid = value_get }, /* union get_value */
+
+ cmp_order,
+ NULL,
+ NULL, /* cmp_matches */
+
+ value_hash, /* hash */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ ftype_register(FT_GUID, &guid_type);
+}
+
+void
+ftype_register_pseudofields_guid(int proto)
+{
+ static int hf_ft_guid;
+
+ static hf_register_info hf_ftypes[] = {
+ { &hf_ft_guid,
+ { "FT_GUID", "_ws.ftypes.guid",
+ FT_GUID, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ };
+
+ proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes));
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/epan/ftypes/ftype-ieee-11073-float.c b/epan/ftypes/ftype-ieee-11073-float.c
new file mode 100644
index 0000000..bb4d628
--- /dev/null
+++ b/epan/ftypes/ftype-ieee-11073-float.c
@@ -0,0 +1,1058 @@
+/* FLOATs as specified by ISO/IEEE Std. 11073-20601-2014
+ *
+ * Personal Health Devices Transcoding White Paper v1.5
+ * https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=272346
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <ftypes-int.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+
+#include "strutil.h"
+
+#define DOUBLE_REPR_LENGTH 27
+
+#define SFLOAT_VALUE_INFINITY_PLUS 0x07FE
+#define SFLOAT_VALUE_NAN 0x07FF
+#define SFLOAT_VALUE_NRES 0x0800
+#define SFLOAT_VALUE_RFU 0x0801
+#define SFLOAT_VALUE_INFINITY_MINUS 0x0802
+
+#define FLOAT_VALUE_INFINITY_PLUS 0x007FFFFE
+#define FLOAT_VALUE_NAN 0x007FFFFF
+#define FLOAT_VALUE_NRES 0x00800000
+#define FLOAT_VALUE_RFU 0x00800001
+#define FLOAT_VALUE_INFINITY_MINUS 0x00800002
+
+static void
+sfloat_ieee_11073_fvalue_new(fvalue_t *fv)
+{
+ fv->value.sfloat_ieee_11073 = 0x0000;
+}
+
+static bool
+sfloat_ieee_11073_val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg _U_)
+{
+ const char *i_char = s;
+ char c;
+ uint8_t mantissa_sign = 0;
+ uint32_t mantissa = 0;
+ int8_t exponent = 0;
+ bool fraction_mode = false;
+ const uint16_t mantissa_max = 0x07FF;
+
+ c = *i_char;
+
+ if (c== '\0')
+ return false;
+
+ if (c == '.')
+ return false;
+
+ if (c == '-' && s[1] == '.')
+ return false;
+
+ if (c == '-' && (s[1] == 'I' || s[1] == 'i')) {
+ if (!g_ascii_strcasecmp(s, "-INFINITY")) {
+ fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_INFINITY_MINUS;
+ return true;
+ }
+
+ return false;
+ } else if (c == 'R' || c == 'r') {
+ if (!g_ascii_strcasecmp(s, "RFU")) {
+ fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_RFU;
+ return true;
+ }
+
+ return false;
+ } else if (c == 'N' || c == 'n') {
+ if (!g_ascii_strcasecmp(s, "NRes")) {
+ fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_NRES;
+ return true;
+ }
+
+ if (!g_ascii_strcasecmp(s, "NaN")) {
+ fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_NAN;
+ return true;
+ }
+
+ return false;
+ } else if (c == '+') {
+ if (!g_ascii_strcasecmp(s, "+INFINITY")) {
+ fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_INFINITY_PLUS;
+ return true;
+ }
+
+ return false;
+ }
+
+ if (c == '-') {
+ if (s[1] == '\0')
+ return false;
+
+ mantissa_sign = 1;
+ i_char += 1;
+ }
+
+ while (*i_char == '0') {
+ i_char += 1;
+ }
+
+ c = *i_char;
+
+ do {
+ if (c == '0') {
+ if (mantissa * 10 > (uint32_t) mantissa_max + mantissa_sign) {
+ exponent += 1;
+ if (exponent > 7)
+ return false;
+ } else {
+ mantissa *= 10;
+ }
+ } else if (c == '1') {
+ mantissa *= 10;
+ mantissa += 1;
+ } else if (c == '2') {
+ mantissa *= 10;
+ mantissa += 2;
+ } else if (c == '3') {
+ mantissa *= 10;
+ mantissa += 3;
+ } else if (c == '4') {
+ mantissa *= 10;
+ mantissa += 4;
+ } else if (c == '5') {
+ mantissa *= 10;
+ mantissa += 5;
+ } else if (c == '6') {
+ mantissa *= 10;
+ mantissa += 6;
+ } else if (c == '7') {
+ mantissa *= 10;
+ mantissa += 7;
+ } else if (c == '8') {
+ mantissa *= 10;
+ mantissa += 8;
+ } else if (c == '9') {
+ mantissa *= 10;
+ mantissa += 9;
+ } else if (c == '.') {
+ if (fraction_mode)
+ return false;
+ fraction_mode = true;
+ i_char += 1;
+
+ while (*i_char == '0') {
+ i_char += 1;
+ if (mantissa * 10 <= (uint32_t) mantissa_max + mantissa_sign) {
+ mantissa *= 10;
+ if (exponent > -8 - 4) /* -8 is min exponent; 4 is mantissa size */
+ exponent -= 1;
+ }
+ }
+
+ i_char -= 1;
+ } else if (c != '\0') {
+ /* NOTE: Maybe 5e-10, 5e3 notation should be also supported */
+ return false;
+ }
+
+ if (mantissa > (uint32_t) mantissa_max + mantissa_sign)
+ return false;
+
+ if (c != '.' && fraction_mode)
+ exponent -= 1;
+
+ i_char += 1;
+ } while ((c = *i_char));
+
+ if (mantissa_sign) {
+ mantissa = ~(mantissa - 1);
+ mantissa &= 0x0FFF;
+ }
+
+ /* Transform to normal form */
+
+ if (mantissa == 0)
+ exponent = 0;
+
+ while (mantissa > 0 && mantissa % 10 == 0 && exponent < 7) {
+ mantissa /= 10;
+ exponent += 1;
+ }
+
+ if (exponent < -8)
+ return false;
+
+ fv->value.sfloat_ieee_11073 = ((exponent & 0x0F) << 12) | mantissa;
+
+ return true;
+}
+
+static char *
+sfloat_ieee_11073_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ int8_t exponent;
+ uint16_t mantissa;
+ uint16_t mantissa_sign;
+ uint32_t offset = 0;
+ char mantissa_buf[5];
+ char *mantissa_str;
+ uint8_t mantissa_digits;
+
+ /* Predefinied: +INFINITY, -INFINITY, RFU, NRes, NaN */
+ if (fv->value.sfloat_ieee_11073 >= 0x07FE && fv->value.sfloat_ieee_11073 <= 0x0802) {
+ char *s = NULL;
+
+ switch (fv->value.sfloat_ieee_11073) {
+ case SFLOAT_VALUE_INFINITY_PLUS:
+ s = "+INFINITY";
+ break;
+ case SFLOAT_VALUE_NAN:
+ s = "NaN";
+ break;
+ case SFLOAT_VALUE_NRES:
+ s = "NRes";
+ break;
+ case SFLOAT_VALUE_RFU:
+ s = "RFU";
+ break;
+ case SFLOAT_VALUE_INFINITY_MINUS:
+ s = "-INFINITY";
+ break;
+ }
+ return wmem_strdup(scope, s);
+ }
+
+ /* Longest Signed Float Number: -0.00002048 (11 characters without NULL) */
+ /* Longest Signed Float Number -0.00000001 */
+ /* Longest Signed Nonfloat Number: -20480000000 (12 characters without NULL) */
+ char buf[13];
+
+ exponent = fv->value.sfloat_ieee_11073 >> 12;
+ if (exponent & 0x8)
+ exponent |= 0xF0; /* It is signed (4bits), so make it signed in int8_t */
+ mantissa = fv->value.sfloat_ieee_11073 & 0x07FF;
+ mantissa_sign = (fv->value.sfloat_ieee_11073 & 0x0800);
+ if (mantissa_sign)
+ mantissa = -((int16_t)mantissa | 0xF800);
+
+ if (mantissa == 0) {
+ return wmem_strdup(scope, "0");
+ }
+
+ if (mantissa_sign) {
+ buf[0] = '-';
+ offset += 1;
+ }
+
+ mantissa_digits = snprintf(mantissa_buf, sizeof(mantissa_buf), "%"PRIu16, mantissa);
+ mantissa_str = mantissa_buf;
+
+ if (exponent == 0) {
+ memcpy(buf + offset, mantissa_str, mantissa_digits);
+ offset += mantissa_digits;
+ } else if (exponent > 0) {
+ memcpy(buf + offset, mantissa_str, mantissa_digits);
+ offset += mantissa_digits;
+
+ memset(buf + offset, '0', exponent);
+ offset += exponent;
+ } else /* if (exponent < 0)*/ {
+ if (-exponent < mantissa_digits) {
+ memcpy(buf + offset, mantissa_str, mantissa_digits + exponent);
+ offset += mantissa_digits + exponent;
+
+ buf[offset] = '.';
+ offset += 1;
+
+ memcpy(buf + offset, mantissa_str + mantissa_digits + exponent, -exponent);
+ offset += -exponent;
+ } else {
+ buf[offset] = '0';
+ offset += 1;
+
+ buf[offset] = '.';
+ offset += 1;
+
+ if (-exponent - mantissa_digits > 0) {
+ memset(buf + offset, '0', -exponent - mantissa_digits);
+ offset += -exponent - mantissa_digits;
+ }
+
+ memcpy(buf + offset, mantissa_str, mantissa_digits);
+ offset += mantissa_digits;
+ }
+ }
+
+ buf[offset] = '\0';
+ return wmem_strdup(scope, buf);
+}
+
+static void
+sfloat_ieee_11073_value_set(fvalue_t *fv, uint32_t value)
+{
+ fv->value.sfloat_ieee_11073 = (uint16_t) value;
+}
+
+static uint32_t
+sfloat_ieee_11073_value_get(fvalue_t *fv)
+{
+ return (uint32_t) fv->value.sfloat_ieee_11073;
+}
+
+static uint16_t sfloat_to_normal_form(uint16_t value)
+{
+ int8_t exponent;
+ uint16_t mantissa;
+ uint8_t mantissa_sign;
+
+ if (value >= 0x07FE && value <= 0x0802) /* Save special values */
+ return value;
+
+ mantissa = value & 0x07FF;
+ if (value & 0x0800) {
+ mantissa = -((int16_t)mantissa | 0xF800);
+ mantissa_sign = 1;
+ } else {
+ mantissa_sign = 0;
+ }
+
+ exponent = value >> 12;
+
+ if (exponent & 0x08) {
+ exponent |= 0xF0;
+ }
+
+ while ((!(mantissa % 10)) && mantissa != 0) {
+ mantissa /= 10;
+
+ if (exponent == 7)
+ break;
+
+ exponent += 1;
+ }
+
+ return ((((exponent & 0x80) ? 0x8 : 0x0 ) | (exponent & 0x7)) << 12) | (mantissa_sign << 11) | mantissa;
+}
+
+static bool
+sfloat_ieee_11073_cmp_eq(const fvalue_t *a, const fvalue_t *b)
+{
+ return sfloat_to_normal_form(a->value.sfloat_ieee_11073) == sfloat_to_normal_form(b->value.sfloat_ieee_11073);
+}
+
+static bool
+sfloat_ieee_11073_cmp_lt(const fvalue_t *a, const fvalue_t *b)
+{
+ uint16_t a_norm;
+ uint16_t b_norm;
+ int16_t a_norm_mantissa;
+ int16_t b_norm_mantissa;
+ int8_t a_norm_exponent;
+ int8_t b_norm_exponent;
+
+ a_norm = sfloat_to_normal_form(a->value.sfloat_ieee_11073);
+ b_norm = sfloat_to_normal_form(b->value.sfloat_ieee_11073);
+
+ if (a_norm == b_norm)
+ return false;
+
+ switch (a_norm) {
+ case SFLOAT_VALUE_NAN:
+ case SFLOAT_VALUE_NRES:
+ case SFLOAT_VALUE_RFU:
+ case SFLOAT_VALUE_INFINITY_PLUS:
+ return false;
+ case SFLOAT_VALUE_INFINITY_MINUS:
+ switch (b_norm) {
+ case SFLOAT_VALUE_NAN:
+ case SFLOAT_VALUE_NRES:
+ case SFLOAT_VALUE_RFU:
+ case SFLOAT_VALUE_INFINITY_MINUS: /* Dead, informative case */
+ return false;
+ case SFLOAT_VALUE_INFINITY_PLUS:
+ default:
+ return true;
+ }
+ }
+
+ a_norm_mantissa = a_norm & 0x0FFF;
+ b_norm_mantissa = b_norm & 0x0FFF;
+ if (a_norm & 0x0800)
+ a_norm_mantissa |= 0xFFFFF000;
+
+ if (b_norm & 0x0800)
+ b_norm_mantissa |= 0xFFFFF000;
+
+ a_norm_exponent = a_norm >> 12;
+ b_norm_exponent = b_norm >> 12;
+
+ if (a_norm_exponent & 0x08) {
+ a_norm_exponent |= 0xF0;
+ }
+
+ if (b_norm_exponent & 0x08) {
+ b_norm_exponent |= 0xF0;
+ }
+
+ if (a_norm_mantissa == b_norm_mantissa && a_norm_exponent < b_norm_exponent)
+ return true;
+
+ if (a_norm_exponent == b_norm_exponent && a_norm_mantissa < b_norm_mantissa)
+ return true;
+
+ if (a_norm_exponent < b_norm_exponent) {
+ uint8_t exponent_difference;
+
+ exponent_difference = b_norm_exponent - a_norm_exponent;
+
+ if (exponent_difference >= 4)
+ return true;
+
+ while (exponent_difference--) {
+ b_norm_mantissa *= 10;
+ }
+ } else {
+ uint8_t exponent_difference;
+
+ exponent_difference = a_norm_exponent - b_norm_exponent;
+
+ if (exponent_difference >= 4)
+ return false;
+
+ while (exponent_difference--) {
+ a_norm_mantissa *= 10;
+ }
+ }
+
+ if (a_norm_mantissa < b_norm_mantissa)
+ return true;
+
+ return false;
+}
+
+static enum ft_result
+sfloat_ieee_11073_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp)
+{
+ if (sfloat_ieee_11073_cmp_lt(a, b))
+ *cmp = -1;
+ else
+ *cmp = sfloat_ieee_11073_cmp_eq(a, b) ? 0 : 1;
+
+ return FT_OK;
+}
+
+static bool
+sfloat_ieee_11073_is_zero(const fvalue_t *a)
+{
+ return a->value.sfloat_ieee_11073 == 0;
+}
+
+static unsigned
+sfloat_ieee_11073_hash(const fvalue_t *fv)
+{
+ int64_t value = fv->value.sfloat_ieee_11073;
+ return g_int64_hash(&value);
+}
+
+/*============================================================================*/
+
+static void
+float_ieee_11073_fvalue_new(fvalue_t *fv)
+{
+ fv->value.float_ieee_11073 = 0x0000;
+}
+
+static bool
+float_ieee_11073_val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg _U_)
+{
+ const char *i_char = s;
+ char c;
+ uint8_t mantissa_sign = 0;
+ uint32_t mantissa = 0;
+ int16_t exponent = 0;
+ bool fraction_mode = false;
+ const uint32_t mantissa_max = 0x007FFFFF;
+
+ c = *i_char;
+
+ if (c== '\0')
+ return false;
+
+ if (c == '.')
+ return false;
+
+ if (c == '-' && s[1] == '.')
+ return false;
+
+ if (c == '-' && (s[1] == 'I' || s[1] == 'i')) {
+ if (!g_ascii_strcasecmp(s, "-INFINITY")) {
+ fv->value.float_ieee_11073 = FLOAT_VALUE_INFINITY_MINUS;
+ return true;
+ }
+
+ return false;
+ } else if (c == 'R' || c == 'r') {
+ if (!g_ascii_strcasecmp(s, "RFU")) {
+ fv->value.float_ieee_11073 = FLOAT_VALUE_RFU;
+ return true;
+ }
+
+ return false;
+ } else if (c == 'N' || c == 'n') {
+ if (!g_ascii_strcasecmp(s, "NRes")) {
+ fv->value.float_ieee_11073 = FLOAT_VALUE_NRES;
+ return true;
+ }
+
+ if (!g_ascii_strcasecmp(s, "NaN")) {
+ fv->value.float_ieee_11073 = FLOAT_VALUE_NAN;
+ return true;
+ }
+
+ return false;
+ } else if (c == '+') {
+ if (!g_ascii_strcasecmp(s, "+INFINITY")) {
+ fv->value.float_ieee_11073 = FLOAT_VALUE_INFINITY_PLUS;
+ return true;
+ }
+
+ return false;
+ }
+
+ if (c == '-') {
+ if (s[1] == '\0')
+ return false;
+
+ mantissa_sign = 1;
+ i_char += 1;
+ }
+
+ while (*i_char == '0') {
+ i_char += 1;
+ }
+
+ c = *i_char;
+
+ do {
+ if (c == '0') {
+ if (mantissa * 10 > mantissa_sign + mantissa_max) {
+ exponent += 1;
+ if (exponent <= 127)
+ return false;
+ } else {
+ mantissa *= 10;
+ }
+ } else if (c == '1') {
+ mantissa *= 10;
+ mantissa += 1;
+ } else if (c == '2') {
+ mantissa *= 10;
+ mantissa += 2;
+ } else if (c == '3') {
+ mantissa *= 10;
+ mantissa += 3;
+ } else if (c == '4') {
+ mantissa *= 10;
+ mantissa += 4;
+ } else if (c == '5') {
+ mantissa *= 10;
+ mantissa += 5;
+ } else if (c == '6') {
+ mantissa *= 10;
+ mantissa += 6;
+ } else if (c == '7') {
+ mantissa *= 10;
+ mantissa += 7;
+ } else if (c == '8') {
+ mantissa *= 10;
+ mantissa += 8;
+ } else if (c == '9') {
+ mantissa *= 10;
+ mantissa += 9;
+ } else if (c == '.') {
+ if (fraction_mode)
+ return false;
+ fraction_mode = true;
+ i_char += 1;
+
+ while (*i_char == '0') {
+ i_char += 1;
+ if (mantissa * 10 <= mantissa_max + mantissa_sign) {
+ mantissa *= 10;
+ if (exponent > -128 - 7) /* -8 is min exponent; 4 is mantissa size */
+ exponent -= 1;
+ }
+ }
+
+ i_char -= 1;
+ } else if (c != '\0') {
+ /* NOTE: Maybe 5e-10, 5e3 notation should be also supported */
+ return false;
+ }
+
+ if (mantissa > mantissa_max + mantissa_sign)
+ return false;
+
+ if (c != '.' && fraction_mode)
+ exponent -= 1;
+
+ i_char += 1;
+ } while ((c = *i_char));
+
+ if (mantissa_sign) {
+ mantissa = ~(mantissa - 1);
+ mantissa &= 0x00FFFFFF;
+ }
+
+ /* Transform to normal form */
+
+ if (mantissa == 0)
+ exponent = 0;
+
+ while (mantissa > 0 && mantissa % 10 == 0 && exponent < 127) {
+ mantissa /= 10;
+ exponent += 1;
+ }
+
+ if (exponent < -128)
+ return false;
+
+ fv->value.float_ieee_11073 = ((exponent & 0xFF) << 24) | mantissa;
+
+ return true;
+}
+
+static char *
+float_ieee_11073_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ int8_t exponent;
+ uint32_t mantissa;
+ uint32_t mantissa_sign;
+ uint32_t offset = 0;
+ char mantissa_buf[8];
+ char *mantissa_str;
+ uint8_t mantissa_digits;
+
+ /* Predefinied: +INFINITY, -INFINITY, RFU, NRes, NaN */
+ if (fv->value.float_ieee_11073 >= 0x007FFFFE && fv->value.float_ieee_11073 <= 0x00800002) {
+ char *s = NULL;
+ switch (fv->value.float_ieee_11073) {
+ case FLOAT_VALUE_INFINITY_PLUS:
+ s = "+INFINITY";
+ break;
+ case FLOAT_VALUE_NAN:
+ s = "NaN";
+ break;
+ case FLOAT_VALUE_NRES:
+ s = "NRes";
+ break;
+ case FLOAT_VALUE_RFU:
+ s = "RFU";
+ break;
+ case FLOAT_VALUE_INFINITY_MINUS:
+ s = "-INFINITY";
+ break;
+ }
+ return wmem_strdup(scope, s);
+ }
+
+ /* Longest Signed Nonfloat Number: -8388608*(10^-128) (1 character for sign, 7 for mantisa digits, 127 zeros, 1 character for NULL) */
+ char buf[136];
+
+ exponent = fv->value.float_ieee_11073 >> 24;
+
+ mantissa = fv->value.float_ieee_11073 & 0x007FFFFF;
+ mantissa_sign = (fv->value.float_ieee_11073 & 0x00800000);
+ if (mantissa_sign)
+ mantissa = (uint32_t)(-((int32_t)(mantissa | 0xFF000000)));
+
+ if (mantissa == 0) {
+ return wmem_strdup(scope, "0");
+ }
+
+ if (mantissa_sign) {
+ buf[0] = '-';
+ offset += 1;
+ }
+
+ mantissa_digits = snprintf(mantissa_buf, sizeof(mantissa_buf), "%"PRIu32, mantissa);
+ mantissa_str = mantissa_buf;
+
+ if (exponent == 0) {
+ memcpy(buf + offset, mantissa_str, mantissa_digits);
+ offset += mantissa_digits;
+ } else if (exponent > 0) {
+ memcpy(buf + offset, mantissa_str, mantissa_digits);
+ offset += mantissa_digits;
+
+ memset(buf + offset, '0', exponent);
+ offset += exponent;
+ } else /* if (exponent < 0)*/ {
+ if (-exponent < mantissa_digits) {
+ memcpy(buf + offset, mantissa_str, mantissa_digits + exponent);
+ offset += mantissa_digits + exponent;
+
+ buf[offset] = '.';
+ offset += 1;
+
+ memcpy(buf + offset, mantissa_str + mantissa_digits + exponent, -exponent);
+ offset += -exponent;
+ } else {
+ buf[offset] = '0';
+ offset += 1;
+
+ buf[offset] = '.';
+ offset += 1;
+
+ if (-exponent - mantissa_digits > 0) {
+ memset(buf + offset, '0', -exponent - mantissa_digits);
+ offset += -exponent - mantissa_digits;
+ }
+
+ memcpy(buf + offset, mantissa_str, mantissa_digits);
+ offset += mantissa_digits;
+ }
+ }
+
+ buf[offset] = '\0';
+ return wmem_strdup(scope, buf);
+}
+
+static void
+float_ieee_11073_value_set(fvalue_t *fv, uint32_t value)
+{
+ fv->value.float_ieee_11073 = value;
+}
+
+static uint32_t
+float_ieee_11073_value_get(fvalue_t *fv)
+{
+ return fv->value.float_ieee_11073;
+}
+
+static uint32_t float_to_normal_form(uint32_t value)
+{
+ int8_t exponent;
+ uint16_t mantissa;
+ uint8_t mantissa_sign;
+
+ if (value >= 0x007FFFFE && value <= 0x00800002) /* Save special values */
+ return value;
+
+ mantissa = value & 0x907FFFFF;
+ if (value & 0x00800000) {
+ mantissa = (uint32_t)(-((int32_t)(mantissa | 0xFF000000)));
+ mantissa_sign = 1;
+ } else {
+ mantissa_sign = 0;
+ }
+
+ exponent = value >> 24;
+
+ while ((!(mantissa % 10)) && mantissa != 0) {
+ mantissa /= 10;
+
+ if (exponent == 127)
+ break;
+
+ exponent += 1;
+ }
+
+ return (exponent << 24) | (mantissa_sign << 23) | mantissa;
+}
+
+static bool
+float_ieee_11073_cmp_eq(const fvalue_t *a, const fvalue_t *b)
+{
+ return float_to_normal_form(a->value.float_ieee_11073) == float_to_normal_form(b->value.float_ieee_11073);
+}
+
+static bool
+float_ieee_11073_cmp_lt(const fvalue_t *a, const fvalue_t *b)
+{
+ uint32_t a_norm;
+ uint32_t b_norm;
+ int32_t a_norm_mantissa;
+ int32_t b_norm_mantissa;
+ int8_t a_norm_exponent;
+ int8_t b_norm_exponent;
+
+ a_norm = float_to_normal_form(a->value.float_ieee_11073);
+ b_norm = float_to_normal_form(b->value.float_ieee_11073);
+
+ if (a_norm == b_norm)
+ return false;
+
+ switch (a_norm) {
+ case FLOAT_VALUE_NAN:
+ case FLOAT_VALUE_NRES:
+ case FLOAT_VALUE_RFU:
+ case FLOAT_VALUE_INFINITY_PLUS:
+ return false;
+ case FLOAT_VALUE_INFINITY_MINUS:
+ switch (b_norm) {
+ case FLOAT_VALUE_NAN:
+ case FLOAT_VALUE_NRES:
+ case FLOAT_VALUE_RFU:
+ case FLOAT_VALUE_INFINITY_MINUS: /* Dead, informative case */
+ return false;
+ case FLOAT_VALUE_INFINITY_PLUS:
+ default:
+ return true;
+ }
+ }
+
+ a_norm_mantissa = a_norm & 0x00FFFFFF;
+ b_norm_mantissa = b_norm & 0x00FFFFFF;
+ if (a_norm & 0x00800000)
+ a_norm_mantissa |= 0xFF000000;
+
+ if (b_norm & 0x00800000)
+ b_norm_mantissa |= 0xFF000000;
+
+ a_norm_exponent = a_norm >> 24;
+ b_norm_exponent = b_norm >> 24;
+
+ if (a_norm_mantissa == b_norm_mantissa && a_norm_exponent < b_norm_exponent)
+ return true;
+
+ if (a_norm_exponent == b_norm_exponent && a_norm_mantissa < b_norm_mantissa)
+ return true;
+
+ if (a_norm_exponent < b_norm_exponent) {
+ uint8_t exponent_difference;
+
+ exponent_difference = b_norm_exponent - a_norm_exponent;
+
+ if (exponent_difference >= 7)
+ return true;
+
+ while (exponent_difference--) {
+ b_norm_mantissa *= 10;
+ }
+ } else {
+ uint8_t exponent_difference;
+
+ exponent_difference = a_norm_exponent - b_norm_exponent;
+
+ if (exponent_difference >= 7)
+ return false;
+
+ while (exponent_difference--) {
+ a_norm_mantissa *= 10;
+ }
+ }
+
+ if (a_norm_mantissa < b_norm_mantissa)
+ return true;
+
+ return false;
+}
+
+static enum ft_result
+float_ieee_11073_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp)
+{
+ if (float_ieee_11073_cmp_lt(a, b))
+ *cmp = -1;
+ else
+ *cmp = float_ieee_11073_cmp_eq(a, b) ? 0 : 1;
+
+ return FT_OK;
+}
+
+static bool
+float_ieee_11073_is_zero(const fvalue_t *a)
+{
+ return a->value.float_ieee_11073 == 0;
+}
+
+static unsigned
+float_ieee_11073_hash(const fvalue_t *fv)
+{
+ int64_t value = fv->value.float_ieee_11073;
+ return g_int64_hash(&value);
+}
+
+/*============================================================================*/
+
+void
+ftype_register_ieee_11073_float(void)
+{
+/*
+Size: 16bits = 2 octets
+
+Exponent: 4 bits (signed integer - 2's complement)
+Mantissa: 12 bits (signed integer - 2's complement)
+Base: 10
+
+x = M * (10 ^ E)
+
+Exponent range: from -8 to 7
+Mantissa range: from -2048 to 2047 (4 digits)
+
+Special values:
+ + INFINITY [exponent 0, mantissa +(2^11 -2) = 0x07FE]
+ NaN (Not a Number) [exponent 0, mantissa +(2^11 -1) = 0x07FF]
+ NRes (Not at this Resolution) [exponent 0, mantissa -(2^11) = 0x0800]
+ Reserved for future use [exponent 0, mantissa -(2^11 -1) = 0x0801]
+ - INFINITY [exponent 0, mantissa -(2^11 -2) = 0x0802]
+
+Note:
+be carefour when comparing: 1e == 10e-1 == 10e-2 == ... (solution: compare only if the lowest mantissa % 10 != 0)
+
+Example: 114 is 0x0072
+
+*/
+ static ftype_t sfloat_type = {
+ FT_IEEE_11073_SFLOAT, /* ftype */
+ "FT_IEEE_11073_SFLOAT", /* name */
+ "IEEE-11073 floating point (16-bit)", /* pretty_name */
+ 2, /* wire_size */
+
+ sfloat_ieee_11073_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ sfloat_ieee_11073_val_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ sfloat_ieee_11073_val_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_uinteger = sfloat_ieee_11073_value_set }, /* union set_value */
+ { .get_value_uinteger = sfloat_ieee_11073_value_get }, /* union get_value */
+
+ sfloat_ieee_11073_cmp_order,
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ sfloat_ieee_11073_hash, /* hash */
+ sfloat_ieee_11073_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ NULL, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+/*
+Size: 32bits = 4 octets
+
+Exponent: 1 octet (signed integer - 2's complement)
+Mantissa: 3 octets (signed integer - 2's complement)
+Base: 10
+
+x = M * (10 ^ E)
+
+Exponent range: from -128 to 127
+Mantissa range: from -8388608 to 8388607 (7 digits)
+
+Special values:
+ + INFINITY [exponent 0, mantissa +(2^23 -2) = 0x007FFFFE]
+ NaN (Not a Number) [exponent 0, mantissa +(2^23 -1) = 0x007FFFFF]
+ NRes (Not at this Resolution) [exponent 0, mantissa -(2^23) = 0x00800000]
+ Reserved for future use [exponent 0, mantissa -(2^23-1) = 0x00800001]
+ - INFINITY [exponent 0, mantissa -(2^23 -2) = 0x00800002]
+
+Note:
+be carefour when comparing: 1e == 10e-1 == 10e-2 == ... (solution: compare only if the lowest mantissa % 10 != 0)
+
+Example: 36.4 is 0xFF00016C
+
+*/
+
+ static ftype_t float_type = {
+ FT_IEEE_11073_FLOAT, /* ftype */
+ "FT_IEEE_11073_FLOAT", /* name */
+ "IEEE-11073 Floating point (32-bit)", /* pretty_name */
+ 4, /* wire_size */
+
+ float_ieee_11073_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ float_ieee_11073_val_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ float_ieee_11073_val_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_uinteger = float_ieee_11073_value_set }, /* union set_value */
+ { .get_value_uinteger = float_ieee_11073_value_get }, /* union get_value */
+
+ float_ieee_11073_cmp_order,
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ float_ieee_11073_hash, /* hash */
+ float_ieee_11073_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ NULL, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ ftype_register(FT_IEEE_11073_SFLOAT, &sfloat_type);
+ ftype_register(FT_IEEE_11073_FLOAT, &float_type);
+}
+
+void
+ftype_register_pseudofields_ieee_11073_float(int proto)
+{
+ static int hf_ft_ieee_11073_sfloat;
+ static int hf_ft_ieee_11073_float;
+
+ static hf_register_info hf_ftypes[] = {
+ { &hf_ft_ieee_11073_sfloat,
+ { "FT_IEEE_11073_SFLOAT", "_ws.ftypes.ieee_11073_sfloat",
+ FT_IEEE_11073_SFLOAT, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_ieee_11073_float,
+ { "FT_IEEE_11073_FLOAT", "_ws.ftypes.ieee_11073_float",
+ FT_IEEE_11073_FLOAT, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ };
+
+ proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes));
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/epan/ftypes/ftype-integer.c b/epan/ftypes/ftype-integer.c
new file mode 100644
index 0000000..608fca0
--- /dev/null
+++ b/epan/ftypes/ftype-integer.c
@@ -0,0 +1,2209 @@
+/*
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <errno.h>
+#include "ftypes-int.h"
+#include <epan/addr_resolv.h>
+#include <epan/strutil.h>
+#include <epan/to_str.h>
+
+#include <wsutil/pint.h>
+#include <wsutil/safe-math.h>
+
+static bool
+binary_strtoll(const char *s, int64_t *ptr, char **err_msg);
+
+static bool
+binary_strtoull(const char *s, uint64_t *ptr, char **err_msg);
+
+static void
+int_fvalue_new(fvalue_t *fv)
+{
+ memset(&fv->value, 0, sizeof(fv->value));
+}
+
+static void
+set_uinteger(fvalue_t *fv, uint32_t value)
+{
+ fv->value.uinteger = value;
+}
+
+static void
+set_sinteger(fvalue_t *fv, int32_t value)
+{
+ fv->value.sinteger = value;
+}
+
+
+static uint32_t
+get_uinteger(fvalue_t *fv)
+{
+ return fv->value.uinteger;
+}
+
+static int32_t
+get_sinteger(fvalue_t *fv)
+{
+ return fv->value.sinteger;
+}
+
+static bool
+_uint_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg,
+ uint64_t max)
+{
+ uint64_t value;
+
+ if (!binary_strtoull(s, &value, err_msg))
+ return false;
+
+ if (value > max) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" too big for this field, maximum %"PRIu64".", s, max);
+ return false;
+ }
+
+ fv->value.uinteger = (uint32_t)value;
+ return true;
+}
+
+static bool
+uint32_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _uint_from_literal (fv, s, allow_partial_value, err_msg, UINT32_MAX);
+}
+
+static bool
+uint24_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _uint_from_literal (fv, s, allow_partial_value, err_msg, 0xFFFFFF);
+}
+
+static bool
+uint16_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _uint_from_literal (fv, s, allow_partial_value, err_msg, UINT16_MAX);
+}
+
+static bool
+uint8_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _uint_from_literal (fv, s, allow_partial_value, err_msg, UINT8_MAX);
+}
+
+static bool
+uint_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg _U_)
+{
+ fv->value.uinteger = (uint32_t)num;
+ return true;
+}
+
+static bool
+_sint_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg,
+ int64_t max, int64_t min)
+{
+ int64_t value;
+
+ if (!binary_strtoll(s, &value, err_msg))
+ return false;
+
+ if (value > max) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" too big for this field, maximum %"PRId64".",
+ s, max);
+ return false;
+ }
+ else if (value < min) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" too small for this field, minimum %"PRId64".",
+ s, min);
+ return false;
+ }
+
+ fv->value.sinteger = (int32_t)value;
+ return true;
+}
+
+static bool
+sint32_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _sint_from_literal (fv, s, allow_partial_value, err_msg, INT32_MAX, INT32_MIN);
+}
+
+static bool
+sint24_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _sint_from_literal (fv, s, allow_partial_value, err_msg, 0x7FFFFF, -0x800000);
+}
+
+static bool
+sint16_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _sint_from_literal (fv, s, allow_partial_value, err_msg, INT16_MAX, INT16_MIN);
+}
+
+static bool
+sint8_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _sint_from_literal (fv, s, allow_partial_value, err_msg, INT8_MAX, INT8_MIN);
+}
+
+static bool
+sint_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg _U_)
+{
+ fv->value.sinteger = (int32_t)num;
+ return true;
+}
+
+static char *
+integer_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ uint32_t val;
+
+ size_t size = 11 + 1; /* enough for 2^31-1, in decimal */
+ char *result = wmem_alloc(scope, size);
+ char *buf = result;
+
+ if (fv->value.sinteger < 0) {
+ *buf++ = '-';
+ val = -fv->value.sinteger;
+ } else {
+ val = fv->value.sinteger;
+ }
+ guint32_to_str_buf(val, buf, size);
+ return result;
+}
+
+static char *
+uinteger_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display)
+{
+ size_t size = 10 + 1; /* enough for 2^32-1, in decimal or 0xXXXXXXXX */
+ char *result = wmem_alloc(scope, size);
+ char *buf = result;
+
+ if ((field_display & 0xff) == BASE_HEX ||
+ (field_display & 0xff) == BASE_HEX_DEC) {
+ /* This format perfectly fits into 11 bytes. */
+ *buf++ = '0';
+ *buf++ = 'x';
+
+ switch (fv->ftype->ftype) {
+
+ case FT_UINT8:
+ buf = guint8_to_hex(buf, fv->value.uinteger);
+ break;
+
+ case FT_UINT16:
+ buf = word_to_hex(buf, fv->value.uinteger);
+ break;
+
+ case FT_UINT24:
+ buf = guint8_to_hex(buf, (fv->value.uinteger & 0x00ff0000) >> 16);
+ buf = word_to_hex(buf, (fv->value.uinteger & 0x0000ffff));
+ break;
+
+ default:
+ buf = dword_to_hex(buf, fv->value.uinteger);
+ break;
+ }
+
+ *buf++ = '\0';
+ }
+ else {
+ guint32_to_str_buf(fv->value.uinteger, buf, size);
+ }
+ return result;
+}
+
+static char *
+char_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display)
+{
+ size_t size = 7 + 1; /* enough for '\OOO' or '\xXX' */
+ char *result = wmem_alloc(scope, size);
+ char *buf = result;
+
+ /*
+ * 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';
+ return result;
+}
+
+static bool
+ipxnet_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ /*
+ * Don't request an error message if bytes_from_literal fails;
+ * if it does, we'll report an error specific to this address
+ * type.
+ */
+ if (uint32_from_literal(fv, s, true, NULL)) {
+ return true;
+ }
+
+ /* XXX - Try resolving as an IPX host name and parse that? */
+
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid IPX network address.", s);
+ return false;
+}
+
+static char *
+ipxnet_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display _U_)
+{
+ return uinteger_to_repr(scope, fv, rtype, BASE_HEX);
+}
+
+static enum ft_result
+uint64_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp)
+{
+ uint64_t val_a, val_b;
+ enum ft_result res;
+
+ res = fvalue_to_uinteger64(a, &val_a);
+ if (res != FT_OK)
+ return res;
+
+ res = fvalue_to_uinteger64(b, &val_b);
+ if (res != FT_OK)
+ return res;
+
+ if (val_a == val_b)
+ *cmp = 0;
+ else
+ *cmp = val_a < val_b ? -1 : 1;
+
+ return FT_OK;
+}
+
+static enum ft_result
+uint_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp)
+{
+ return uint64_cmp_order(a, b, cmp);
+}
+
+static enum ft_result
+sint64_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp)
+{
+ int64_t val_a, val_b;
+ enum ft_result res;
+
+ res = fvalue_to_sinteger64(a, &val_a);
+ if (res != FT_OK)
+ return res;
+
+ res = fvalue_to_sinteger64(b, &val_b);
+ if (res != FT_OK)
+ return res;
+
+ if (val_a == val_b)
+ *cmp = 0;
+ else
+ *cmp = val_a < val_b ? -1 : 1;
+
+ return FT_OK;
+}
+
+static enum ft_result
+sint_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp)
+{
+ return sint64_cmp_order(a, b, cmp);
+}
+
+static void
+int64_fvalue_new(fvalue_t *fv)
+{
+ fv->value.sinteger64 = 0;
+}
+
+static void
+set_uinteger64(fvalue_t *fv, uint64_t value)
+{
+ fv->value.uinteger64 = value;
+}
+
+static void
+set_sinteger64(fvalue_t *fv, int64_t value)
+{
+ fv->value.sinteger64 = value;
+}
+
+static uint64_t
+get_uinteger64(fvalue_t *fv)
+{
+ return fv->value.uinteger64;
+}
+
+static int64_t
+get_sinteger64(fvalue_t *fv)
+{
+ return fv->value.sinteger64;
+}
+
+static bool
+binary_strtoull(const char *s, uint64_t *ptr, char **err_msg)
+{
+ char *endptr;
+
+ errno = 0;
+ if (s[0] == '0' && (s[1] == 'b' || s[1] == 'B')) {
+ *ptr = g_ascii_strtoull(s + 2, &endptr, 2);
+ }
+ else {
+ *ptr = g_ascii_strtoull(s, &endptr, 0);
+ }
+
+ if (errno == EINVAL || endptr == s || *endptr != '\0') {
+ /* This isn't a valid number. */
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid number.", s);
+ return false;
+ }
+ if (errno == ERANGE) {
+ if (*ptr == UINT64_MAX) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("\"%s\" causes an integer overflow.", s);
+ }
+ }
+ else if (err_msg != NULL) {
+ /*
+ * XXX - can "strtol()" set errno to
+ * ERANGE without returning LONG_MAX?
+ */
+ *err_msg = ws_strdup_printf("\"%s\" is not an integer.", s);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+_uint64_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg,
+ uint64_t max)
+{
+ uint64_t value;
+
+ if (!binary_strtoull(s, &value, err_msg))
+ return false;
+
+ if (value > max) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" too big for this field, maximum %" PRIu64".", s, max);
+ return false;
+ }
+
+ fv->value.uinteger64 = value;
+ return true;
+}
+
+static bool
+uint64_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _uint64_from_literal (fv, s, allow_partial_value, err_msg, UINT64_MAX);
+}
+
+static bool
+uint56_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _uint64_from_literal (fv, s, allow_partial_value, err_msg, G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFF));
+}
+
+static bool
+uint48_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _uint64_from_literal (fv, s, allow_partial_value, err_msg, G_GUINT64_CONSTANT(0xFFFFFFFFFFFF));
+}
+
+static bool
+uint40_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _uint64_from_literal (fv, s, allow_partial_value, err_msg, G_GUINT64_CONSTANT(0xFFFFFFFFFF));
+}
+
+static bool
+uint64_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg _U_)
+{
+ fv->value.uinteger64 = (uint64_t)num;
+ return true;
+}
+
+static bool
+binary_strtoll(const char *s, int64_t *ptr, char **err_msg)
+{
+ char *endptr;
+
+ errno = 0;
+ if (s[0] == '0' && (s[1] == 'b' || s[1] == 'B')) {
+ *ptr = g_ascii_strtoll(s + 2, &endptr, 2);
+ }
+ else {
+ *ptr = g_ascii_strtoll(s, &endptr, 0);
+ }
+
+ if (errno == EINVAL || endptr == s || *endptr != '\0') {
+ /* This isn't a valid number. */
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid number.", s);
+ return false;
+ }
+ if (errno == ERANGE) {
+ if (*ptr == INT64_MAX) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("\"%s\" causes an integer overflow.", s);
+ }
+ }
+ else if (*ptr == INT64_MIN) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("\"%s\" causes an integer underflow.", s);
+ }
+ }
+ else if (err_msg != NULL) {
+ /*
+ * XXX - can "strtol()" set errno to
+ * ERANGE without returning LONG_MAX?
+ */
+ *err_msg = ws_strdup_printf("\"%s\" is not an integer.", s);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+_sint64_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg,
+ int64_t max, int64_t min)
+{
+ int64_t value;
+
+ if (!binary_strtoll(s, &value, err_msg))
+ return false;
+
+ if (value > max) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" too big for this field, maximum %" PRId64".", s, max);
+ return false;
+ }
+ else if (value < min) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" too small for this field, minimum %" PRId64 ".", s, min);
+ return false;
+ }
+
+ fv->value.sinteger64 = value;
+ return true;
+}
+
+static bool
+sint64_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _sint64_from_literal (fv, s, allow_partial_value, err_msg, INT64_MAX, INT64_MIN);
+}
+
+static bool
+sint56_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _sint64_from_literal (fv, s, allow_partial_value, err_msg, G_GINT64_CONSTANT(0x7FFFFFFFFFFFFF), G_GINT64_CONSTANT(-0x80000000000000));
+}
+
+static bool
+sint48_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _sint64_from_literal (fv, s, allow_partial_value, err_msg, G_GINT64_CONSTANT(0x7FFFFFFFFFFF), G_GINT64_CONSTANT(-0x800000000000));
+}
+
+static bool
+sint40_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg)
+{
+ return _sint64_from_literal (fv, s, allow_partial_value, err_msg, G_GINT64_CONSTANT(0x7FFFFFFFFF), G_GINT64_CONSTANT(-0x8000000000));
+}
+
+static bool
+sint64_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg _U_)
+{
+ fv->value.sinteger64 = (int64_t)num;
+ return true;
+}
+
+static char *
+integer64_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ uint64_t val;
+
+ size_t size = 20 + 1; /* enough for -2^63-1, in decimal */
+ char *result = wmem_alloc(scope, size);
+ char *buf = result;
+
+ if (fv->value.sinteger64 < 0) {
+ *buf++ = '-';
+ val = -fv->value.sinteger64;
+ }
+ else {
+ val = fv->value.sinteger64;
+ }
+ guint64_to_str_buf(val, buf, size);
+ return result;
+}
+
+static char *
+uinteger64_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ size_t size = 20 + 1; /* enough for 2^64-1, in decimal or 0xXXXXXXXXXXXXXXXX */
+ char *result = wmem_alloc(scope, size);
+ char *buf = result;
+
+ if (field_display == BASE_HEX || field_display == BASE_HEX_DEC) {
+ /* This format perfectly fits into 19 bytes. */
+ *buf++ = '0';
+ *buf++ = 'x';
+
+ buf = qword_to_hex(buf, fv->value.uinteger64);
+ *buf++ = '\0';
+ }
+ else {
+ guint64_to_str_buf(fv->value.uinteger64, buf, size);
+ }
+ return result;
+}
+
+static enum ft_result
+uint_bitwise_and(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_)
+{
+ dst->value.uinteger = a->value.uinteger & b->value.uinteger;
+ return FT_OK;
+}
+
+static unsigned
+uint_hash(const fvalue_t *fv)
+{
+ int64_t val = fv->value.uinteger;
+ return g_int64_hash(&val);
+}
+
+static bool
+uint_is_zero(const fvalue_t *fv)
+{
+ return fv->value.uinteger == 0;
+}
+
+static bool
+uint_is_negative(const fvalue_t *fv _U_)
+{
+ return false;
+}
+
+static enum ft_result
+uint_unary_minus(fvalue_t *dst, const fvalue_t *src, char **err_ptr)
+{
+ /* Unsigned integers are promoted to signed 32 bits. */
+ if (src->value.uinteger > INT32_MAX) {
+ if (err_ptr)
+ *err_ptr = ws_strdup_printf("%"G_GUINT32_FORMAT" overflows gint32",
+ src->value.uinteger);
+ return FT_ERROR;
+ }
+ FTYPE_LOOKUP(FT_INT32, dst->ftype);
+ dst->value.sinteger = -(int32_t)src->value.uinteger;
+ return FT_OK;
+}
+
+static enum ft_result
+uint64_bitwise_and(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_)
+{
+ dst->value.uinteger64 = a->value.uinteger64 & b->value.uinteger64;
+ return FT_OK;
+}
+
+static unsigned
+uint64_hash(const fvalue_t *fv)
+{
+ int64_t val = fv->value.uinteger64;
+ return g_int64_hash(&val);
+}
+
+static bool
+uint64_is_zero(const fvalue_t *fv)
+{
+ return fv->value.uinteger64 == 0;
+}
+
+static bool
+uint64_is_negative(const fvalue_t *fv _U_)
+{
+ return false;
+}
+
+static enum ft_result
+uint64_unary_minus(fvalue_t *dst, const fvalue_t *src, char **err_ptr)
+{
+ /* Unsigned64 integers are promoted to signed 64 bits. */
+ if (src->value.uinteger64 > INT64_MAX) {
+ if (err_ptr)
+ *err_ptr = ws_strdup_printf("%"PRIu64" overflows gint64",
+ src->value.uinteger64);
+ return FT_ERROR;
+ }
+ FTYPE_LOOKUP(FT_INT64, dst->ftype);
+ dst->value.sinteger64 = -(int64_t)src->value.uinteger64;
+ return FT_OK;
+}
+
+static enum ft_result
+sint_bitwise_and(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_)
+{
+ dst->value.sinteger = a->value.sinteger & b->value.sinteger;
+ return FT_OK;
+}
+
+static unsigned
+sint_hash(const fvalue_t *fv)
+{
+ int64_t val = fv->value.sinteger;
+ return g_int64_hash(&val);
+}
+
+static bool
+sint_is_zero(const fvalue_t *fv)
+{
+ return fv->value.sinteger == 0;
+}
+
+static bool
+sint_is_negative(const fvalue_t *fv)
+{
+ return fv->value.sinteger < 0;
+}
+
+static enum ft_result
+sint_unary_minus(fvalue_t * dst, const fvalue_t *src, char **err_ptr _U_)
+{
+ dst->value.sinteger = -src->value.sinteger;
+ return FT_OK;
+}
+
+static enum ft_result
+sint64_bitwise_and(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_)
+{
+ dst->value.sinteger64 = a->value.sinteger64 & b->value.sinteger64;
+ return FT_OK;
+}
+
+static unsigned
+sint64_hash(const fvalue_t *fv)
+{
+ int64_t val = fv->value.sinteger64;
+ return g_int64_hash(&val);
+}
+
+static bool
+sint64_is_zero(const fvalue_t *fv)
+{
+ return fv->value.sinteger64 == 0;
+}
+
+static bool
+sint64_is_negative(const fvalue_t *fv)
+{
+ return fv->value.sinteger64 < 0;
+}
+
+static enum ft_result
+sint64_unary_minus(fvalue_t * dst, const fvalue_t *src, char **err_ptr _U_)
+{
+ dst->value.sinteger64 = -src->value.sinteger64;
+ return FT_OK;
+}
+
+static enum ft_result
+sint_add(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (!psnip_safe_int32_add(&dst->value.sinteger, a->value.sinteger, b->value.sinteger)) {
+ *err_ptr = ws_strdup_printf("sint_add: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+_sint_subtract(int32_t *sint_dst, int32_t sint_a, int32_t sint_b, char **err_ptr)
+{
+ if (!psnip_safe_int32_sub(sint_dst, sint_a, sint_b)) {
+ *err_ptr = ws_strdup_printf("sint_subtract: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+sint_subtract(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ return _sint_subtract(&dst->value.sinteger, a->value.sinteger, b->value.sinteger, err_ptr);
+}
+
+static enum ft_result
+sint_multiply(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (!psnip_safe_int32_mul(&dst->value.sinteger, a->value.sinteger, b->value.sinteger)) {
+ *err_ptr = ws_strdup_printf("sint_multiply: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+sint_divide(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (b->value.sinteger == 0) {
+ *err_ptr = ws_strdup_printf("sint_divide: division by zero");
+ return FT_ERROR;
+ }
+
+ if (!psnip_safe_int32_div(&dst->value.sinteger, a->value.sinteger, b->value.sinteger)) {
+ *err_ptr = ws_strdup_printf("sint_divide: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+sint_modulo(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (b->value.sinteger == 0) {
+ *err_ptr = ws_strdup_printf("sint_modulo: division by zero");
+ return FT_ERROR;
+ }
+
+ if (!psnip_safe_int32_mod(&dst->value.sinteger, a->value.sinteger, b->value.sinteger)) {
+ *err_ptr = ws_strdup_printf("sint_modulo: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+uint_add(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (!psnip_safe_uint32_add(&dst->value.uinteger, a->value.uinteger, b->value.uinteger)) {
+ *err_ptr = ws_strdup_printf("uint_add: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+uint_subtract(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (b->value.uinteger > a->value.uinteger) {
+ /* Uses signed arithmetic. */
+ if (a->value.uinteger > INT32_MAX ||
+ b->value.uinteger > INT32_MAX) {
+ *err_ptr = ws_strdup_printf("uint_subtract: signed overflow");
+ return FT_ERROR;
+ }
+ FTYPE_LOOKUP(FT_INT32, dst->ftype);
+ return _sint_subtract(&dst->value.sinteger, (int32_t)a->value.uinteger, (int32_t)b->value.uinteger, err_ptr);
+ }
+
+ if (!psnip_safe_uint32_sub(&dst->value.uinteger, a->value.uinteger, b->value.uinteger)) {
+ *err_ptr = ws_strdup_printf("uint_subtract: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+uint_multiply(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (!psnip_safe_uint32_mul(&dst->value.uinteger, a->value.uinteger, b->value.uinteger)) {
+ *err_ptr = ws_strdup_printf("uint_multiply: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+uint_divide(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (b->value.uinteger == 0) {
+ *err_ptr = ws_strdup_printf("uint_divide: division by zero");
+ return FT_ERROR;
+ }
+
+ if (!psnip_safe_uint32_div(&dst->value.uinteger, a->value.uinteger, b->value.uinteger)) {
+ *err_ptr = ws_strdup_printf("uint_divide: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+uint_modulo(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (b->value.uinteger == 0) {
+ *err_ptr = ws_strdup_printf("uint_modulo: division by zero");
+ return FT_ERROR;
+ }
+
+ if (!psnip_safe_uint32_mod(&dst->value.uinteger, a->value.uinteger, b->value.uinteger)) {
+ *err_ptr = ws_strdup_printf("uint_modulo: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+sint64_add(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (!psnip_safe_int64_add(&dst->value.sinteger64, a->value.sinteger64, b->value.sinteger64)) {
+ *err_ptr = ws_strdup_printf("sint64_add: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+_sint64_subtract(int64_t *sint_dst, int64_t sint_a, int64_t sint_b, char **err_ptr)
+{
+ if (!psnip_safe_int64_sub(sint_dst, sint_a, sint_b)) {
+ *err_ptr = ws_strdup_printf("sint64_subtract: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+sint64_subtract(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ return _sint64_subtract(&dst->value.sinteger64, a->value.sinteger64, b->value.sinteger64, err_ptr);
+}
+
+static enum ft_result
+sint64_multiply(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (!psnip_safe_int64_mul(&dst->value.sinteger64, a->value.sinteger64, b->value.sinteger64)) {
+ *err_ptr = ws_strdup_printf("sint64_multiply: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+sint64_divide(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (b->value.sinteger64 == 0) {
+ *err_ptr = ws_strdup_printf("sint64_divide: division by zero");
+ return FT_ERROR;
+ }
+
+ if (!psnip_safe_int64_div(&dst->value.sinteger64, a->value.sinteger64, b->value.sinteger64)) {
+ *err_ptr = ws_strdup_printf("sint64_divide: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+sint64_modulo(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (b->value.sinteger64 == 0) {
+ *err_ptr = ws_strdup_printf("sint64_modulo: division by zero");
+ return FT_ERROR;
+ }
+
+ if (!psnip_safe_int64_mod(&dst->value.sinteger64, a->value.sinteger64, b->value.sinteger64)) {
+ *err_ptr = ws_strdup_printf("sint64_modulo: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+uint64_add(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (!psnip_safe_uint64_add(&dst->value.uinteger64, a->value.uinteger64, b->value.uinteger64)) {
+ *err_ptr = ws_strdup_printf("uint64_add: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+uint64_subtract(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (b->value.uinteger64 > a->value.uinteger64) {
+ /* Uses signed arithmetic. */
+ if (a->value.uinteger64 > INT64_MAX ||
+ b->value.uinteger64 > INT64_MAX) {
+ *err_ptr = ws_strdup_printf("uint64_subtract: signed overflow");
+ return FT_ERROR;
+ }
+ FTYPE_LOOKUP(FT_INT64, dst->ftype);
+ return _sint64_subtract(&dst->value.sinteger64, (int64_t)a->value.uinteger64, (int64_t)b->value.uinteger64, err_ptr);
+ }
+
+ if (!psnip_safe_uint64_sub(&dst->value.uinteger64, a->value.uinteger64, b->value.uinteger64)) {
+ *err_ptr = ws_strdup_printf("uint64_subtract: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+uint64_multiply(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (!psnip_safe_uint64_mul(&dst->value.uinteger64, a->value.uinteger64, b->value.uinteger64)) {
+ *err_ptr = ws_strdup_printf("uint64_multiply: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+uint64_divide(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (b->value.uinteger64 == 0) {
+ *err_ptr = ws_strdup_printf("uint64_divide: division by zero");
+ return FT_ERROR;
+ }
+
+ if (!psnip_safe_uint64_div(&dst->value.uinteger64, a->value.uinteger64, b->value.uinteger64)) {
+ *err_ptr = ws_strdup_printf("uint64_divide: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result
+uint64_modulo(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ if (b->value.uinteger64 == 0) {
+ *err_ptr = ws_strdup_printf("uint64_modulo: division by zero");
+ return FT_ERROR;
+ }
+
+ if (!psnip_safe_uint64_mod(&dst->value.uinteger64, a->value.uinteger64, b->value.uinteger64)) {
+ *err_ptr = ws_strdup_printf("uint64_modulo: overflow");
+ return FT_ERROR;
+ }
+ return FT_OK;
+}
+
+static enum ft_result uint_val_to_uinteger64(const fvalue_t *src, uint64_t *dst)
+{
+ *dst = src->value.uinteger;
+ return FT_OK;
+}
+
+static enum ft_result uint_val_to_sinteger64(const fvalue_t *src, int64_t *dst)
+{
+ *dst = (int64_t)src->value.uinteger;
+ return FT_OK;
+}
+
+static enum ft_result sint_val_to_uinteger64(const fvalue_t *src, uint64_t *dst)
+{
+ if (src->value.sinteger < 0)
+ return FT_OVERFLOW;
+
+ *dst = (uint64_t)src->value.sinteger;
+ return FT_OK;
+}
+
+static enum ft_result sint_val_to_sinteger64(const fvalue_t *src, int64_t *dst)
+{
+ *dst = src->value.sinteger;
+ return FT_OK;
+}
+
+static enum ft_result uint64_val_to_uinteger64(const fvalue_t *src, uint64_t *dst)
+{
+ *dst = src->value.uinteger64;
+ return FT_OK;
+}
+
+static enum ft_result uint64_val_to_sinteger64(const fvalue_t *src, int64_t *dst)
+{
+ if (src->value.uinteger64 > INT64_MAX)
+ return FT_OVERFLOW;
+
+ *dst = (int64_t)src->value.uinteger64;
+ return FT_OK;
+}
+
+static enum ft_result sint64_val_to_uinteger64(const fvalue_t *src, uint64_t *dst)
+{
+ if (src->value.sinteger64 < 0)
+ return FT_OVERFLOW;
+
+ *dst = (uint64_t)src->value.sinteger64;
+ return FT_OK;
+}
+
+static enum ft_result sint64_val_to_sinteger64(const fvalue_t *src, int64_t *dst)
+{
+ *dst = src->value.sinteger64;
+ return FT_OK;
+}
+
+/* BOOLEAN-specific */
+
+static bool
+boolean_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ if (g_ascii_strcasecmp(s, "true") == 0) {
+ fv->value.uinteger64 = 1;
+ return true;
+ }
+ if (g_ascii_strcasecmp(s, "false") == 0) {
+ fv->value.uinteger64 = 0;
+ return true;
+ }
+
+ char *endptr;
+ errno = 0;
+ int64_t val = g_ascii_strtoll(s, &endptr, 0);
+ if (errno == 0 && *endptr == '\0') {
+ /* This is a valid number. */
+ fv->value.uinteger64 = (val != 0);
+ return true;
+ }
+ if (err_msg)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid boolean", s);
+ return false;
+}
+
+static bool
+boolean_from_string(fvalue_t *fv, const char *s, size_t len, char **err_msg _U_)
+{
+ if (g_ascii_strncasecmp(s, "true", len) == 0) {
+ fv->value.uinteger64 = 1;
+ return true;
+ }
+ if (g_ascii_strncasecmp(s, "false", len) == 0) {
+ fv->value.uinteger64 = 0;
+ return true;
+ }
+
+ if (err_msg)
+ *err_msg = ws_strdup_printf("expected \"True\" or \"False\", not \"%s\"", s);
+ return false;
+}
+
+static char *
+boolean_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display _U_)
+{
+ bool val = fv->value.uinteger64;
+ const char *str = NULL;
+
+ switch (rtype) {
+ case FTREPR_DFILTER:
+ case FTREPR_DISPLAY:
+ str = val ? "True" : "False";
+ break;
+ case FTREPR_JSON:
+ str = val ? "1" : "0";
+ break;
+ }
+
+ return wmem_strdup(scope, str);
+}
+
+/* False is less than True (arbitrary):
+ * A B cmp(A, B)
+ * T T 0
+ * F F 0
+ * F T -1
+ * T F 1
+ */
+static enum ft_result
+boolean_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp)
+{
+ uint64_t val_a, val_b;
+ enum ft_result res;
+
+ val_a = a->value.uinteger64;
+ res = fvalue_to_uinteger64(b, &val_b);
+ if (res != FT_OK)
+ return res;
+
+ if (val_a) {
+ if (val_b) {
+ *cmp = 0;
+ }
+ else {
+ *cmp = 1;
+ }
+ }
+ else if (val_b) {
+ *cmp = -1;
+ }
+ else {
+ *cmp = 0;
+ }
+
+ return FT_OK;
+}
+
+static unsigned
+boolean_hash(const fvalue_t *fv)
+{
+ int val;
+
+ if (fv->value.uinteger64)
+ val = 1;
+ else
+ val = 0;
+ return g_int_hash(&val);
+}
+
+/* EUI64-specific */
+static bool
+eui64_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ GByteArray *bytes;
+ bool res;
+ union {
+ uint64_t value;
+ uint8_t bytes[8];
+ } eui64;
+
+ /*
+ * Don't request an error message if uint64_from_literal fails;
+ * if it does, we'll try parsing it as a sequence of bytes, and
+ * report an error if *that* fails.
+ */
+ if (uint64_from_literal(fv, s, true, NULL)) {
+ return true;
+ }
+
+ bytes = g_byte_array_new();
+ res = hex_str_to_bytes(s, bytes, true);
+ if (!res || bytes->len != 8) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid EUI-64 address.", s);
+ g_byte_array_free(bytes, true);
+ return false;
+ }
+
+ memcpy(eui64.bytes, bytes->data, 8);
+ g_byte_array_free(bytes, true);
+ fv->value.uinteger64 = GUINT64_FROM_BE(eui64.value);
+ return true;
+}
+
+static char *
+eui64_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ union {
+ uint64_t value;
+ uint8_t bytes[8];
+ } eui64;
+
+ /* Copy and convert the address from host to network byte order. */
+ eui64.value = GUINT64_TO_BE(fv->value.uinteger64);
+
+ return wmem_strdup_printf(scope, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
+ eui64.bytes[0], eui64.bytes[1], eui64.bytes[2], eui64.bytes[3],
+ eui64.bytes[4], eui64.bytes[5], eui64.bytes[6], eui64.bytes[7]);
+}
+
+void
+ftype_register_integers(void)
+{
+ static ftype_t char_type = {
+ FT_CHAR, /* ftype */
+ "FT_CHAR", /* name */
+ "Character (8 bits)", /* pretty name */
+ 1, /* wire_size */
+ int_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ uint8_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ uint_from_charconst, /* val_from_charconst */
+ char_to_repr, /* val_to_string_repr */
+
+ uint_val_to_uinteger64, /* val_to_uinteger64 */
+ uint_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_uinteger = set_uinteger }, /* union set_value */
+ { .get_value_uinteger = get_uinteger }, /* union get_value */
+
+ uint_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ uint_hash, /* hash */
+ uint_is_zero, /* is_zero */
+ uint_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ uint_bitwise_and, /* bitwise_and */
+ uint_unary_minus, /* unary_minus */
+ uint_add, /* add */
+ uint_subtract, /* subtract */
+ uint_multiply, /* multiply */
+ uint_divide, /* divide */
+ uint_modulo, /* modulo */
+ };
+ static ftype_t uint8_type = {
+ FT_UINT8, /* ftype */
+ "FT_UINT8", /* name */
+ "Unsigned integer (8 bits)", /* pretty name */
+ 1, /* wire_size */
+ int_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ uint8_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ uint_from_charconst, /* val_from_charconst */
+ uinteger_to_repr, /* val_to_string_repr */
+
+ uint_val_to_uinteger64, /* val_to_uinteger64 */
+ uint_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_uinteger = set_uinteger }, /* union set_value */
+ { .get_value_uinteger = get_uinteger }, /* union get_value */
+
+ uint_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ uint_hash, /* hash */
+ uint_is_zero, /* is_zero */
+ uint_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ uint_bitwise_and, /* bitwise_and */
+ uint_unary_minus, /* unary_minus */
+ uint_add, /* add */
+ uint_subtract, /* subtract */
+ uint_multiply, /* multiply */
+ uint_divide, /* divide */
+ uint_modulo, /* modulo */
+ };
+ static ftype_t uint16_type = {
+ FT_UINT16, /* ftype */
+ "FT_UINT16", /* name */
+ "Unsigned integer (16 bits)", /* pretty_name */
+ 2, /* wire_size */
+ int_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ uint16_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ uint_from_charconst, /* val_from_charconst */
+ uinteger_to_repr, /* val_to_string_repr */
+
+ uint_val_to_uinteger64, /* val_to_uinteger64 */
+ uint_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_uinteger = set_uinteger }, /* union set_value */
+ { .get_value_uinteger = get_uinteger }, /* union get_value */
+
+ uint_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ uint_hash, /* hash */
+ uint_is_zero, /* is_zero */
+ uint_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ uint_bitwise_and, /* bitwise_and */
+ uint_unary_minus, /* unary_minus */
+ uint_add, /* add */
+ uint_subtract, /* subtract */
+ uint_multiply, /* multiply */
+ uint_divide, /* divide */
+ uint_modulo, /* modulo */
+ };
+ static ftype_t uint24_type = {
+ FT_UINT24, /* ftype */
+ "FT_UINT24", /* name */
+ "Unsigned integer (24 bits)", /* pretty_name */
+ 3, /* wire_size */
+ int_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ uint24_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ uint_from_charconst, /* val_from_charconst */
+ uinteger_to_repr, /* val_to_string_repr */
+
+ uint_val_to_uinteger64, /* val_to_uinteger64 */
+ uint_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_uinteger = set_uinteger }, /* union set_value */
+ { .get_value_uinteger = get_uinteger }, /* union get_value */
+
+ uint_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ uint_hash, /* hash */
+ uint_is_zero, /* is_zero */
+ uint_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ uint_bitwise_and, /* bitwise_and */
+ uint_unary_minus, /* unary_minus */
+ uint_add, /* add */
+ uint_subtract, /* subtract */
+ uint_multiply, /* multiply */
+ uint_divide, /* divide */
+ uint_modulo, /* modulo */
+ };
+ static ftype_t uint32_type = {
+ FT_UINT32, /* ftype */
+ "FT_UINT32", /* name */
+ "Unsigned integer (32 bits)", /* pretty_name */
+ 4, /* wire_size */
+ int_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ uint32_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ uint_from_charconst, /* val_from_charconst */
+ uinteger_to_repr, /* val_to_string_repr */
+
+ uint_val_to_uinteger64, /* val_to_uinteger64 */
+ uint_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_uinteger = set_uinteger }, /* union set_value */
+ { .get_value_uinteger = get_uinteger }, /* union get_value */
+
+ uint_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ uint_hash, /* hash */
+ uint_is_zero, /* is_zero */
+ uint_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ uint_bitwise_and, /* bitwise_and */
+ uint_unary_minus, /* unary_minus */
+ uint_add, /* add */
+ uint_subtract, /* subtract */
+ uint_multiply, /* multiply */
+ uint_divide, /* divide */
+ uint_modulo, /* modulo */
+ };
+ static ftype_t uint40_type = {
+ FT_UINT40, /* ftype */
+ "FT_UINT40", /* name */
+ "Unsigned integer (40 bits)", /* pretty_name */
+ 5, /* wire_size */
+ int64_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ uint40_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ uint64_from_charconst, /* val_from_charconst */
+ uinteger64_to_repr, /* val_to_string_repr */
+
+ uint64_val_to_uinteger64, /* val_to_uinteger64 */
+ uint64_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_uinteger64 = set_uinteger64 }, /* union set_value */
+ { .get_value_uinteger64 = get_uinteger64 }, /* union get_value */
+
+ uint64_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ uint64_hash, /* hash */
+ uint64_is_zero, /* is_zero */
+ uint64_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ uint64_bitwise_and, /* bitwise_and */
+ uint64_unary_minus, /* unary_minus */
+ uint64_add, /* add */
+ uint64_subtract, /* subtract */
+ uint64_multiply, /* multiply */
+ uint64_divide, /* divide */
+ uint64_modulo, /* modulo */
+ };
+ static ftype_t uint48_type = {
+ FT_UINT48, /* ftype */
+ "FT_UINT48", /* name */
+ "Unsigned integer (48 bits)", /* pretty_name */
+ 6, /* wire_size */
+ int64_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ uint48_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ uint64_from_charconst, /* val_from_charconst */
+ uinteger64_to_repr, /* val_to_string_repr */
+
+ uint64_val_to_uinteger64, /* val_to_uinteger64 */
+ uint64_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_uinteger64 = set_uinteger64 }, /* union set_value */
+ { .get_value_uinteger64 = get_uinteger64 }, /* union get_value */
+
+ uint64_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ uint64_hash, /* hash */
+ uint64_is_zero, /* is_zero */
+ uint64_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ uint64_bitwise_and, /* bitwise_and */
+ uint64_unary_minus, /* unary_minus */
+ uint64_add, /* add */
+ uint64_subtract, /* subtract */
+ uint64_multiply, /* multiply */
+ uint64_divide, /* divide */
+ uint64_modulo, /* modulo */
+ };
+ static ftype_t uint56_type = {
+ FT_UINT56, /* ftype */
+ "FT_UINT56", /* name */
+ "Unsigned integer (56 bits)", /* pretty_name */
+ 7, /* wire_size */
+ int64_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ uint56_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ uint64_from_charconst, /* val_from_charconst */
+ uinteger64_to_repr, /* val_to_string_repr */
+
+ uint64_val_to_uinteger64, /* val_to_uinteger64 */
+ uint64_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_uinteger64 = set_uinteger64 }, /* union set_value */
+ { .get_value_uinteger64 = get_uinteger64 }, /* union get_value */
+
+ uint64_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ uint64_hash, /* hash */
+ uint64_is_zero, /* is_zero */
+ uint64_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ uint64_bitwise_and, /* bitwise_and */
+ uint64_unary_minus, /* unary_minus */
+ uint64_add, /* add */
+ uint64_subtract, /* subtract */
+ uint64_multiply, /* multiply */
+ uint64_divide, /* divide */
+ uint64_modulo, /* modulo */
+ };
+ static ftype_t uint64_type = {
+ FT_UINT64, /* ftype */
+ "FT_UINT64", /* name */
+ "Unsigned integer (64bits)", /* pretty_name */
+ 8, /* wire_size */
+ int64_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ uint64_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ uint64_from_charconst, /* val_from_charconst */
+ uinteger64_to_repr, /* val_to_string_repr */
+
+ uint64_val_to_uinteger64, /* val_to_uinteger64 */
+ uint64_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_uinteger64 = set_uinteger64 }, /* union set_value */
+ { .get_value_uinteger64 = get_uinteger64 }, /* union get_value */
+
+ uint64_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ uint64_hash, /* hash */
+ uint64_is_zero, /* is_zero */
+ uint64_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ uint64_bitwise_and, /* bitwise_and */
+ uint64_unary_minus, /* unary_minus */
+ uint64_add, /* add */
+ uint64_subtract, /* subtract */
+ uint64_multiply, /* multiply */
+ uint64_divide, /* divide */
+ uint64_modulo, /* modulo */
+ };
+ static ftype_t int8_type = {
+ FT_INT8, /* ftype */
+ "FT_INT8", /* name */
+ "Signed integer (8bits)", /* pretty_name */
+ 1, /* wire_size */
+ int_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ sint8_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ sint_from_charconst, /* val_from_charconst */
+ integer_to_repr, /* val_to_string_repr */
+
+ sint_val_to_uinteger64, /* val_to_uinteger64 */
+ sint_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_sinteger = set_sinteger }, /* union set_value */
+ { .get_value_sinteger = get_sinteger }, /* union get_value */
+
+ sint_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ sint_hash, /* hash */
+ sint_is_zero, /* is_zero */
+ sint_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ sint_bitwise_and, /* bitwise_and */
+ sint_unary_minus, /* unary_minus */
+ sint_add, /* add */
+ sint_subtract, /* subtract */
+ sint_multiply, /* multiply */
+ sint_divide, /* divide */
+ sint_modulo, /* modulo */
+ };
+ static ftype_t int16_type = {
+ FT_INT16, /* ftype */
+ "FT_INT16", /* name */
+ "Signed integer (16 bits)", /* pretty_name */
+ 2, /* wire_size */
+ int_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ sint16_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ sint_from_charconst, /* val_from_charconst */
+ integer_to_repr, /* val_to_string_repr */
+
+ sint_val_to_uinteger64, /* val_to_uinteger64 */
+ sint_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_sinteger = set_sinteger }, /* union set_value */
+ { .get_value_sinteger = get_sinteger }, /* union get_value */
+
+ sint_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ sint_hash, /* hash */
+ sint_is_zero, /* is_zero */
+ sint_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ sint_bitwise_and, /* bitwise_and */
+ sint_unary_minus, /* unary_minus */
+ sint_add, /* add */
+ sint_subtract, /* subtract */
+ sint_multiply, /* multiply */
+ sint_divide, /* divide */
+ sint_modulo, /* modulo */
+ };
+ static ftype_t int24_type = {
+ FT_INT24, /* ftype */
+ "FT_INT24", /* name */
+ "Signed integer (24 bits)", /* pretty_name */
+ 3, /* wire_size */
+ int_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ sint24_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ sint_from_charconst, /* val_from_charconst */
+ integer_to_repr, /* val_to_string_repr */
+
+ sint_val_to_uinteger64, /* val_to_uinteger64 */
+ sint_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_sinteger = set_sinteger }, /* union set_value */
+ { .get_value_sinteger = get_sinteger }, /* union get_value */
+
+ sint_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ sint_hash, /* hash */
+ sint_is_zero, /* is_zero */
+ sint_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ sint_bitwise_and, /* bitwise_and */
+ sint_unary_minus, /* unary_minus */
+ sint_add, /* add */
+ sint_subtract, /* subtract */
+ sint_multiply, /* multiply */
+ sint_divide, /* divide */
+ sint_modulo, /* modulo */
+ };
+ static ftype_t int32_type = {
+ FT_INT32, /* ftype */
+ "FT_INT32", /* name */
+ "Signed integer (32 bits)", /* pretty_name */
+ 4, /* wire_size */
+ int_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ sint32_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ sint_from_charconst, /* val_from_charconst */
+ integer_to_repr, /* val_to_string_repr */
+
+ sint_val_to_uinteger64, /* val_to_uinteger64 */
+ sint_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_sinteger = set_sinteger }, /* union set_value */
+ { .get_value_sinteger = get_sinteger }, /* union get_value */
+
+ sint_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ sint_hash, /* hash */
+ sint_is_zero, /* is_zero */
+ sint_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ sint_bitwise_and, /* bitwise_and */
+ sint_unary_minus, /* unary_minus */
+ sint_add, /* add */
+ sint_subtract, /* subtract */
+ sint_multiply, /* multiply */
+ sint_divide, /* divide */
+ sint_modulo, /* modulo */
+ };
+ static ftype_t int40_type = {
+ FT_INT40, /* ftype */
+ "FT_INT40", /* name */
+ "Signed integer (40 bits)", /* pretty_name */
+ 5, /* wire_size */
+ int64_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ sint40_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ sint64_from_charconst, /* val_from_charconst */
+ integer64_to_repr, /* val_to_string_repr */
+
+ sint64_val_to_uinteger64, /* val_to_uinteger64 */
+ sint64_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_sinteger64 = set_sinteger64 }, /* union set_value */
+ { .get_value_sinteger64 = get_sinteger64 }, /* union get_value */
+
+ sint64_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ sint64_hash, /* hash */
+ sint64_is_zero, /* is_zero */
+ sint64_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ sint64_bitwise_and, /* bitwise_and */
+ sint64_unary_minus, /* unary_minus */
+ sint64_add, /* add */
+ sint64_subtract, /* subtract */
+ sint64_multiply, /* multiply */
+ sint64_divide, /* divide */
+ sint64_modulo, /* modulo */
+ };
+ static ftype_t int48_type = {
+ FT_INT48, /* ftype */
+ "FT_INT48", /* name */
+ "Signed integer (48 bits)", /* pretty_name */
+ 6, /* wire_size */
+ int64_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ sint48_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ sint64_from_charconst, /* val_from_charconst */
+ integer64_to_repr, /* val_to_string_repr */
+
+ sint64_val_to_uinteger64, /* val_to_uinteger64 */
+ sint64_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_sinteger64 = set_sinteger64 }, /* union set_value */
+ { .get_value_sinteger64 = get_sinteger64 }, /* union get_value */
+
+ sint64_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ sint64_hash, /* hash */
+ sint64_is_zero, /* is_zero */
+ sint64_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ sint64_bitwise_and, /* bitwise_and */
+ sint64_unary_minus, /* unary_minus */
+ sint64_add, /* add */
+ sint64_subtract, /* subtract */
+ sint64_multiply, /* multiply */
+ sint64_divide, /* divide */
+ sint64_modulo, /* modulo */
+ };
+ static ftype_t int56_type = {
+ FT_INT56, /* ftype */
+ "FT_INT56", /* name */
+ "Signed integer (56 bits)", /* pretty_name */
+ 7, /* wire_size */
+ int64_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ sint56_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ sint64_from_charconst, /* val_from_charconst */
+ integer64_to_repr, /* val_to_string_repr */
+
+ sint64_val_to_uinteger64, /* val_to_uinteger64 */
+ sint64_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_sinteger64 = set_sinteger64 }, /* union set_value */
+ { .get_value_sinteger64 = get_sinteger64 }, /* union get_value */
+
+ sint64_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ sint64_hash, /* hash */
+ sint64_is_zero, /* is_zero */
+ sint64_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ sint64_bitwise_and, /* bitwise_and */
+ sint64_unary_minus, /* unary_minus */
+ sint64_add, /* add */
+ sint64_subtract, /* subtract */
+ sint64_multiply, /* multiply */
+ sint64_divide, /* divide */
+ sint64_modulo, /* modulo */
+ };
+ static ftype_t int64_type = {
+ FT_INT64, /* ftype */
+ "FT_INT64", /* name */
+ "Signed integer (64 bits)", /* pretty_name */
+ 8, /* wire_size */
+ int64_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ sint64_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ sint64_from_charconst, /* val_from_charconst */
+ integer64_to_repr, /* val_to_string_repr */
+
+ sint64_val_to_uinteger64, /* val_to_uinteger64 */
+ sint64_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_sinteger64 = set_sinteger64 }, /* union set_value */
+ { .get_value_sinteger64 = get_sinteger64 }, /* union get_value */
+
+ sint64_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ sint64_hash, /* hash */
+ sint64_is_zero, /* is_zero */
+ sint64_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ sint64_bitwise_and, /* bitwise_and */
+ sint64_unary_minus, /* unary_minus */
+ sint64_add, /* add */
+ sint64_subtract, /* subtract */
+ sint64_multiply, /* multiply */
+ sint64_divide, /* divide */
+ sint64_modulo, /* modulo */
+ };
+ static ftype_t boolean_type = {
+ FT_BOOLEAN, /* ftype */
+ "FT_BOOLEAN", /* name */
+ "Boolean", /* pretty_name */
+ 0, /* wire_size */
+ int_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ boolean_from_literal, /* val_from_literal */
+ boolean_from_string, /* val_from_string */
+ uint64_from_charconst, /* val_from_charconst */
+ boolean_to_repr, /* val_to_string_repr */
+
+ uint64_val_to_uinteger64, /* val_to_uinteger64 */
+ uint64_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_uinteger64 = set_uinteger64 }, /* union set_value */
+ { .get_value_uinteger64 = get_uinteger64 }, /* union get_value */
+
+ boolean_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ boolean_hash, /* hash */
+ uint64_is_zero, /* is_zero */
+ uint64_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ NULL, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ static ftype_t ipxnet_type = {
+ FT_IPXNET, /* ftype */
+ "FT_IPXNET", /* name */
+ "IPX network number", /* pretty_name */
+ 4, /* wire_size */
+ int_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ ipxnet_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ ipxnet_to_repr, /* val_to_string_repr */
+
+ uint_val_to_uinteger64, /* val_to_uinteger64 */
+ uint_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_uinteger = set_uinteger }, /* union set_value */
+ { .get_value_uinteger = get_uinteger }, /* union get_value */
+
+ uint_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ uint_hash, /* hash */
+ uint_is_zero, /* is_zero */
+ uint_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ uint_bitwise_and, /* bitwise_and */
+ uint_unary_minus, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ static ftype_t framenum_type = {
+ FT_FRAMENUM, /* ftype */
+ "FT_FRAMENUM", /* name */
+ "Frame number", /* pretty_name */
+ 4, /* wire_size */
+ int_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ uint32_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ uint_from_charconst, /* val_from_charconst */
+ uinteger_to_repr, /* val_to_string_repr */
+
+ uint_val_to_uinteger64, /* val_to_uinteger64 */
+ uint_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_uinteger = set_uinteger }, /* union set_value */
+ { .get_value_uinteger = get_uinteger }, /* union get_value */
+
+ uint_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ uint_hash, /* hash */
+ uint_is_zero, /* is_zero */
+ uint_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ uint_bitwise_and, /* bitwise_and */
+ uint_unary_minus, /* unary_minus */
+ uint_add, /* add */
+ uint_subtract, /* subtract */
+ uint_multiply, /* multiply */
+ uint_divide, /* divide */
+ uint_modulo, /* modulo */
+ };
+
+ static ftype_t eui64_type = {
+ FT_EUI64, /* ftype */
+ "FT_EUI64", /* name */
+ "EUI64 address", /* pretty_name */
+ FT_EUI64_LEN, /* wire_size */
+ int64_fvalue_new, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ eui64_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ eui64_to_repr, /* val_to_string_repr */
+
+ uint64_val_to_uinteger64, /* val_to_uinteger64 */
+ uint64_val_to_sinteger64, /* val_to_sinteger64 */
+
+ { .set_value_uinteger64 = set_uinteger64 }, /* union set_value */
+ { .get_value_uinteger64 = get_uinteger64 }, /* union get_value */
+
+ uint64_cmp_order, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ uint64_hash, /* hash */
+ uint64_is_zero, /* is_zero */
+ uint64_is_negative, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ uint64_bitwise_and, /* bitwise_and */
+ uint64_unary_minus, /* unary_minus */
+ uint64_add, /* add */
+ uint64_subtract, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ ftype_register(FT_CHAR, &char_type);
+ ftype_register(FT_UINT8, &uint8_type);
+ ftype_register(FT_UINT16, &uint16_type);
+ ftype_register(FT_UINT24, &uint24_type);
+ ftype_register(FT_UINT32, &uint32_type);
+ ftype_register(FT_UINT40, &uint40_type);
+ ftype_register(FT_UINT48, &uint48_type);
+ ftype_register(FT_UINT56, &uint56_type);
+ ftype_register(FT_UINT64, &uint64_type);
+ ftype_register(FT_INT8, &int8_type);
+ ftype_register(FT_INT16, &int16_type);
+ ftype_register(FT_INT24, &int24_type);
+ ftype_register(FT_INT32, &int32_type);
+ ftype_register(FT_INT40, &int40_type);
+ ftype_register(FT_INT48, &int48_type);
+ ftype_register(FT_INT56, &int56_type);
+ ftype_register(FT_INT64, &int64_type);
+ ftype_register(FT_BOOLEAN, &boolean_type);
+ ftype_register(FT_IPXNET, &ipxnet_type);
+ ftype_register(FT_FRAMENUM, &framenum_type);
+ ftype_register(FT_EUI64, &eui64_type);
+}
+
+void
+ftype_register_pseudofields_integer(int proto)
+{
+ static int hf_ft_char;
+ static int hf_ft_uint8;
+ static int hf_ft_uint16;
+ static int hf_ft_uint24;
+ static int hf_ft_uint32;
+ static int hf_ft_uint40;
+ static int hf_ft_uint48;
+ static int hf_ft_uint56;
+ static int hf_ft_uint64;
+ static int hf_ft_int8;
+ static int hf_ft_int16;
+ static int hf_ft_int24;
+ static int hf_ft_int32;
+ static int hf_ft_int40;
+ static int hf_ft_int48;
+ static int hf_ft_int56;
+ static int hf_ft_int64;
+ static int hf_ft_boolean;
+ static int hf_ft_ipxnet;
+ static int hf_ft_framenum;
+ static int hf_ft_eui64;
+
+ static hf_register_info hf_ftypes[] = {
+ { &hf_ft_char,
+ { "FT_CHAR", "_ws.ftypes.char",
+ FT_CHAR, BASE_HEX, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_uint8,
+ { "FT_UINT8", "_ws.ftypes.uint8",
+ FT_UINT8, BASE_HEX, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_uint16,
+ { "FT_UINT16", "_ws.ftypes.uint16",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_uint24,
+ { "FT_UINT24", "_ws.ftypes.uint24",
+ FT_UINT24, BASE_HEX, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_uint32,
+ { "FT_UINT32", "_ws.ftypes.uint32",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_uint40,
+ { "FT_UINT40", "_ws.ftypes.uint40",
+ FT_UINT40, BASE_HEX, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_uint48,
+ { "FT_UINT48", "_ws.ftypes.uint48",
+ FT_UINT48, BASE_HEX, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_uint56,
+ { "FT_UINT56", "_ws.ftypes.uint56",
+ FT_UINT56, BASE_HEX, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_uint64,
+ { "FT_UINT64", "_ws.ftypes.uint64",
+ FT_UINT64, BASE_HEX, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_int8,
+ { "FT_INT8", "_ws.ftypes.int8",
+ FT_INT8, BASE_DEC, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_int16,
+ { "FT_INT16", "_ws.ftypes.int16",
+ FT_INT16, BASE_DEC, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_int24,
+ { "FT_INT24", "_ws.ftypes.int24",
+ FT_INT24, BASE_DEC, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_int32,
+ { "FT_INT32", "_ws.ftypes.int32",
+ FT_INT32, BASE_DEC, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_int40,
+ { "FT_INT40", "_ws.ftypes.int40",
+ FT_INT40, BASE_DEC, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_int48,
+ { "FT_INT48", "_ws.ftypes.int48",
+ FT_INT48, BASE_DEC, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_int56,
+ { "FT_INT56", "_ws.ftypes.int56",
+ FT_INT56, BASE_DEC, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_int64,
+ { "FT_INT64", "_ws.ftypes.int64",
+ FT_INT64, BASE_DEC, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_boolean,
+ { "FT_BOOLEAN", "_ws.ftypes.boolean",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_ipxnet,
+ { "FT_IPXNET", "_ws.ftypes.ipxnet",
+ FT_IPXNET, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_framenum,
+ { "FT_FRAMENUM", "_ws.ftypes.framenum",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_eui64,
+ { "FT_EUI64", "_ws.ftypes.eui64",
+ FT_EUI64, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ };
+
+ proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes));
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/epan/ftypes/ftype-ipv4.c b/epan/ftypes/ftype-ipv4.c
new file mode 100644
index 0000000..b39788e
--- /dev/null
+++ b/epan/ftypes/ftype-ipv4.c
@@ -0,0 +1,246 @@
+/*
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <ftypes-int.h>
+#include <epan/ipv4.h>
+#include <epan/addr_and_mask.h>
+#include <epan/addr_resolv.h>
+#include <wsutil/bits_count_ones.h>
+
+static void
+set_uinteger(fvalue_t *fv, uint32_t value)
+{
+ fv->value.ipv4.addr = g_ntohl(value);
+ fv->value.ipv4.nmask = ip_get_subnet_mask(32);
+}
+
+static uint32_t
+value_get(fvalue_t *fv)
+{
+ return g_htonl(fv->value.ipv4.addr);
+}
+
+static bool
+val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ uint32_t addr;
+ unsigned int nmask_bits;
+
+ const char *slash, *net_str;
+ const char *addr_str;
+ char *addr_str_to_free = NULL;
+ fvalue_t *nmask_fvalue;
+
+ /* Look for CIDR: Is there a single slash in the string? */
+ slash = strchr(s, '/');
+ if (slash) {
+ /* Make a copy of the string up to but not including the
+ * slash; that's the address portion. */
+ addr_str_to_free = wmem_strndup(NULL, s, slash - s);
+ addr_str = addr_str_to_free;
+ }
+ else {
+ addr_str = s;
+ }
+
+ if (!get_host_ipaddr(addr_str, &addr)) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid hostname or IPv4 address.",
+ addr_str);
+ }
+ if (addr_str_to_free)
+ wmem_free(NULL, addr_str_to_free);
+ return false;
+ }
+
+ if (addr_str_to_free)
+ wmem_free(NULL, addr_str_to_free);
+ fv->value.ipv4.addr = g_ntohl(addr);
+
+ /* If CIDR, get netmask bits. */
+ if (slash) {
+ /* Skip past the slash */
+ net_str = slash + 1;
+
+ /* XXX - this is inefficient */
+ nmask_fvalue = fvalue_from_literal(FT_UINT32, net_str, false, err_msg);
+ if (!nmask_fvalue) {
+ return false;
+ }
+ nmask_bits = fvalue_get_uinteger(nmask_fvalue);
+ fvalue_free(nmask_fvalue);
+
+ if (nmask_bits > 32) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("Netmask bits in a CIDR IPv4 address should be <= 32, not %u",
+ nmask_bits);
+ }
+ return false;
+ }
+ fv->value.ipv4.nmask = ip_get_subnet_mask(nmask_bits);
+ }
+ else {
+ /* Not CIDR; mask covers entire address. */
+ fv->value.ipv4.nmask = ip_get_subnet_mask(32);
+ }
+
+ return true;
+}
+
+static char *
+val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ char buf[WS_INET_ADDRSTRLEN];
+ char *repr;
+
+ uint32_t ipv4_net_order = g_htonl(fv->value.ipv4.addr);
+ ip_to_str_buf((uint8_t*)&ipv4_net_order, buf, sizeof(buf));
+
+ if (fv->value.ipv4.nmask != 0 && fv->value.ipv4.nmask != 0xffffffff)
+ repr = wmem_strdup_printf(scope, "%s/%d", buf, ws_count_ones(fv->value.ipv4.nmask));
+ else
+ repr = wmem_strdup(scope, buf);
+
+ return repr;
+}
+
+
+/* Compares two ipv4_addr_and_masks, taking into account the less restrictive of the
+ * two netmasks, applying that netmask to both addrs.
+ *
+ * So, for example, w.x.y.z/32 eq w.x.y.0/24 is true.
+ */
+
+static enum ft_result
+cmp_order(const fvalue_t *fv_a, const fvalue_t *fv_b, int *cmp)
+{
+ uint32_t addr_a, addr_b, nmask;
+
+ nmask = MIN(fv_a->value.ipv4.nmask, fv_b->value.ipv4.nmask);
+ addr_a = fv_a->value.ipv4.addr & nmask;
+ addr_b = fv_b->value.ipv4.addr & nmask;
+ if (addr_a == addr_b)
+ *cmp = 0;
+ else
+ *cmp = addr_a < addr_b ? -1 : 1;
+ return FT_OK;
+}
+
+static enum ft_result
+bitwise_and(fvalue_t *dst, const fvalue_t *fv_a, const fvalue_t *fv_b, char **err_ptr _U_)
+{
+ dst->value.ipv4 = fv_a->value.ipv4;
+ dst->value.ipv4.addr &= (fv_b->value.ipv4.addr & fv_b->value.ipv4.nmask);
+ return FT_OK;
+}
+
+static unsigned
+len(fvalue_t *fv _U_)
+{
+ return 4;
+}
+
+static void
+slice(fvalue_t *fv, GByteArray *bytes, unsigned offset, unsigned length)
+{
+ uint8_t* data;
+ uint32_t addr = g_htonl(fv->value.ipv4.addr);
+ data = ((uint8_t*)&addr)+offset;
+ g_byte_array_append(bytes, data, length);
+}
+
+static unsigned
+ipv4_hash(const fvalue_t *fv)
+{
+ int64_t val1 = fv->value.ipv4.addr;
+ int64_t val2 = fv->value.ipv4.nmask;
+ return g_int64_hash(&val1) ^ g_int64_hash(&val2);
+}
+
+static bool
+is_zero(const fvalue_t *fv_a)
+{
+ return fv_a->value.ipv4.addr == 0;
+}
+
+void
+ftype_register_ipv4(void)
+{
+
+ static ftype_t ipv4_type = {
+ FT_IPv4, /* ftype */
+ "FT_IPv4", /* name */
+ "IPv4 address", /* pretty_name */
+ 4, /* wire_size */
+ NULL, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ val_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ val_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_uinteger = set_uinteger }, /* union set_value */
+ { .get_value_uinteger = value_get }, /* union get_value */
+
+ cmp_order,
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ ipv4_hash,
+ is_zero,
+ NULL,
+ len,
+ (FvalueSlice)slice,
+ bitwise_and,
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ ftype_register(FT_IPv4, &ipv4_type);
+}
+
+void
+ftype_register_pseudofields_ipv4(int proto)
+{
+ static int hf_ft_ipv4;
+
+ static hf_register_info hf_ftypes[] = {
+ { &hf_ft_ipv4,
+ { "FT_IPv4", "_ws.ftypes.ipv4",
+ FT_IPv4, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ };
+
+ proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes));
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/epan/ftypes/ftype-ipv6.c b/epan/ftypes/ftype-ipv6.c
new file mode 100644
index 0000000..3b06bfd
--- /dev/null
+++ b/epan/ftypes/ftype-ipv6.c
@@ -0,0 +1,275 @@
+/*
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <ftypes-int.h>
+#include <epan/ipv6.h>
+#include <epan/addr_resolv.h>
+#include <epan/to_str.h>
+
+static bool
+ipv6_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ const char *slash;
+ const char *addr_str;
+ char *addr_str_to_free = NULL;
+ unsigned int nmask_bits;
+ fvalue_t *nmask_fvalue;
+
+ /* Look for prefix: Is there a single slash in the string? */
+ slash = strchr(s, '/');
+ if (slash) {
+ /* Make a copy of the string up to but not including the
+ * slash; that's the address portion. */
+ addr_str_to_free = wmem_strndup(NULL, s, slash-s);
+ addr_str = addr_str_to_free;
+ }
+ else
+ addr_str = s;
+
+ if (!get_host_ipaddr6(addr_str, &(fv->value.ipv6.addr))) {
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid hostname or IPv6 address.", s);
+ if (addr_str_to_free)
+ wmem_free(NULL, addr_str_to_free);
+ return false;
+ }
+
+ if (addr_str_to_free)
+ wmem_free(NULL, addr_str_to_free);
+
+ /* If prefix */
+ if (slash) {
+ /* XXX - this is inefficient */
+ nmask_fvalue = fvalue_from_literal(FT_UINT32, slash+1, false, err_msg);
+ if (!nmask_fvalue) {
+ return false;
+ }
+ nmask_bits = fvalue_get_uinteger(nmask_fvalue);
+ fvalue_free(nmask_fvalue);
+
+ if (nmask_bits > 128) {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("Prefix in a IPv6 address should be <= 128, not %u",
+ nmask_bits);
+ }
+ return false;
+ }
+ fv->value.ipv6.prefix = nmask_bits;
+ } else {
+ /* Not CIDR; mask covers entire address. */
+ fv->value.ipv6.prefix = 128;
+ }
+
+ return true;
+}
+
+static char *
+ipv6_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ char buf[WS_INET6_ADDRSTRLEN];
+ char *repr;
+
+ ip6_to_str_buf(&fv->value.ipv6.addr, buf, sizeof(buf));
+
+ if (fv->value.ipv6.prefix != 0 && fv->value.ipv6.prefix != 128)
+ repr = wmem_strdup_printf(scope, "%s/%"PRIu32, buf, fv->value.ipv6.prefix);
+ else
+ repr = wmem_strdup(scope, buf);
+
+ return repr;
+}
+
+static void
+ipv6_set(fvalue_t *fv, const ws_in6_addr *value)
+{
+ memcpy(&fv->value.ipv6.addr, value, FT_IPv6_LEN);
+ fv->value.ipv6.prefix = 128;
+}
+
+
+static const ws_in6_addr *
+ipv6_get(fvalue_t *fv)
+{
+ return &fv->value.ipv6.addr;
+}
+
+static const uint8_t bitmasks[9] =
+ { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+
+static enum ft_result
+cmp_order(const fvalue_t *fv_a, const fvalue_t *fv_b, int *cmp)
+{
+ const ipv6_addr_and_prefix *a = &(fv_a->value.ipv6);
+ const ipv6_addr_and_prefix *b = &(fv_b->value.ipv6);
+ uint32_t prefix;
+ int pos = 0;
+
+ prefix = MIN(a->prefix, b->prefix); /* MIN() like IPv4 */
+ prefix = MIN(prefix, 128); /* sanitize, max prefix is 128 */
+
+ while (prefix >= 8) {
+ int byte_a = (int) (a->addr.bytes[pos]);
+ int byte_b = (int) (b->addr.bytes[pos]);
+
+ if (byte_a != byte_b) {
+ *cmp = byte_a - byte_b;
+ return FT_OK;
+ }
+
+ prefix -= 8;
+ pos++;
+ }
+
+ if (prefix != 0) {
+ int byte_a = (int) (a->addr.bytes[pos] & (bitmasks[prefix]));
+ int byte_b = (int) (b->addr.bytes[pos] & (bitmasks[prefix]));
+
+ if (byte_a != byte_b) {
+ *cmp = byte_a - byte_b;
+ return FT_OK;
+ }
+ }
+ *cmp = 0;
+ return FT_OK;
+}
+
+static enum ft_result
+bitwise_and(fvalue_t *dst, const fvalue_t *fv_a, const fvalue_t *fv_b, char **err_ptr _U_)
+{
+ const ipv6_addr_and_prefix *a = &(fv_a->value.ipv6);
+ const ipv6_addr_and_prefix *b = &(fv_b->value.ipv6);
+ uint32_t prefix;
+ int pos = 0;
+
+ prefix = MIN(a->prefix, b->prefix); /* MIN() like in IPv4 */
+ prefix = MIN(prefix, 128); /* sanitize, max prefix is 128 */
+
+ while (prefix >= 8) {
+ dst->value.ipv6.addr.bytes[pos] =
+ a->addr.bytes[pos] & b->addr.bytes[pos];
+
+ prefix -= 8;
+ pos++;
+ }
+
+ if (prefix != 0) {
+ dst->value.ipv6.addr.bytes[pos] =
+ a->addr.bytes[pos] & b->addr.bytes[pos] & bitmasks[prefix];
+ }
+ return FT_OK;
+}
+
+static unsigned
+len(fvalue_t *fv _U_)
+{
+ return FT_IPv6_LEN;
+}
+
+static void
+slice(fvalue_t *fv, GByteArray *bytes, unsigned offset, unsigned length)
+{
+ uint8_t* data;
+
+ data = fv->value.ipv6.addr.bytes + offset;
+
+ g_byte_array_append(bytes, data, length);
+}
+
+static unsigned
+ipv6_hash(const fvalue_t *fv)
+{
+ struct _ipv6 {
+ int64_t val[2];
+ } *addr = (struct _ipv6 *)&fv->value.ipv6.addr;
+ int64_t mask = fv->value.ipv6.prefix;
+
+ return g_int64_hash(&addr->val[0]) ^ g_int64_hash(&addr->val[1]) ^ g_int64_hash(&mask);
+}
+
+static bool
+is_zero(const fvalue_t *fv_a)
+{
+ ws_in6_addr zero = { 0 };
+ return memcmp(&fv_a->value.ipv6.addr, &zero, sizeof(ws_in6_addr)) == 0;
+}
+
+void
+ftype_register_ipv6(void)
+{
+ static ftype_t ipv6_type = {
+ FT_IPv6, /* ftype */
+ "FT_IPv6", /* name */
+ "IPv6 address", /* pretty_name */
+ FT_IPv6_LEN, /* wire_size */
+ NULL, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ ipv6_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ ipv6_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_ipv6 = ipv6_set }, /* union set_value */
+ { .get_value_ipv6 = ipv6_get }, /* union get_value */
+
+ cmp_order,
+ NULL, /* XXX, cmp_contains, needed? ipv4 doesn't support it */
+ NULL, /* cmp_matches */
+
+ ipv6_hash,
+ is_zero,
+ NULL,
+ len,
+ (FvalueSlice)slice,
+ bitwise_and,
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ ftype_register(FT_IPv6, &ipv6_type);
+}
+
+void
+ftype_register_pseudofields_ipv6(int proto)
+{
+ static int hf_ft_ipv6;
+
+ static hf_register_info hf_ftypes[] = {
+ { &hf_ft_ipv6,
+ { "FT_IPv6", "_ws.ftypes.ipv6",
+ FT_IPv6, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ };
+
+ proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes));
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/epan/ftypes/ftype-none.c b/epan/ftypes/ftype-none.c
new file mode 100644
index 0000000..909fcba
--- /dev/null
+++ b/epan/ftypes/ftype-none.c
@@ -0,0 +1,84 @@
+/*
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <ftypes-int.h>
+
+
+void
+ftype_register_none(void)
+{
+
+ static ftype_t none_type = {
+ FT_NONE, /* ftype */
+ "FT_NONE", /* name */
+ "Label", /* pretty_name */
+ 0, /* wire_size */
+ NULL, /* new_value */
+ NULL, /* copy_value */
+ NULL, /* free_value */
+ NULL, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ NULL, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { NULL }, /* union set_value */
+ { NULL }, /* union get_value */
+
+ NULL, /* cmp_order */
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ NULL, /* hash */
+ NULL, /* is_zero */
+ NULL, /* is_negative */
+ NULL, /* len */
+ NULL, /* slice */
+ NULL, /* biwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+ ftype_register(FT_NONE, &none_type);
+}
+
+void
+ftype_register_pseudofields_none(int proto)
+{
+ static int hf_ft_none;
+
+ static hf_register_info hf_ftypes[] = {
+ { &hf_ft_none,
+ { "FT_NONE", "_ws.ftypes.none",
+ FT_NONE, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ };
+
+ proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes));
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/epan/ftypes/ftype-protocol.c b/epan/ftypes/ftype-protocol.c
new file mode 100644
index 0000000..a0e964c
--- /dev/null
+++ b/epan/ftypes/ftype-protocol.c
@@ -0,0 +1,440 @@
+/*
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <ftypes-int.h>
+#include <epan/strutil.h>
+#include <epan/to_str.h>
+#include <string.h>
+#include <wsutil/glib-compat.h>
+
+#include <epan/exceptions.h>
+#include <wsutil/ws_assert.h>
+
+static void
+value_new(fvalue_t *fv)
+{
+ fv->value.protocol.tvb = NULL;
+ fv->value.protocol.proto_string = NULL;
+ fv->value.protocol.tvb_is_private = false;
+ fv->value.protocol.length = -1;
+}
+
+static void
+value_copy(fvalue_t *dst, const fvalue_t *src)
+{
+ dst->value.protocol.tvb = tvb_clone(src->value.protocol.tvb);
+ dst->value.protocol.proto_string = g_strdup(src->value.protocol.proto_string);
+ dst->value.protocol.tvb_is_private = true;
+ dst->value.protocol.length = src->value.protocol.length;
+}
+
+static void
+value_free(fvalue_t *fv)
+{
+ if (fv->value.protocol.tvb && fv->value.protocol.tvb_is_private) {
+ tvb_free_chain(fv->value.protocol.tvb);
+ }
+ g_free(fv->value.protocol.proto_string);
+}
+
+static void
+value_set(fvalue_t *fv, tvbuff_t *value, const char *name, int length)
+{
+ if (value != NULL) {
+ /* Free up the old value, if we have one */
+ value_free(fv);
+
+ /* Set the protocol description and an (optional, nullable) tvbuff. */
+ fv->value.protocol.tvb = value;
+ fv->value.protocol.proto_string = g_strdup(name);
+ }
+ fv->value.protocol.length = length;
+}
+
+static bool
+val_from_string(fvalue_t *fv, const char *s, size_t len, char **err_msg _U_)
+{
+ tvbuff_t *new_tvb;
+ uint8_t *private_data;
+
+ /* Free up the old value, if we have one */
+ value_free(fv);
+
+ if (len == 0)
+ len = strlen(s);
+
+ /* Make a tvbuff from the string. We can drop the
+ * terminating NUL. */
+ private_data = (uint8_t *)g_memdup2(s, (unsigned)len);
+ new_tvb = tvb_new_real_data(private_data,
+ (unsigned)len, (int)len);
+
+ /* Let the tvbuff know how to delete the data. */
+ tvb_set_free_cb(new_tvb, g_free);
+
+ /* And let us know that we need to free the tvbuff */
+ fv->value.protocol.tvb_is_private = true;
+ /* This "field" is a value, it has no protocol description, but
+ * we might compare it to a protocol with NULL tvb.
+ * (e.g., proto_expert) */
+ fv->value.protocol.tvb = new_tvb;
+ fv->value.protocol.proto_string = g_strdup("");
+ fv->value.protocol.length = -1;
+ return true;
+}
+
+static bool
+val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ GByteArray *bytes;
+ tvbuff_t *new_tvb;
+
+ /* Free up the old value, if we have one */
+ value_free(fv);
+ fv->value.protocol.tvb = NULL;
+ fv->value.protocol.proto_string = NULL;
+ fv->value.protocol.length = -1;
+
+ /* Does this look like a byte string? */
+ bytes = byte_array_from_literal(s, err_msg);
+ if (bytes != NULL) {
+ /* Make a tvbuff from the bytes */
+ new_tvb = tvb_new_real_data(bytes->data, bytes->len, bytes->len);
+
+ /* Let the tvbuff know how to delete the data. */
+ tvb_set_free_cb(new_tvb, g_free);
+
+ /* Free GByteArray, but keep data. */
+ g_byte_array_free(bytes, false);
+
+ /* And let us know that we need to free the tvbuff */
+ fv->value.protocol.tvb_is_private = true;
+ fv->value.protocol.tvb = new_tvb;
+
+ /* This "field" is a value, it has no protocol description, but
+ * we might compare it to a protocol with NULL tvb.
+ * (e.g., proto_expert) */
+ fv->value.protocol.proto_string = g_strdup("");
+ return true;
+ }
+
+ /* Not a byte array, forget about it. */
+ return false;
+}
+
+static bool
+val_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg)
+{
+ GByteArray *bytes;
+ tvbuff_t *new_tvb;
+
+ /* Free up the old value, if we have one */
+ value_free(fv);
+ fv->value.protocol.tvb = NULL;
+ fv->value.protocol.proto_string = NULL;
+ fv->value.protocol.length = -1;
+
+ /* Does this look like a byte string? */
+ bytes = byte_array_from_charconst(num, err_msg);
+ if (bytes != NULL) {
+ /* Make a tvbuff from the bytes */
+ new_tvb = tvb_new_real_data(bytes->data, bytes->len, bytes->len);
+
+ /* Let the tvbuff know how to delete the data. */
+ tvb_set_free_cb(new_tvb, g_free);
+
+ /* Free GByteArray, but keep data. */
+ g_byte_array_free(bytes, false);
+
+ /* And let us know that we need to free the tvbuff */
+ fv->value.protocol.tvb_is_private = true;
+ fv->value.protocol.tvb = new_tvb;
+
+ /* This "field" is a value, it has no protocol description, but
+ * we might compare it to a protocol with NULL tvb.
+ * (e.g., proto_expert) */
+ fv->value.protocol.proto_string = g_strdup("");
+ return true;
+ }
+
+ /* Not a byte array, forget about it. */
+ return false;
+}
+
+static char *
+val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display _U_)
+{
+ unsigned length;
+ char *volatile buf = NULL;
+
+ if (rtype != FTREPR_DFILTER)
+ return NULL;
+
+ TRY {
+ if (fv->value.protocol.length >= 0)
+ length = fv->value.protocol.length;
+ else
+ length = tvb_captured_length(fv->value.protocol.tvb);
+
+ if (length) {
+ if (rtype == FTREPR_DFILTER)
+ buf = bytes_to_dfilter_repr(scope, tvb_get_ptr(fv->value.protocol.tvb, 0, length), length);
+ else
+ buf = bytes_to_str_punct_maxlen(scope, tvb_get_ptr(fv->value.protocol.tvb, 0, length), length, ':', 0);
+ }
+ }
+ CATCH_ALL {
+ /* nothing */
+ }
+ ENDTRY;
+ return buf;
+}
+
+static tvbuff_t *
+value_get(fvalue_t *fv)
+{
+ if (fv->value.protocol.length < 0)
+ return fv->value.protocol.tvb;
+ return tvb_new_subset_length_caplen(fv->value.protocol.tvb, 0, fv->value.protocol.length, fv->value.protocol.length);
+}
+
+static unsigned
+len(fvalue_t *fv)
+{
+ volatile unsigned length = 0;
+
+ TRY {
+ if (fv->value.protocol.tvb) {
+ if (fv->value.protocol.length >= 0)
+ length = fv->value.protocol.length;
+ else
+ length = tvb_captured_length(fv->value.protocol.tvb);
+
+ }
+ }
+ CATCH_ALL {
+ /* nothing */
+ }
+ ENDTRY;
+
+ return length;
+}
+
+static void
+slice(fvalue_t *fv, GByteArray *bytes, unsigned offset, unsigned length)
+{
+ const uint8_t* data;
+ volatile unsigned len = length;
+
+ if (fv->value.protocol.tvb) {
+ if (fv->value.protocol.length >= 0 && (unsigned)fv->value.protocol.length < len) {
+ len = fv->value.protocol.length;
+ }
+
+ TRY {
+ data = tvb_get_ptr(fv->value.protocol.tvb, offset, len);
+ g_byte_array_append(bytes, data, len);
+ }
+ CATCH_ALL {
+ /* nothing */
+ }
+ ENDTRY;
+
+ }
+}
+
+static int
+_tvbcmp(const protocol_value_t *a, const protocol_value_t *b)
+{
+ unsigned a_len;
+ unsigned b_len;
+
+ if (a->length < 0)
+ a_len = tvb_captured_length(a->tvb);
+ else
+ a_len = a->length;
+
+ if (b->length < 0)
+ b_len = tvb_captured_length(b->tvb);
+ else
+ b_len = b->length;
+
+ if (a_len != b_len)
+ return a_len < b_len ? -1 : 1;
+ return memcmp(tvb_get_ptr(a->tvb, 0, a_len), tvb_get_ptr(b->tvb, 0, a_len), a_len);
+}
+
+static enum ft_result
+cmp_order(const fvalue_t *fv_a, const fvalue_t *fv_b, int *cmp)
+{
+ const protocol_value_t *a = (const protocol_value_t *)&fv_a->value.protocol;
+ const protocol_value_t *b = (const protocol_value_t *)&fv_b->value.protocol;
+ volatile int c = 0;
+
+ TRY {
+ if ((a->tvb != NULL) && (b->tvb != NULL)) {
+ c = _tvbcmp(a, b);
+ } else {
+ c = strcmp(a->proto_string, b->proto_string);
+ }
+ }
+ CATCH_ALL {
+ /* nothing */
+ }
+ ENDTRY;
+
+ *cmp = c;
+ return FT_OK;
+}
+
+static enum ft_result
+cmp_contains(const fvalue_t *fv_a, const fvalue_t *fv_b, bool *contains)
+{
+ volatile bool yes = false;
+
+ TRY {
+ /* First see if tvb exists for both sides */
+ if ((fv_a->value.protocol.tvb != NULL) && (fv_b->value.protocol.tvb != NULL)) {
+ if (tvb_find_tvb(fv_a->value.protocol.tvb, fv_b->value.protocol.tvb, 0) > -1) {
+ yes = true;
+ }
+ } else {
+ /* Otherwise just compare strings */
+ if ((strlen(fv_b->value.protocol.proto_string) != 0) &&
+ strstr(fv_a->value.protocol.proto_string, fv_b->value.protocol.proto_string)) {
+ yes = true;
+ }
+ }
+ }
+ CATCH_ALL {
+ /* nothing */
+ }
+ ENDTRY;
+
+ *contains = yes;
+ return FT_OK;
+}
+
+static enum ft_result
+cmp_matches(const fvalue_t *fv, const ws_regex_t *regex, bool *matches)
+{
+ const protocol_value_t *a = (const protocol_value_t *)&fv->value.protocol;
+ volatile bool rc = false;
+ const char *data = NULL; /* tvb data */
+ uint32_t tvb_len; /* tvb length */
+
+ if (! regex) {
+ return FT_BADARG;
+ }
+ TRY {
+ if (a->tvb != NULL) {
+ tvb_len = tvb_captured_length(a->tvb);
+ data = (const char *)tvb_get_ptr(a->tvb, 0, tvb_len);
+ rc = ws_regex_matches_length(regex, data, tvb_len);
+ } else {
+ rc = ws_regex_matches(regex, a->proto_string);
+ }
+ }
+ CATCH_ALL {
+ rc = false;
+ }
+ ENDTRY;
+
+ *matches = rc;
+ return FT_OK;
+}
+
+static unsigned
+val_hash(const fvalue_t *fv)
+{
+ const protocol_value_t *value = &fv->value.protocol;
+ return g_direct_hash(value->tvb) ^ g_int_hash(&value->length) ^ g_str_hash(value->proto_string);
+}
+
+static bool
+is_zero(const fvalue_t *fv)
+{
+ const protocol_value_t *a = &fv->value.protocol;
+ return a->tvb == NULL && a->proto_string == NULL;
+}
+
+void
+ftype_register_tvbuff(void)
+{
+
+ static ftype_t protocol_type = {
+ FT_PROTOCOL, /* ftype */
+ "FT_PROTOCOL", /* name */
+ "Protocol", /* pretty_name */
+ 0, /* wire_size */
+ value_new, /* new_value */
+ value_copy, /* copy_value */
+ value_free, /* free_value */
+ val_from_literal, /* val_from_literal */
+ val_from_string, /* val_from_string */
+ val_from_charconst, /* val_from_charconst */
+ val_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_protocol = value_set }, /* union set_value */
+ { .get_value_protocol = value_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains,
+ cmp_matches,
+
+ val_hash,
+ is_zero,
+ NULL,
+ len,
+ (FvalueSlice)slice,
+ NULL,
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+
+ ftype_register(FT_PROTOCOL, &protocol_type);
+}
+
+void
+ftype_register_pseudofields_tvbuff(int proto)
+{
+ static int hf_ft_protocol;
+
+ static hf_register_info hf_ftypes[] = {
+ { &hf_ft_protocol,
+ { "FT_PROTOCOL", "_ws.ftypes.protocol",
+ FT_PROTOCOL, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ };
+
+ proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes));
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/epan/ftypes/ftype-string.c b/epan/ftypes/ftype-string.c
new file mode 100644
index 0000000..28c33a7
--- /dev/null
+++ b/epan/ftypes/ftype-string.c
@@ -0,0 +1,439 @@
+/*
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <ftypes-int.h>
+#include <string.h>
+
+#include <strutil.h>
+#include <wsutil/ws_assert.h>
+#include <wsutil/unicode-utils.h>
+
+
+static void
+string_fvalue_new(fvalue_t *fv)
+{
+ fv->value.strbuf = NULL;
+}
+
+static void
+string_fvalue_copy(fvalue_t *dst, const fvalue_t *src)
+{
+ dst->value.strbuf = wmem_strbuf_dup(NULL, src->value.strbuf);
+}
+
+static void
+string_fvalue_free(fvalue_t *fv)
+{
+ wmem_strbuf_destroy(fv->value.strbuf);
+}
+
+static void
+string_fvalue_set_strbuf(fvalue_t *fv, wmem_strbuf_t *value)
+{
+ DISSECTOR_ASSERT(value != NULL);
+
+ /* Free up the old value, if we have one */
+ string_fvalue_free(fv);
+
+ fv->value.strbuf = value;
+}
+
+static char *
+string_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ if (rtype == FTREPR_DISPLAY || rtype == FTREPR_JSON) {
+ return ws_escape_null(scope, fv->value.strbuf->str, fv->value.strbuf->len, false);
+ }
+ if (rtype == FTREPR_DFILTER) {
+ return ws_escape_string_len(scope, fv->value.strbuf->str, fv->value.strbuf->len, true);
+ }
+ ws_assert_not_reached();
+}
+
+
+static const wmem_strbuf_t *
+value_get(fvalue_t *fv)
+{
+ return fv->value.strbuf;
+}
+
+static bool
+val_from_string(fvalue_t *fv, const char *s, size_t len, char **err_msg _U_)
+{
+ /* Free up the old value, if we have one */
+ string_fvalue_free(fv);
+
+ if (len > 0)
+ fv->value.strbuf = wmem_strbuf_new_len(NULL, s, len);
+ else
+ fv->value.strbuf = wmem_strbuf_new(NULL, s);
+
+ return true;
+}
+
+static bool
+val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ /* Just turn it into a string */
+ /* XXX Should probably be a syntax error instead. It's more user-friendly to ask the
+ * user to be explicit about the meaning of an unquoted literal than them trying to figure out
+ * why a valid filter expression is giving wrong results. */
+ return val_from_string(fv, s, 0, err_msg);
+}
+
+static bool
+val_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg)
+{
+ /* XXX Should be a syntax error if literal is also a syntax error. */
+
+ /* Free up the old value, if we have one */
+ string_fvalue_free(fv);
+ fv->value.strbuf = NULL;
+
+ if (num > UINT8_MAX) {
+ if (err_msg) {
+ *err_msg = ws_strdup_printf("%lu is too large for a byte value", num);
+ }
+ return false;
+ }
+
+ char c = (char)num;
+ fv->value.strbuf = wmem_strbuf_new(NULL, NULL);
+ wmem_strbuf_append_c(fv->value.strbuf, c);
+
+ return true;
+}
+
+static unsigned
+string_hash(const fvalue_t *fv)
+{
+ return g_str_hash(wmem_strbuf_get_str(fv->value.strbuf));
+}
+
+static bool
+string_is_zero(const fvalue_t *fv)
+{
+ return fv->value.strbuf == NULL || fv->value.strbuf->len == 0;
+}
+
+static unsigned
+len(fvalue_t *fv)
+{
+ /* g_utf8_strlen returns long for no apparent reason*/
+ long len = g_utf8_strlen(fv->value.strbuf->str, -1);
+ if (len < 0)
+ return 0;
+ return (unsigned)len;
+}
+
+static void
+slice(fvalue_t *fv, wmem_strbuf_t *buf, unsigned offset, unsigned length)
+{
+ const char *str = fv->value.strbuf->str;
+
+ /* Go to the starting offset */
+ const char *p = g_utf8_offset_to_pointer(str, (long)offset);
+ const char *n;
+ /* Copy 'length' codepoints to dst. Skip the terminating NULL */
+ while (*p != '\0' && length-- > 0) {
+ n = g_utf8_next_char(p);
+ /* Append n - p bytes (one codepoint)*/
+ wmem_strbuf_append_len(buf, p, n - p);
+ p = n;
+ }
+}
+
+static enum ft_result
+cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp)
+{
+ *cmp = wmem_strbuf_strcmp(a->value.strbuf, b->value.strbuf);
+ return FT_OK;
+}
+
+static enum ft_result
+cmp_contains(const fvalue_t *fv_a, const fvalue_t *fv_b, bool *contains)
+{
+ /* According to
+ * http://www.introl.com/introl-demo/Libraries/C/ANSI_C/string/strstr.html
+ * strstr() returns a non-NULL value if needle is an empty
+ * string. We don't that behavior for cmp_contains. */
+ if (fv_b->value.strbuf->len == 0) {
+ *contains = false;
+ return FT_OK;
+ }
+
+ if (wmem_strbuf_strstr(fv_a->value.strbuf, fv_b->value.strbuf)) {
+ *contains = true;
+ }
+ else {
+ *contains = false;
+ }
+
+ return FT_OK;
+}
+
+static enum ft_result
+cmp_matches(const fvalue_t *fv, const ws_regex_t *regex, bool *matches)
+{
+ wmem_strbuf_t *buf = fv->value.strbuf;
+
+ if (regex == NULL) {
+ return FT_BADARG;
+ }
+
+ *matches = ws_regex_matches_length(regex, buf->str, buf->len);
+ return FT_OK;
+}
+
+void
+ftype_register_string(void)
+{
+
+ static ftype_t string_type = {
+ FT_STRING, /* ftype */
+ "FT_STRING", /* name */
+ "Character string", /* pretty_name */
+ 0, /* wire_size */
+ string_fvalue_new, /* new_value */
+ string_fvalue_copy, /* copy_value */
+ string_fvalue_free, /* free_value */
+ val_from_literal, /* val_from_literal */
+ val_from_string, /* val_from_string */
+ val_from_charconst, /* val_from_charconst */
+ string_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */
+ { .get_value_strbuf = value_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains,
+ cmp_matches,
+
+ string_hash, /* hash */
+ string_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ NULL, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+ static ftype_t stringz_type = {
+ FT_STRINGZ, /* ftype */
+ "FT_STRINGZ", /* name */
+ "Character string", /* pretty name */
+ 0, /* wire_size */
+ string_fvalue_new, /* new_value */
+ string_fvalue_copy, /* copy_value */
+ string_fvalue_free, /* free_value */
+ val_from_literal, /* val_from_literal */
+ val_from_string, /* val_from_string */
+ val_from_charconst, /* val_from_charconst */
+ string_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */
+ { .get_value_strbuf = value_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains, /* cmp_contains */
+ cmp_matches,
+
+ string_hash, /* hash */
+ string_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ NULL, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+ static ftype_t uint_string_type = {
+ FT_UINT_STRING, /* ftype */
+ "FT_UINT_STRING", /* name */
+ "Character string", /* pretty_name */
+ 0, /* wire_size */
+ string_fvalue_new, /* new_value */
+ string_fvalue_copy, /* copy_value */
+ string_fvalue_free, /* free_value */
+ val_from_literal, /* val_from_literal */
+ val_from_string, /* val_from_string */
+ val_from_charconst, /* val_from_charconst */
+ string_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */
+ { .get_value_strbuf = value_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains, /* cmp_contains */
+ cmp_matches,
+
+ string_hash, /* hash */
+ string_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ NULL, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+ static ftype_t stringzpad_type = {
+ FT_STRINGZPAD, /* ftype */
+ "FT_STRINGZPAD", /* name */
+ "Character string", /* pretty name */
+ 0, /* wire_size */
+ string_fvalue_new, /* new_value */
+ string_fvalue_copy, /* copy_value */
+ string_fvalue_free, /* free_value */
+ val_from_literal, /* val_from_literal */
+ val_from_string, /* val_from_string */
+ val_from_charconst, /* val_from_charconst */
+ string_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */
+ { .get_value_strbuf = value_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains, /* cmp_contains */
+ cmp_matches,
+
+ string_hash, /* hash */
+ string_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ NULL, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+ static ftype_t stringztrunc_type = {
+ FT_STRINGZTRUNC, /* ftype */
+ "FT_STRINGZTRUNC", /* name */
+ "Character string", /* pretty name */
+ 0, /* wire_size */
+ string_fvalue_new, /* new_value */
+ string_fvalue_copy, /* copy_value */
+ string_fvalue_free, /* free_value */
+ val_from_literal, /* val_from_literal */
+ val_from_string, /* val_from_string */
+ val_from_charconst, /* val_from_charconst */
+ string_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */
+ { .get_value_strbuf = value_get }, /* union get_value */
+
+ cmp_order,
+ cmp_contains, /* cmp_contains */
+ cmp_matches,
+
+ string_hash, /* hash */
+ string_is_zero, /* is_zero */
+ NULL, /* is_negative */
+ len,
+ (FvalueSlice)slice,
+ NULL, /* bitwise_and */
+ NULL, /* unary_minus */
+ NULL, /* add */
+ NULL, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ ftype_register(FT_STRING, &string_type);
+ ftype_register(FT_STRINGZ, &stringz_type);
+ ftype_register(FT_UINT_STRING, &uint_string_type);
+ ftype_register(FT_STRINGZPAD, &stringzpad_type);
+ ftype_register(FT_STRINGZTRUNC, &stringztrunc_type);
+}
+
+void
+ftype_register_pseudofields_string(int proto)
+{
+ static int hf_ft_string;
+ static int hf_ft_stringz;
+ static int hf_ft_uint_string;
+ static int hf_ft_stringzpad;
+ static int hf_ft_stringztrunc;
+
+ static hf_register_info hf_ftypes[] = {
+ { &hf_ft_string,
+ { "FT_STRING", "_ws.ftypes.string",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_stringz,
+ { "FT_STRINGZ", "_ws.ftypes.stringz",
+ FT_STRINGZ, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_uint_string,
+ { "FT_UINT_STRING", "_ws.ftypes.uint_string",
+ FT_UINT_STRING, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_stringzpad,
+ { "FT_STRINGZPAD", "_ws.ftypes.stringzpad",
+ FT_STRINGZPAD, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_stringztrunc,
+ { "FT_STRINGZTRUNC", "_ws.ftypes.stringztrunc",
+ FT_STRINGZTRUNC, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ };
+
+ proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes));
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/epan/ftypes/ftype-time.c b/epan/ftypes/ftype-time.c
new file mode 100644
index 0000000..568f9e0
--- /dev/null
+++ b/epan/ftypes/ftype-time.c
@@ -0,0 +1,670 @@
+/*
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include "ftypes-int.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <epan/to_str.h>
+#include <wsutil/time_util.h>
+#include <wsutil/ws_strptime.h>
+#include <wsutil/safe-math.h>
+
+
+static enum ft_result
+cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp)
+{
+ *cmp = nstime_cmp(&(a->value.time), &(b->value.time));
+ return FT_OK;
+}
+
+/*
+ * Get a nanoseconds value, starting at "p".
+ *
+ * Returns true on success, false on failure.
+ *
+ * If successful endptr points to the first invalid character.
+ */
+static bool
+get_nsecs(const char *startp, int *nsecs, const char **endptr)
+{
+ int ndigits = 0;
+ int scale;
+ const char *p;
+ int val;
+ int digit;
+ int i;
+
+ /*
+ * How many digits are in the string?
+ */
+ for (p = startp; g_ascii_isdigit(*p); p++)
+ ndigits++;
+
+ /*
+ * If there are N characters in the string, the last of the
+ * characters would be the digit corresponding to 10^(9-N)
+ * nanoseconds.
+ */
+ scale = 9 - ndigits;
+
+ /*
+ * Start at the last character, and work backwards.
+ */
+ val = 0;
+ while (p != startp) {
+ p--;
+
+ if (!g_ascii_isdigit(*p)) {
+ /*
+ * Not a digit - error.
+ */
+ return false;
+ }
+ digit = *p - '0';
+ if (digit != 0) {
+ /*
+ * Non-zero digit corresponding to that number
+ * of (10^scale) units.
+ *
+ * If scale is less than zero, this digit corresponds
+ * to a value less than a nanosecond, so this number
+ * isn't valid.
+ */
+ if (scale < 0)
+ return false;
+ for (i = 0; i < scale; i++)
+ digit *= 10;
+ val += digit;
+ }
+ scale++;
+ }
+ *nsecs = val;
+ if (endptr)
+ *endptr = startp + ndigits;
+ return true;
+}
+
+static bool
+val_from_unix_time(fvalue_t *fv, const char *s)
+{
+ const char *curptr;
+ char *endptr;
+ bool negative = false;
+
+ curptr = s;
+
+ if (*curptr == '-') {
+ negative = true;
+ curptr++;
+ }
+
+ /*
+ * If it doesn't begin with ".", it should contain a seconds
+ * value.
+ */
+ if (*curptr != '.') {
+ /*
+ * Get the seconds value.
+ */
+ fv->value.time.secs = strtoul(curptr, &endptr, 10);
+ if (endptr == curptr || (*endptr != '\0' && *endptr != '.'))
+ return false;
+ curptr = endptr;
+ if (*curptr == '.')
+ curptr++; /* skip the decimal point */
+ } else {
+ /*
+ * No seconds value - it's 0.
+ */
+ fv->value.time.secs = 0;
+ curptr++; /* skip the decimal point */
+ }
+
+ /*
+ * If there's more stuff left in the string, it should be the
+ * nanoseconds value.
+ */
+ if (*curptr != '\0') {
+ /*
+ * Get the nanoseconds value.
+ */
+ if (!get_nsecs(curptr, &fv->value.time.nsecs, NULL))
+ return false;
+ } else {
+ /*
+ * No nanoseconds value - it's 0.
+ */
+ fv->value.time.nsecs = 0;
+ }
+
+ if (negative) {
+ fv->value.time.secs = -fv->value.time.secs;
+ fv->value.time.nsecs = -fv->value.time.nsecs;
+ }
+ return true;
+}
+
+static bool
+relative_val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ if (val_from_unix_time(fv, s))
+ return true;
+
+ if (err_msg != NULL)
+ *err_msg = ws_strdup_printf("\"%s\" is not a valid time.", s);
+ return false;
+}
+
+/*
+ * Parses an absolute time value from a string. The string can have
+ * a UTC time zone suffix. In that case it is interpreted in UTC. Otherwise
+ * it is interpreted in local time.
+ *
+ * OS-dependent; e.g., on 32 bit versions of Windows when compiled to use
+ * _mktime32 treats dates before January 1, 1970 as invalid.
+ * (https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/mktime-mktime32-mktime64)
+ */
+
+/*
+ * Timezone support:
+ *
+ %z an ISO 8601, RFC-2822, or RFC-3339 time zone specification. (A
+ NetBSD extension.) This is one of the following:
+ - The offset from Coordinated Universal Time (`UTC') speci-
+ fied as:
+ · [+-]hhmm
+ · [+-]hh:mm
+ · [+-]hh
+ - `UTC' specified as:
+ · UTC (`Coordinated Universal Time')
+ · GMT (`Greenwich Mean Time')
+ · UT (`Universal Time')
+ · Z (`Zulu Time')
+ - A three character US time zone specified as:
+ · EDT
+ · EST
+ · CDT
+ · CST
+ · MDT
+ · MST
+ · PDT
+ · PST
+ with the first letter standing for `Eastern' (``E''),
+ `Central' (``C''), `Mountain' (``M'') or `Pacific'
+ (``P''), and the second letter standing for `Daylight'
+ (``D'' or summer) time or `Standard' (``S'') time
+ - a single letter military or nautical time zone specified
+ as:
+ · ``A'' through ``I''
+ · ``K'' through ``Y''
+ · ``J'' (non-nautical local time zone)
+
+ %Z time zone name or no characters when time zone information is
+ unavailable. (A NetBSD extension.)
+*/
+
+/*
+ * POSIX and C11 calendar time APIs are limited, poorly documented and have
+ * loads of bagage and surprising behavior and quirks (most stemming from
+ * the fact that the struct tm argument is sometimes both input and output).
+ * See the following reference for a reliable method of handling arbitrary timezones:
+ * C: Converting struct tm times with timezone to time_t
+ * http://kbyanc.blogspot.com/2007/06/c-converting-struct-tm-times-with.html
+ * Relevant excerpt:
+ * "However, if your libc implements both tm_gmtoff and timegm(3) you are
+ * in luck. You just need to use timegm(3) to get the time_t representing
+ * the time in GMT and then subtract the offset stored in tm_gmtoff.
+ * The tricky part is that calling timegm(3) will modify the struct tm,
+ * clearing the tm_gmtoff field to zero."
+ */
+
+#define EXAMPLE "Example: \"Nov 12, 1999 08:55:44.123\" or \"2011-07-04 12:34:56\""
+
+static bool
+absolute_val_from_string(fvalue_t *fv, const char *s, size_t len _U_, char **err_msg_ptr)
+{
+ struct tm tm;
+ const char *bufptr, *curptr = NULL;
+ const char *endptr;
+ bool has_seconds = true;
+ bool has_timezone = true;
+ char *err_msg = NULL;
+ struct ws_timezone zoneinfo = { 0, NULL };
+
+ /* Try Unix time first. */
+ if (val_from_unix_time(fv, s))
+ return true;
+
+ /* Try ISO 8601 format. */
+ endptr = iso8601_to_nstime(&fv->value.time, s, ISO8601_DATETIME);
+ /* Check whether it parsed all of the string */
+ if (endptr != NULL && *endptr == '\0')
+ return true;
+
+ /* No - try other legacy formats. */
+ memset(&tm, 0, sizeof(tm));
+ /* Let the computer figure out if it's DST. */
+ tm.tm_isdst = -1;
+
+ /* Parse the date. ws_strptime() always uses the "C" locale. */
+ bufptr = s;
+ curptr = ws_strptime(bufptr, "%b %d, %Y", &tm, &zoneinfo);
+ if (curptr == NULL)
+ curptr = ws_strptime(bufptr,"%Y-%m-%d", &tm, &zoneinfo);
+ if (curptr == NULL)
+ goto fail;
+
+ /* Parse the time, it is optional. */
+ bufptr = curptr;
+ curptr = ws_strptime(bufptr, " %H:%M:%S", &tm, &zoneinfo);
+ if (curptr == NULL) {
+ has_seconds = false;
+ /* Seconds can be omitted but minutes (and hours) are required
+ * for a valid time value. */
+ curptr = ws_strptime(bufptr," %H:%M", &tm, &zoneinfo);
+ }
+ if (curptr == NULL)
+ curptr = bufptr;
+
+ if (*curptr == '.') {
+ /* Nanoseconds */
+ if (!has_seconds) {
+ err_msg = ws_strdup("Subsecond precision requires a seconds field.");
+ goto fail; /* Requires seconds */
+ }
+ curptr++; /* skip the "." */
+ if (!g_ascii_isdigit((unsigned char)*curptr)) {
+ /* not a digit, so not valid */
+ err_msg = ws_strdup("Subseconds value is not a number.");
+ goto fail;
+ }
+ if (!get_nsecs(curptr, &fv->value.time.nsecs, &endptr)) {
+ err_msg = ws_strdup("Subseconds value is invalid.");
+ goto fail;
+ }
+ curptr = endptr;
+ }
+ else {
+ /*
+ * No nanoseconds value - it's 0.
+ */
+ fv->value.time.nsecs = 0;
+ }
+
+ /* Timezone */
+ bufptr = curptr;
+ curptr = ws_strptime(bufptr, "%n%z", &tm, &zoneinfo);
+ if (curptr == NULL) {
+ /* No timezone, assume localtime. */
+ has_timezone = false;
+ curptr = bufptr;
+ }
+
+ /* Skip whitespace */
+ while (g_ascii_isspace(*curptr)) {
+ curptr++;
+ }
+
+ if (*curptr != '\0') {
+ err_msg = ws_strdup("Unexpected data after time value.");
+ goto fail;
+ }
+
+ if (has_timezone) {
+ /* Convert our calendar time (presumed in UTC, possibly with
+ * an extra timezone offset correction datum) to epoch time. */
+ fv->value.time.secs = mktime_utc(&tm);
+ }
+ else {
+ /* Convert our calendar time (in the local timezone) to epoch time. */
+ fv->value.time.secs = mktime(&tm);
+ }
+ if (fv->value.time.secs == (time_t)-1) {
+ /*
+ * XXX - should we supply an error message that mentions
+ * that the time specified might be syntactically valid
+ * but might not actually have occurred, e.g. a time in
+ * the non-existent time range after the clocks are
+ * set forward during daylight savings time (or possibly
+ * that it's in the time range after the clocks are set
+ * backward, so that there are two different times that
+ * it could be)?
+ */
+ err_msg = ws_strdup_printf("\"%s\" cannot be converted to a valid calendar time.", s);
+ goto fail;
+ }
+
+ if (has_timezone) {
+ /* Normalize to UTC with the offset we have saved. */
+ fv->value.time.secs -= zoneinfo.tm_gmtoff;
+ }
+
+ return true;
+
+fail:
+ if (err_msg_ptr != NULL) {
+ if (err_msg == NULL) {
+ *err_msg_ptr = ws_strdup_printf("\"%s\" is not a valid absolute time. " EXAMPLE, s);
+ }
+ else {
+ *err_msg_ptr = err_msg;
+ }
+ }
+ else {
+ g_free(err_msg);
+ }
+
+ return false;
+}
+
+static bool
+absolute_val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
+{
+ return absolute_val_from_string(fv, s, 0, err_msg);
+}
+
+static void
+time_fvalue_new(fvalue_t *fv)
+{
+ fv->value.time.secs = 0;
+ fv->value.time.nsecs = 0;
+}
+
+static void
+time_fvalue_copy(fvalue_t *dst, const fvalue_t *src)
+{
+ nstime_copy(&dst->value.time, &src->value.time);
+}
+
+static void
+time_fvalue_set(fvalue_t *fv, const nstime_t *value)
+{
+ fv->value.time = *value;
+}
+
+static const nstime_t *
+value_get(fvalue_t *fv)
+{
+ return &(fv->value.time);
+}
+
+static char *
+abs_time_to_ftrepr_dfilter(wmem_allocator_t *scope,
+ const nstime_t *nstime, bool use_utc)
+{
+ struct tm *tm;
+ char datetime_format[128];
+ char nsecs_buf[32];
+
+ if (use_utc) {
+ tm = gmtime(&nstime->secs);
+ if (tm != NULL)
+ strftime(datetime_format, sizeof(datetime_format), "\"%Y-%m-%d %H:%M:%S%%sZ\"", tm);
+ else
+ snprintf(datetime_format, sizeof(datetime_format), "Not representable");
+ }
+ else {
+ tm = localtime(&nstime->secs);
+ /* Displaying the timezone could be made into a preference. */
+ if (tm != NULL)
+ strftime(datetime_format, sizeof(datetime_format), "\"%Y-%m-%d %H:%M:%S%%s%z\"", tm);
+ else
+ snprintf(datetime_format, sizeof(datetime_format), "Not representable");
+ }
+
+ if (nstime->nsecs == 0)
+ return wmem_strdup_printf(scope, datetime_format, "");
+
+ snprintf(nsecs_buf, sizeof(nsecs_buf), ".%09d", nstime->nsecs);
+
+ return wmem_strdup_printf(scope, datetime_format, nsecs_buf);
+}
+
+static char *
+absolute_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display)
+{
+ char *rep;
+
+ if (field_display == BASE_NONE)
+ field_display = ABSOLUTE_TIME_LOCAL;
+
+ switch (rtype) {
+ case FTREPR_DISPLAY:
+ case FTREPR_JSON:
+ rep = abs_time_to_str_ex(scope, &fv->value.time,
+ field_display, ABS_TIME_TO_STR_SHOW_ZONE);
+ break;
+
+ case FTREPR_DFILTER:
+ if (field_display == ABSOLUTE_TIME_UNIX) {
+ rep = abs_time_to_unix_str(scope, &fv->value.time);
+ }
+ else {
+ /* Only ABSOLUTE_TIME_LOCAL and ABSOLUTE_TIME_UTC
+ * are supported. Normalize the field_display value. */
+ if (field_display != ABSOLUTE_TIME_LOCAL)
+ field_display = ABSOLUTE_TIME_UTC;
+ rep = abs_time_to_ftrepr_dfilter(scope, &fv->value.time, field_display != ABSOLUTE_TIME_LOCAL);
+ }
+ break;
+
+ default:
+ ws_assert_not_reached();
+ break;
+ }
+
+ return rep;
+}
+
+static char *
+relative_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
+{
+ return rel_time_to_secs_str(scope, &fv->value.time);
+}
+
+static unsigned
+time_hash(const fvalue_t *fv)
+{
+ return nstime_hash(&fv->value.time);
+}
+
+static bool
+time_is_zero(const fvalue_t *fv)
+{
+ return nstime_is_zero(&fv->value.time);
+}
+
+static bool
+time_is_negative(const fvalue_t *fv)
+{
+ return fv->value.time.secs < 0;
+}
+
+static enum ft_result
+time_unary_minus(fvalue_t * dst, const fvalue_t *src, char **err_ptr _U_)
+{
+ dst->value.time.secs = -src->value.time.secs;
+ dst->value.time.nsecs = -src->value.time.nsecs;
+ return FT_OK;
+}
+
+#define NS_PER_S 1000000000
+
+static void
+check_ns_wraparound(nstime_t *ns, jmp_buf env)
+{
+ if (ns->nsecs >= NS_PER_S || (ns->nsecs > 0 && ns->secs < 0)) {
+ ws_safe_sub_jmp(&ns->nsecs, ns->nsecs, NS_PER_S, env);
+ ws_safe_add_jmp(&ns->secs, ns->secs, 1, env);
+ }
+ else if(ns->nsecs <= -NS_PER_S || (ns->nsecs < 0 && ns->secs > 0)) {
+ ws_safe_add_jmp(&ns->nsecs, ns->nsecs, NS_PER_S, env);
+ ws_safe_sub_jmp(&ns->secs, ns->secs, 1, env);
+ }
+}
+
+static void
+_nstime_add(nstime_t *res, nstime_t a, const nstime_t b, jmp_buf env)
+{
+ ws_safe_add_jmp(&res->secs, a.secs, b.secs, env);
+ ws_safe_add_jmp(&res->nsecs, a.nsecs, b.nsecs, env);
+ check_ns_wraparound(res, env);
+}
+
+static void
+_nstime_sub(nstime_t *res, nstime_t a, const nstime_t b, jmp_buf env)
+{
+ ws_safe_sub_jmp(&res->secs, a.secs, b.secs, env);
+ ws_safe_sub_jmp(&res->nsecs, a.nsecs, b.nsecs, env);
+ check_ns_wraparound(res, env);
+}
+
+static enum ft_result
+time_add(fvalue_t * dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ jmp_buf env;
+ if (setjmp(env) != 0) {
+ *err_ptr = ws_strdup_printf("time_add: overflow");
+ return FT_ERROR;
+ }
+ _nstime_add(&dst->value.time, a->value.time, b->value.time, env);
+ return FT_OK;
+}
+
+static enum ft_result
+time_subtract(fvalue_t * dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr)
+{
+ jmp_buf env;
+ if (setjmp(env) != 0) {
+ *err_ptr = ws_strdup_printf("time_subtract: overflow");
+ return FT_ERROR;
+ }
+ _nstime_sub(&dst->value.time, a->value.time, b->value.time, env);
+ return FT_OK;
+}
+
+void
+ftype_register_time(void)
+{
+
+ static ftype_t abstime_type = {
+ FT_ABSOLUTE_TIME, /* ftype */
+ "FT_ABSOLUTE_TIME", /* name */
+ "Date and time", /* pretty_name */
+ 0, /* wire_size */
+ time_fvalue_new, /* new_value */
+ time_fvalue_copy, /* copy_value */
+ NULL, /* free_value */
+ absolute_val_from_literal, /* val_from_literal */
+ absolute_val_from_string, /* val_from_string */
+ NULL, /* val_from_charconst */
+ absolute_val_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_time = time_fvalue_set }, /* union set_value */
+ { .get_value_time = value_get }, /* union get_value */
+
+ cmp_order,
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ time_hash, /* hash */
+ time_is_zero, /* is_zero */
+ time_is_negative, /* is_negative */
+ NULL,
+ NULL,
+ NULL, /* bitwise_and */
+ time_unary_minus, /* unary_minus */
+ time_add, /* add */
+ time_subtract, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+ static ftype_t reltime_type = {
+ FT_RELATIVE_TIME, /* ftype */
+ "FT_RELATIVE_TIME", /* name */
+ "Time offset", /* pretty_name */
+ 0, /* wire_size */
+ time_fvalue_new, /* new_value */
+ time_fvalue_copy, /* copy_value */
+ NULL, /* free_value */
+ relative_val_from_literal, /* val_from_literal */
+ NULL, /* val_from_string */
+ NULL, /* val_from_charconst */
+ relative_val_to_repr, /* val_to_string_repr */
+
+ NULL, /* val_to_uinteger64 */
+ NULL, /* val_to_sinteger64 */
+
+ { .set_value_time = time_fvalue_set }, /* union set_value */
+ { .get_value_time = value_get }, /* union get_value */
+
+ cmp_order,
+ NULL, /* cmp_contains */
+ NULL, /* cmp_matches */
+
+ time_hash, /* hash */
+ time_is_zero, /* is_zero */
+ time_is_negative, /* is_negative */
+ NULL,
+ NULL,
+ NULL, /* bitwise_and */
+ time_unary_minus, /* unary_minus */
+ time_add, /* add */
+ time_subtract, /* subtract */
+ NULL, /* multiply */
+ NULL, /* divide */
+ NULL, /* modulo */
+ };
+
+ ftype_register(FT_ABSOLUTE_TIME, &abstime_type);
+ ftype_register(FT_RELATIVE_TIME, &reltime_type);
+}
+
+void
+ftype_register_pseudofields_time(int proto)
+{
+ static int hf_ft_rel_time;
+ static int hf_ft_abs_time;
+
+ static hf_register_info hf_ftypes[] = {
+ { &hf_ft_abs_time,
+ { "FT_ABSOLUTE_TIME", "_ws.ftypes.abs_time",
+ FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_ft_rel_time,
+ { "FT_RELATIVE_TIME", "_ws.ftypes.rel_time",
+ FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }
+ },
+ };
+
+ proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes));
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/epan/ftypes/ftypes-int.h b/epan/ftypes/ftypes-int.h
new file mode 100644
index 0000000..3dbd34e
--- /dev/null
+++ b/epan/ftypes/ftypes-int.h
@@ -0,0 +1,205 @@
+/** @file
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef FTYPES_INT_H
+#define FTYPES_INT_H
+
+#include "ftypes.h"
+#include <epan/proto.h>
+#include <epan/packet.h>
+
+struct _fvalue_t {
+ ftype_t *ftype;
+ union {
+ /* Put a few basic types in here */
+ uint32_t uinteger;
+ int32_t sinteger;
+ uint64_t uinteger64;
+ int64_t sinteger64;
+ double floating;
+ wmem_strbuf_t *strbuf;
+ GBytes *bytes;
+ ipv4_addr_and_mask ipv4;
+ ipv6_addr_and_prefix ipv6;
+ e_guid_t guid;
+ nstime_t time;
+ protocol_value_t protocol;
+ uint16_t sfloat_ieee_11073;
+ uint32_t float_ieee_11073;
+ } value;
+};
+
+extern ftype_t* type_list[FT_NUM_TYPES];
+
+/* Given an ftenum number, return an ftype_t* */
+#define FTYPE_LOOKUP(ftype, result) \
+ /* Check input */ \
+ ws_assert(ftype < FT_NUM_TYPES); \
+ result = type_list[ftype];
+
+typedef void (*FvalueNewFunc)(fvalue_t*);
+typedef void (*FvalueCopyFunc)(fvalue_t*, const fvalue_t*);
+typedef void (*FvalueFreeFunc)(fvalue_t*);
+
+typedef bool (*FvalueFromLiteral)(fvalue_t*, const char*, bool, char **);
+typedef bool (*FvalueFromString)(fvalue_t*, const char*, size_t, char **);
+typedef bool (*FvalueFromCharConst)(fvalue_t*, unsigned long, char **);
+typedef char *(*FvalueToStringRepr)(wmem_allocator_t *, const fvalue_t*, ftrepr_t, int field_display);
+
+typedef enum ft_result (*FvalueToUnsignedInteger64Func)(const fvalue_t*, uint64_t *);
+typedef enum ft_result (*FvalueToSignedInteger64Func)(const fvalue_t*, int64_t *);
+
+typedef void (*FvalueSetBytesFunc)(fvalue_t*, GBytes *);
+typedef void (*FvalueSetGuidFunc)(fvalue_t*, const e_guid_t *);
+typedef void (*FvalueSetTimeFunc)(fvalue_t*, const nstime_t *);
+typedef void (*FvalueSetStrbufFunc)(fvalue_t*, wmem_strbuf_t *);
+typedef void (*FvalueSetProtocolFunc)(fvalue_t*, tvbuff_t *value, const char *name, int length);
+typedef void (*FvalueSetUnsignedIntegerFunc)(fvalue_t*, uint32_t);
+typedef void (*FvalueSetSignedIntegerFunc)(fvalue_t*, int32_t);
+typedef void (*FvalueSetUnsignedInteger64Func)(fvalue_t*, uint64_t);
+typedef void (*FvalueSetSignedInteger64Func)(fvalue_t*, int64_t);
+typedef void (*FvalueSetFloatingFunc)(fvalue_t*, double);
+typedef void (*FvalueSetIpv6)(fvalue_t*, const ws_in6_addr *);
+
+typedef GBytes *(*FvalueGetBytesFunc)(fvalue_t*);
+typedef const e_guid_t *(*FvalueGetGuidFunc)(fvalue_t*);
+typedef const nstime_t *(*FvalueGetTimeFunc)(fvalue_t*);
+typedef const wmem_strbuf_t *(*FvalueGetStrbufFunc)(fvalue_t*);
+typedef tvbuff_t *(*FvalueGetProtocolFunc)(fvalue_t*);
+typedef uint32_t (*FvalueGetUnsignedIntegerFunc)(fvalue_t*);
+typedef int32_t (*FvalueGetSignedIntegerFunc)(fvalue_t*);
+typedef uint64_t (*FvalueGetUnsignedInteger64Func)(fvalue_t*);
+typedef int64_t (*FvalueGetSignedInteger64Func)(fvalue_t*);
+typedef double (*FvalueGetFloatingFunc)(fvalue_t*);
+typedef const ws_in6_addr *(*FvalueGetIpv6)(fvalue_t*);
+
+typedef enum ft_result (*FvalueCmp)(const fvalue_t*, const fvalue_t*, int*);
+typedef enum ft_result (*FvalueContains)(const fvalue_t*, const fvalue_t*, bool*);
+typedef enum ft_result (*FvalueMatches)(const fvalue_t*, const ws_regex_t*, bool*);
+
+typedef bool (*FvalueIs)(const fvalue_t*);
+typedef unsigned (*FvalueLen)(fvalue_t*);
+typedef unsigned (*FvalueHashFunc)(const fvalue_t *);
+typedef void (*FvalueSlice)(fvalue_t*, void *, unsigned offset, unsigned length);
+typedef enum ft_result (*FvalueUnaryOp)(fvalue_t *, const fvalue_t*, char **);
+typedef enum ft_result (*FvalueBinaryOp)(fvalue_t *, const fvalue_t*, const fvalue_t*, char **);
+
+struct _ftype_t {
+ ftenum_t ftype;
+ const char *name;
+ const char *pretty_name;
+ int wire_size;
+ FvalueNewFunc new_value;
+ FvalueCopyFunc copy_value;
+ FvalueFreeFunc free_value;
+ FvalueFromLiteral val_from_literal;
+ FvalueFromString val_from_string;
+ FvalueFromCharConst val_from_charconst;
+ FvalueToStringRepr val_to_string_repr;
+
+ FvalueToUnsignedInteger64Func val_to_uinteger64;
+ FvalueToSignedInteger64Func val_to_sinteger64;
+
+ union {
+ FvalueSetBytesFunc set_value_bytes;
+ FvalueSetGuidFunc set_value_guid;
+ FvalueSetTimeFunc set_value_time;
+ FvalueSetStrbufFunc set_value_strbuf;
+ FvalueSetProtocolFunc set_value_protocol;
+ FvalueSetUnsignedIntegerFunc set_value_uinteger;
+ FvalueSetSignedIntegerFunc set_value_sinteger;
+ FvalueSetUnsignedInteger64Func set_value_uinteger64;
+ FvalueSetSignedInteger64Func set_value_sinteger64;
+ FvalueSetFloatingFunc set_value_floating;
+ FvalueSetIpv6 set_value_ipv6;
+ } set_value;
+
+ union {
+ FvalueGetBytesFunc get_value_bytes;
+ FvalueGetGuidFunc get_value_guid;
+ FvalueGetTimeFunc get_value_time;
+ FvalueGetStrbufFunc get_value_strbuf;
+ FvalueGetProtocolFunc get_value_protocol;
+ FvalueGetUnsignedIntegerFunc get_value_uinteger;
+ FvalueGetSignedIntegerFunc get_value_sinteger;
+ FvalueGetUnsignedInteger64Func get_value_uinteger64;
+ FvalueGetSignedInteger64Func get_value_sinteger64;
+ FvalueGetFloatingFunc get_value_floating;
+ FvalueGetIpv6 get_value_ipv6;
+ } get_value;
+
+ FvalueCmp cmp_order;
+ FvalueContains cmp_contains;
+ FvalueMatches cmp_matches;
+
+ FvalueHashFunc hash;
+ FvalueIs is_zero;
+ FvalueIs is_negative;
+ FvalueLen len;
+ FvalueSlice slice;
+ FvalueBinaryOp bitwise_and;
+ FvalueUnaryOp unary_minus;
+ FvalueBinaryOp add;
+ FvalueBinaryOp subtract;
+ FvalueBinaryOp multiply;
+ FvalueBinaryOp divide;
+ FvalueBinaryOp modulo;
+};
+
+void ftype_register(enum ftenum ftype, ftype_t *ft);
+
+void ftype_register_bytes(void);
+void ftype_register_double(void);
+void ftype_register_ieee_11073_float(void);
+void ftype_register_integers(void);
+void ftype_register_ipv4(void);
+void ftype_register_ipv6(void);
+void ftype_register_guid(void);
+void ftype_register_none(void);
+void ftype_register_string(void);
+void ftype_register_time(void);
+void ftype_register_tvbuff(void);
+
+/* For debugging. */
+void ftype_register_pseudofields_bytes(int proto);
+void ftype_register_pseudofields_double(int proto);
+void ftype_register_pseudofields_ieee_11073_float(int proto);
+void ftype_register_pseudofields_integer(int proto);
+void ftype_register_pseudofields_ipv4(int proto);
+void ftype_register_pseudofields_ipv6(int proto);
+void ftype_register_pseudofields_guid(int proto);
+void ftype_register_pseudofields_none(int proto);
+void ftype_register_pseudofields_string(int proto);
+void ftype_register_pseudofields_time(int proto);
+void ftype_register_pseudofields_tvbuff(int proto);
+
+GByteArray *
+byte_array_from_literal(const char *s, char **err_msg);
+
+GByteArray *
+byte_array_from_charconst(unsigned long num, char **err_msg);
+
+char *
+bytes_to_dfilter_repr(wmem_allocator_t *scope,
+ const uint8_t *src, size_t src_size);
+
+#endif /* FTYPES_INT_H */
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/epan/ftypes/ftypes.c b/epan/ftypes/ftypes.c
new file mode 100644
index 0000000..163a662
--- /dev/null
+++ b/epan/ftypes/ftypes.c
@@ -0,0 +1,1249 @@
+/*
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include "ftypes-int.h"
+
+#include <wsutil/ws_assert.h>
+
+/* Keep track of ftype_t's via their ftenum number */
+ftype_t* type_list[FT_NUM_TYPES];
+
+/* Initialize the ftype module. */
+void
+ftypes_initialize(void)
+{
+ ftype_register_bytes();
+ ftype_register_double();
+ ftype_register_ieee_11073_float();
+ ftype_register_integers();
+ ftype_register_ipv4();
+ ftype_register_ipv6();
+ ftype_register_guid();
+ ftype_register_none();
+ ftype_register_string();
+ ftype_register_time();
+ ftype_register_tvbuff();
+}
+
+void
+ftypes_register_pseudofields(void)
+{
+ static int proto_ftypes;
+
+ proto_ftypes = proto_register_protocol(
+ "Wireshark Field/Fundamental Types",
+ "Wireshark FTypes",
+ "_ws.ftypes");
+
+ ftype_register_pseudofields_bytes(proto_ftypes);
+ ftype_register_pseudofields_double(proto_ftypes);
+ ftype_register_pseudofields_ieee_11073_float(proto_ftypes);
+ ftype_register_pseudofields_integer(proto_ftypes);
+ ftype_register_pseudofields_ipv4(proto_ftypes);
+ ftype_register_pseudofields_ipv6(proto_ftypes);
+ ftype_register_pseudofields_guid(proto_ftypes);
+ ftype_register_pseudofields_none(proto_ftypes);
+ ftype_register_pseudofields_string(proto_ftypes);
+ ftype_register_pseudofields_time(proto_ftypes);
+ ftype_register_pseudofields_tvbuff(proto_ftypes);
+
+ proto_set_cant_toggle(proto_ftypes);
+}
+
+/* Each ftype_t is registered via this function */
+void
+ftype_register(enum ftenum ftype, ftype_t *ft)
+{
+ /* Check input */
+ ws_assert(ftype < FT_NUM_TYPES);
+ ws_assert(ftype == ft->ftype);
+
+ /* Don't re-register. */
+ ws_assert(type_list[ftype] == NULL);
+
+ type_list[ftype] = ft;
+}
+
+
+/* from README.dissector:
+ Note that the formats used must all belong to the same list as defined below:
+ - FT_INT8, FT_INT16, FT_INT24 and FT_INT32
+ - FT_UINT8, FT_UINT16, FT_UINT24, FT_UINT32, FT_IPXNET and FT_FRAMENUM
+ - FT_UINT64 and FT_EUI64
+ - FT_STRING, FT_STRINGZ and FT_UINT_STRING
+ - FT_FLOAT and FT_DOUBLE
+ - FT_BYTES, FT_UINT_BYTES, FT_AX25, FT_ETHER, FT_VINES, FT_OID and FT_REL_OID
+ - FT_ABSOLUTE_TIME and FT_RELATIVE_TIME
+*/
+static enum ftenum
+same_ftype(const enum ftenum ftype)
+{
+ switch (ftype) {
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ return FT_INT32;
+
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ return FT_UINT32;
+
+ case FT_INT40:
+ case FT_INT48:
+ case FT_INT56:
+ case FT_INT64:
+ return FT_INT64;
+
+ case FT_UINT40:
+ case FT_UINT48:
+ case FT_UINT56:
+ case FT_UINT64:
+ return FT_UINT64;
+
+ case FT_STRING:
+ case FT_STRINGZ:
+ case FT_UINT_STRING:
+ return FT_STRING;
+
+ case FT_FLOAT:
+ case FT_DOUBLE:
+ return FT_DOUBLE;
+
+ case FT_BYTES:
+ case FT_UINT_BYTES:
+ return FT_BYTES;
+
+ case FT_OID:
+ case FT_REL_OID:
+ return FT_OID;
+
+ /* XXX: the folowing are unique for now */
+ case FT_IPv4:
+ case FT_IPv6:
+
+ /* everything else is unique */
+ default:
+ return ftype;
+ }
+}
+
+/* given two types, are they similar - for example can two
+ * duplicate fields be registered of these two types. */
+bool
+ftype_similar_types(const enum ftenum ftype_a, const enum ftenum ftype_b)
+{
+ return (same_ftype(ftype_a) == same_ftype(ftype_b));
+}
+
+/* Returns a string representing the name of the type. Useful
+ * for glossary production. */
+const char*
+ftype_name(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->name;
+}
+
+const char*
+ftype_pretty_name(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->pretty_name;
+}
+
+int
+ftype_wire_size(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->wire_size;
+}
+
+bool
+ftype_can_length(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->len ? true : false;
+}
+
+bool
+ftype_can_slice(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->slice ? true : false;
+}
+
+bool
+ftype_can_eq(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->cmp_order != NULL;
+}
+
+bool
+ftype_can_cmp(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->cmp_order != NULL;
+}
+
+bool
+ftype_can_bitwise_and(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->bitwise_and ? true : false;
+}
+
+bool
+ftype_can_unary_minus(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->unary_minus != NULL;
+}
+
+bool
+ftype_can_add(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->add != NULL;
+}
+
+bool
+ftype_can_subtract(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->subtract != NULL;
+}
+
+bool
+ftype_can_multiply(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->multiply != NULL;
+}
+
+bool
+ftype_can_divide(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->divide != NULL;
+}
+
+bool
+ftype_can_modulo(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->modulo != NULL;
+}
+
+bool
+ftype_can_contains(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->cmp_contains ? true : false;
+}
+
+bool
+ftype_can_matches(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->cmp_matches ? true : false;
+}
+
+bool
+ftype_can_is_zero(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->is_zero ? true : false;
+}
+
+bool
+ftype_can_is_negative(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->is_negative ? true : false;
+}
+
+bool
+ftype_can_val_to_sinteger(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ /* We first convert to 64 bit and then check for overflow. */
+ return ft->val_to_sinteger64 ? true : false;
+}
+
+bool
+ftype_can_val_to_uinteger(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ /* We first convert to 64 bit and then check for overflow. */
+ return ft->val_to_uinteger64 ? true : false;
+}
+
+bool
+ftype_can_val_to_sinteger64(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->val_to_sinteger64 ? true : false;
+}
+
+bool
+ftype_can_val_to_uinteger64(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ FTYPE_LOOKUP(ftype, ft);
+ return ft->val_to_uinteger64 ? true : false;
+}
+
+/* ---------------------------------------------------------- */
+
+/* Allocate and initialize an fvalue_t, given an ftype */
+fvalue_t*
+fvalue_new(ftenum_t ftype)
+{
+ fvalue_t *fv;
+ ftype_t *ft;
+ FvalueNewFunc new_value;
+
+ fv = g_slice_new(fvalue_t);
+
+ FTYPE_LOOKUP(ftype, ft);
+ fv->ftype = ft;
+
+ new_value = ft->new_value;
+ if (new_value) {
+ new_value(fv);
+ }
+
+ return fv;
+}
+
+fvalue_t*
+fvalue_dup(const fvalue_t *fv_orig)
+{
+ fvalue_t *fv_new;
+ FvalueCopyFunc copy_value;
+
+ fv_new = g_slice_new(fvalue_t);
+ fv_new->ftype = fv_orig->ftype;
+ copy_value = fv_new->ftype->copy_value;
+ if (copy_value != NULL) {
+ /* deep copy */
+ copy_value(fv_new, fv_orig);
+ }
+ else {
+ /* shallow copy */
+ memcpy(&fv_new->value, &fv_orig->value, sizeof(fv_orig->value));
+ }
+
+ return fv_new;
+}
+
+void
+fvalue_init(fvalue_t *fv, ftenum_t ftype)
+{
+ ftype_t *ft;
+ FvalueNewFunc new_value;
+
+ FTYPE_LOOKUP(ftype, ft);
+ fv->ftype = ft;
+
+ new_value = ft->new_value;
+ if (new_value) {
+ new_value(fv);
+ }
+}
+
+void
+fvalue_cleanup(fvalue_t *fv)
+{
+ if (!fv->ftype->free_value)
+ return;
+ fv->ftype->free_value(fv);
+}
+
+void
+fvalue_free(fvalue_t *fv)
+{
+ fvalue_cleanup(fv);
+ g_slice_free(fvalue_t, fv);
+}
+
+fvalue_t*
+fvalue_from_literal(ftenum_t ftype, const char *s, bool allow_partial_value, char **err_msg)
+{
+ fvalue_t *fv;
+ bool ok = false;
+
+ fv = fvalue_new(ftype);
+ if (fv->ftype->val_from_literal) {
+ ok = fv->ftype->val_from_literal(fv, s, allow_partial_value, err_msg);
+ if (ok) {
+ /* Success */
+ if (err_msg != NULL)
+ *err_msg = NULL;
+ return fv;
+ }
+ }
+ else {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("\"%s\" cannot be converted to %s.",
+ s, ftype_pretty_name(ftype));
+ }
+ }
+ fvalue_free(fv);
+ return NULL;
+}
+
+fvalue_t*
+fvalue_from_string(ftenum_t ftype, const char *str, size_t len, char **err_msg)
+{
+ fvalue_t *fv;
+
+ fv = fvalue_new(ftype);
+ if (fv->ftype->val_from_string) {
+ if (fv->ftype->val_from_string(fv, str, len, err_msg)) {
+ /* Success */
+ if (err_msg != NULL)
+ *err_msg = NULL;
+ return fv;
+ }
+ }
+ else {
+ if (err_msg != NULL) {
+ *err_msg = ws_strdup_printf("%s cannot be converted from a string (\"%s\").",
+ ftype_pretty_name(ftype), str);
+ }
+ }
+ fvalue_free(fv);
+ return NULL;
+}
+
+fvalue_t*
+fvalue_from_charconst(ftenum_t ftype, unsigned long num, char **err_msg)
+{
+ fvalue_t *fv;
+
+ fv = fvalue_new(ftype);
+ if (fv->ftype->val_from_charconst) {
+ if (fv->ftype->val_from_charconst(fv, num, err_msg)) {
+ /* Success */
+ if (err_msg != NULL)
+ *err_msg = NULL;
+ return fv;
+ }
+ }
+ else {
+ if (err_msg != NULL) {
+ if (num <= 0x7f && g_ascii_isprint(num)) {
+ *err_msg = ws_strdup_printf("Character constant '%c' (0x%lx) cannot be converted to %s.",
+ (int)num, num, ftype_pretty_name(ftype));
+ }
+ else {
+ *err_msg = ws_strdup_printf("Character constant 0x%lx cannot be converted to %s.",
+ num, ftype_pretty_name(ftype));
+ }
+ }
+ }
+ fvalue_free(fv);
+ return NULL;
+}
+
+ftenum_t
+fvalue_type_ftenum(fvalue_t *fv)
+{
+ return fv->ftype->ftype;
+}
+
+const char*
+fvalue_type_name(const fvalue_t *fv)
+{
+ return fv->ftype->name;
+}
+
+
+size_t
+fvalue_length2(fvalue_t *fv)
+{
+ if (!fv->ftype->len) {
+ ws_critical("fv->ftype->len is NULL");
+ return 0;
+ }
+ return fv->ftype->len(fv);
+}
+
+char *
+fvalue_to_string_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display)
+{
+ if (fv->ftype->val_to_string_repr == NULL) {
+ /* no value-to-string-representation function, so the value cannot be represented */
+ return NULL;
+ }
+
+ return fv->ftype->val_to_string_repr(scope, fv, rtype, field_display);
+}
+
+enum ft_result
+fvalue_to_uinteger(const fvalue_t *fv, uint32_t *repr)
+{
+ uint64_t val;
+ enum ft_result res = fv->ftype->val_to_uinteger64(fv, &val);
+ if (res != FT_OK)
+ return res;
+ if (val > UINT32_MAX)
+ return FT_OVERFLOW;
+
+ *repr = (uint32_t)val;
+ return FT_OK;
+}
+
+enum ft_result
+fvalue_to_sinteger(const fvalue_t *fv, int32_t *repr)
+{
+ int64_t val;
+ enum ft_result res = fv->ftype->val_to_sinteger64(fv, &val);
+ if (res != FT_OK)
+ return res;
+ if (val > INT32_MAX)
+ return FT_OVERFLOW;
+
+ *repr = (int32_t)val;
+ return FT_OK;
+}
+
+enum ft_result
+fvalue_to_uinteger64(const fvalue_t *fv, uint64_t *repr)
+{
+ return fv->ftype->val_to_uinteger64(fv, repr);
+}
+
+enum ft_result
+fvalue_to_sinteger64(const fvalue_t *fv, int64_t *repr)
+{
+ return fv->ftype->val_to_sinteger64(fv, repr);
+}
+
+typedef struct {
+ fvalue_t *fv;
+ void *ptr;
+ bool slice_failure;
+} slice_data_t;
+
+static bool
+compute_drnode(size_t field_length, drange_node *drnode, size_t *offset_ptr, size_t *length_ptr)
+{
+ ssize_t start_offset;
+ ssize_t length = 0;
+ ssize_t end_offset = 0;
+ drange_node_end_t ending;
+
+ start_offset = drange_node_get_start_offset(drnode);
+ ending = drange_node_get_ending(drnode);
+
+ /* Check for negative start */
+ if (start_offset < 0) {
+ start_offset = field_length + start_offset;
+ if (start_offset < 0) {
+ return false;
+ }
+ }
+
+ /* Check the end type and set the length */
+
+ if (ending == DRANGE_NODE_END_T_TO_THE_END) {
+ length = field_length - start_offset;
+ if (length <= 0) {
+ return false;
+ }
+ }
+ else if (ending == DRANGE_NODE_END_T_LENGTH) {
+ length = drange_node_get_length(drnode);
+ if (start_offset + length > (int) field_length) {
+ return false;
+ }
+ }
+ else if (ending == DRANGE_NODE_END_T_OFFSET) {
+ end_offset = drange_node_get_end_offset(drnode);
+ if (end_offset < 0) {
+ end_offset = field_length + end_offset;
+ if (end_offset < start_offset) {
+ return false;
+ }
+ } else if (end_offset >= (int) field_length) {
+ return false;
+ }
+ length = end_offset - start_offset + 1;
+ }
+ else {
+ ws_assert_not_reached();
+ }
+
+ *offset_ptr = start_offset;
+ *length_ptr = length;
+ return true;
+}
+
+static void
+slice_func(void * data, void * user_data)
+{
+ drange_node *drnode = (drange_node *)data;
+ slice_data_t *slice_data = (slice_data_t *)user_data;
+ size_t start_offset;
+ size_t length = 0;
+ fvalue_t *fv;
+
+ if (slice_data->slice_failure) {
+ return;
+ }
+
+ fv = slice_data->fv;
+ if (!compute_drnode((unsigned)fvalue_length2(fv), drnode, &start_offset, &length)) {
+ slice_data->slice_failure = true;
+ return;
+ }
+
+ ws_assert(length > 0);
+ fv->ftype->slice(fv, slice_data->ptr, (unsigned)start_offset, (unsigned)length);
+}
+
+static fvalue_t *
+slice_string(fvalue_t *fv, drange_t *d_range)
+{
+ slice_data_t slice_data;
+ fvalue_t *new_fv;
+
+ slice_data.fv = fv;
+ slice_data.ptr = wmem_strbuf_create(NULL);
+ slice_data.slice_failure = false;
+
+ /* XXX - We could make some optimizations here based on
+ * drange_has_total_length() and
+ * drange_get_max_offset().
+ */
+
+ drange_foreach_drange_node(d_range, slice_func, &slice_data);
+
+ new_fv = fvalue_new(FT_STRING);
+ fvalue_set_strbuf(new_fv, slice_data.ptr);
+ return new_fv;
+}
+
+static fvalue_t *
+slice_bytes(fvalue_t *fv, drange_t *d_range)
+{
+ slice_data_t slice_data;
+ fvalue_t *new_fv;
+
+ slice_data.fv = fv;
+ slice_data.ptr = g_byte_array_new();
+ slice_data.slice_failure = false;
+
+ /* XXX - We could make some optimizations here based on
+ * drange_has_total_length() and
+ * drange_get_max_offset().
+ */
+
+ drange_foreach_drange_node(d_range, slice_func, &slice_data);
+
+ new_fv = fvalue_new(FT_BYTES);
+ fvalue_set_byte_array(new_fv, slice_data.ptr);
+ return new_fv;
+}
+
+/* Returns a new slice fvalue_t* if possible, otherwise NULL */
+fvalue_t*
+fvalue_slice(fvalue_t *fv, drange_t *d_range)
+{
+ if (FT_IS_STRING(fvalue_type_ftenum(fv))) {
+ return slice_string(fv, d_range);
+ }
+ return slice_bytes(fv, d_range);
+}
+
+void
+fvalue_set_bytes(fvalue_t *fv, GBytes *value)
+{
+ ws_assert(fv->ftype->ftype == FT_BYTES ||
+ fv->ftype->ftype == FT_UINT_BYTES ||
+ fv->ftype->ftype == FT_OID ||
+ fv->ftype->ftype == FT_REL_OID ||
+ fv->ftype->ftype == FT_SYSTEM_ID ||
+ fv->ftype->ftype == FT_AX25 ||
+ fv->ftype->ftype == FT_VINES ||
+ fv->ftype->ftype == FT_ETHER ||
+ fv->ftype->ftype == FT_FCWWN);
+ ws_assert(fv->ftype->set_value.set_value_bytes);
+ fv->ftype->set_value.set_value_bytes(fv, value);
+}
+
+void
+fvalue_set_byte_array(fvalue_t *fv, GByteArray *value)
+{
+ GBytes *bytes = g_byte_array_free_to_bytes(value);
+ fvalue_set_bytes(fv, bytes);
+ g_bytes_unref(bytes);
+}
+
+void
+fvalue_set_bytes_data(fvalue_t *fv, const void *data, size_t size)
+{
+ GBytes *bytes = g_bytes_new(data, size);
+ fvalue_set_bytes(fv, bytes);
+ g_bytes_unref(bytes);
+}
+
+void
+fvalue_set_fcwwn(fvalue_t *fv, const uint8_t *value)
+{
+ GBytes *bytes = g_bytes_new(value, FT_FCWWN_LEN);
+ fvalue_set_bytes(fv, bytes);
+ g_bytes_unref(bytes);
+}
+
+void
+fvalue_set_ax25(fvalue_t *fv, const uint8_t *value)
+{
+ GBytes *bytes = g_bytes_new(value, FT_AX25_ADDR_LEN);
+ fvalue_set_bytes(fv, bytes);
+ g_bytes_unref(bytes);
+}
+
+void
+fvalue_set_vines(fvalue_t *fv, const uint8_t *value)
+{
+ GBytes *bytes = g_bytes_new(value, FT_VINES_ADDR_LEN);
+ fvalue_set_bytes(fv, bytes);
+ g_bytes_unref(bytes);
+}
+
+void
+fvalue_set_ether(fvalue_t *fv, const uint8_t *value)
+{
+ GBytes *bytes = g_bytes_new(value, FT_ETHER_LEN);
+ fvalue_set_bytes(fv, bytes);
+ g_bytes_unref(bytes);
+}
+
+void
+fvalue_set_guid(fvalue_t *fv, const e_guid_t *value)
+{
+ ws_assert(fv->ftype->ftype == FT_GUID);
+ ws_assert(fv->ftype->set_value.set_value_guid);
+ fv->ftype->set_value.set_value_guid(fv, value);
+}
+
+void
+fvalue_set_time(fvalue_t *fv, const nstime_t *value)
+{
+ ws_assert(FT_IS_TIME(fv->ftype->ftype));
+ ws_assert(fv->ftype->set_value.set_value_time);
+ fv->ftype->set_value.set_value_time(fv, value);
+}
+
+void
+fvalue_set_string(fvalue_t *fv, const char *value)
+{
+ wmem_strbuf_t *buf = wmem_strbuf_new(NULL, value);
+ fvalue_set_strbuf(fv, buf);
+}
+
+void
+fvalue_set_strbuf(fvalue_t *fv, wmem_strbuf_t *value)
+{
+ if (value->allocator != NULL) {
+ /* XXX Can this condition be relaxed? */
+ ws_critical("Fvalue strbuf allocator must be NULL");
+ }
+ ws_assert(FT_IS_STRING(fv->ftype->ftype));
+ ws_assert(fv->ftype->set_value.set_value_strbuf);
+ fv->ftype->set_value.set_value_strbuf(fv, value);
+}
+
+void
+fvalue_set_protocol(fvalue_t *fv, tvbuff_t *value, const char *name, int length)
+{
+ ws_assert(fv->ftype->ftype == FT_PROTOCOL);
+ ws_assert(fv->ftype->set_value.set_value_protocol);
+ fv->ftype->set_value.set_value_protocol(fv, value, name, length);
+}
+
+void
+fvalue_set_uinteger(fvalue_t *fv, uint32_t value)
+{
+ ws_assert(fv->ftype->ftype == FT_IEEE_11073_SFLOAT ||
+ fv->ftype->ftype == FT_IEEE_11073_FLOAT ||
+ fv->ftype->ftype == FT_CHAR ||
+ fv->ftype->ftype == FT_UINT8 ||
+ fv->ftype->ftype == FT_UINT16 ||
+ fv->ftype->ftype == FT_UINT24 ||
+ fv->ftype->ftype == FT_UINT32 ||
+ fv->ftype->ftype == FT_IPXNET ||
+ fv->ftype->ftype == FT_FRAMENUM ||
+ fv->ftype->ftype == FT_IPv4);
+ ws_assert(fv->ftype->set_value.set_value_uinteger);
+ fv->ftype->set_value.set_value_uinteger(fv, value);
+}
+
+void
+fvalue_set_sinteger(fvalue_t *fv, int32_t value)
+{
+ ws_assert(fv->ftype->ftype == FT_INT8 ||
+ fv->ftype->ftype == FT_INT16 ||
+ fv->ftype->ftype == FT_INT24 ||
+ fv->ftype->ftype == FT_INT32);
+ ws_assert(fv->ftype->set_value.set_value_sinteger);
+ fv->ftype->set_value.set_value_sinteger(fv, value);
+}
+
+void
+fvalue_set_uinteger64(fvalue_t *fv, uint64_t value)
+{
+ ws_assert(fv->ftype->ftype == FT_UINT40 ||
+ fv->ftype->ftype == FT_UINT48 ||
+ fv->ftype->ftype == FT_UINT56 ||
+ fv->ftype->ftype == FT_UINT64 ||
+ fv->ftype->ftype == FT_BOOLEAN ||
+ fv->ftype->ftype == FT_EUI64);
+ ws_assert(fv->ftype->set_value.set_value_uinteger64);
+ fv->ftype->set_value.set_value_uinteger64(fv, value);
+}
+
+void
+fvalue_set_sinteger64(fvalue_t *fv, int64_t value)
+{
+ ws_assert(fv->ftype->ftype == FT_INT40 ||
+ fv->ftype->ftype == FT_INT48 ||
+ fv->ftype->ftype == FT_INT56 ||
+ fv->ftype->ftype == FT_INT64);
+ ws_assert(fv->ftype->set_value.set_value_sinteger64);
+ fv->ftype->set_value.set_value_sinteger64(fv, value);
+}
+
+void
+fvalue_set_floating(fvalue_t *fv, double value)
+{
+ ws_assert(fv->ftype->ftype == FT_FLOAT ||
+ fv->ftype->ftype == FT_DOUBLE);
+ ws_assert(fv->ftype->set_value.set_value_floating);
+ fv->ftype->set_value.set_value_floating(fv, value);
+}
+
+void
+fvalue_set_ipv6(fvalue_t *fv, const ws_in6_addr *value)
+{
+ ws_assert(fv->ftype->ftype == FT_IPv6);
+ ws_assert(fv->ftype->set_value.set_value_ipv6);
+ fv->ftype->set_value.set_value_ipv6(fv, value);
+}
+
+GBytes *
+fvalue_get_bytes(fvalue_t *fv)
+{
+ ws_assert(fv->ftype->ftype == FT_BYTES ||
+ fv->ftype->ftype == FT_UINT_BYTES ||
+ fv->ftype->ftype == FT_AX25 ||
+ fv->ftype->ftype == FT_VINES ||
+ fv->ftype->ftype == FT_ETHER ||
+ fv->ftype->ftype == FT_OID ||
+ fv->ftype->ftype == FT_REL_OID ||
+ fv->ftype->ftype == FT_SYSTEM_ID ||
+ fv->ftype->ftype == FT_FCWWN ||
+ fv->ftype->ftype == FT_IPv6);
+ ws_assert(fv->ftype->get_value.get_value_bytes);
+ return fv->ftype->get_value.get_value_bytes(fv);
+}
+
+size_t
+fvalue_get_bytes_size(fvalue_t *fv)
+{
+ GBytes *bytes = fvalue_get_bytes(fv);
+ size_t size = g_bytes_get_size(bytes);
+ g_bytes_unref(bytes);
+ return size;
+}
+
+const void *
+fvalue_get_bytes_data(fvalue_t *fv)
+{
+ GBytes *bytes = fvalue_get_bytes(fv);
+ const void *data = g_bytes_get_data(bytes, NULL);
+ g_bytes_unref(bytes);
+ return data;
+}
+
+const e_guid_t *
+fvalue_get_guid(fvalue_t *fv)
+{
+ ws_assert(fv->ftype->ftype == FT_GUID);
+ ws_assert(fv->ftype->get_value.get_value_guid);
+ return fv->ftype->get_value.get_value_guid(fv);
+}
+
+const nstime_t *
+fvalue_get_time(fvalue_t *fv)
+{
+ ws_assert(FT_IS_TIME(fv->ftype->ftype));
+ ws_assert(fv->ftype->get_value.get_value_time);
+ return fv->ftype->get_value.get_value_time(fv);
+}
+
+const char *
+fvalue_get_string(fvalue_t *fv)
+{
+ return wmem_strbuf_get_str(fvalue_get_strbuf(fv));
+}
+
+const wmem_strbuf_t *
+fvalue_get_strbuf(fvalue_t *fv)
+{
+ ws_assert(FT_IS_STRING(fv->ftype->ftype));
+ ws_assert(fv->ftype->get_value.get_value_strbuf);
+ return fv->ftype->get_value.get_value_strbuf(fv);
+}
+
+tvbuff_t *
+fvalue_get_protocol(fvalue_t *fv)
+{
+ ws_assert(fv->ftype->ftype == FT_PROTOCOL);
+ ws_assert(fv->ftype->get_value.get_value_protocol);
+ return fv->ftype->get_value.get_value_protocol(fv);
+}
+
+uint32_t
+fvalue_get_uinteger(fvalue_t *fv)
+{
+ ws_assert(fv->ftype->ftype == FT_IEEE_11073_SFLOAT ||
+ fv->ftype->ftype == FT_IEEE_11073_FLOAT ||
+ fv->ftype->ftype == FT_CHAR ||
+ fv->ftype->ftype == FT_UINT8 ||
+ fv->ftype->ftype == FT_UINT16 ||
+ fv->ftype->ftype == FT_UINT24 ||
+ fv->ftype->ftype == FT_UINT32 ||
+ fv->ftype->ftype == FT_IPXNET ||
+ fv->ftype->ftype == FT_FRAMENUM ||
+ fv->ftype->ftype == FT_IPv4);
+ ws_assert(fv->ftype->get_value.get_value_uinteger);
+ return fv->ftype->get_value.get_value_uinteger(fv);
+}
+
+int32_t
+fvalue_get_sinteger(fvalue_t *fv)
+{
+ ws_assert(fv->ftype->ftype == FT_INT8 ||
+ fv->ftype->ftype == FT_INT16 ||
+ fv->ftype->ftype == FT_INT24 ||
+ fv->ftype->ftype == FT_INT32);
+ ws_assert(fv->ftype->get_value.get_value_sinteger);
+ return fv->ftype->get_value.get_value_sinteger(fv);
+}
+
+uint64_t
+fvalue_get_uinteger64(fvalue_t *fv)
+{
+ ws_assert(fv->ftype->ftype == FT_UINT40 ||
+ fv->ftype->ftype == FT_UINT48 ||
+ fv->ftype->ftype == FT_UINT56 ||
+ fv->ftype->ftype == FT_UINT64 ||
+ fv->ftype->ftype == FT_BOOLEAN ||
+ fv->ftype->ftype == FT_EUI64);
+ ws_assert(fv->ftype->get_value.get_value_uinteger64);
+ return fv->ftype->get_value.get_value_uinteger64(fv);
+}
+
+int64_t
+fvalue_get_sinteger64(fvalue_t *fv)
+{
+ ws_assert(fv->ftype->ftype == FT_INT40 ||
+ fv->ftype->ftype == FT_INT48 ||
+ fv->ftype->ftype == FT_INT56 ||
+ fv->ftype->ftype == FT_INT64);
+ ws_assert(fv->ftype->get_value.get_value_sinteger64);
+ return fv->ftype->get_value.get_value_sinteger64(fv);
+}
+
+double
+fvalue_get_floating(fvalue_t *fv)
+{
+ ws_assert(fv->ftype->ftype == FT_FLOAT ||
+ fv->ftype->ftype == FT_DOUBLE);
+ ws_assert(fv->ftype->get_value.get_value_floating);
+ return fv->ftype->get_value.get_value_floating(fv);
+}
+
+WS_DLL_PUBLIC const ws_in6_addr *
+fvalue_get_ipv6(fvalue_t *fv)
+{
+ ws_assert(fv->ftype->ftype == FT_IPv6);
+ ws_assert(fv->ftype->get_value.get_value_ipv6);
+ return fv->ftype->get_value.get_value_ipv6(fv);
+}
+
+ft_bool_t
+fvalue_eq(const fvalue_t *a, const fvalue_t *b)
+{
+ int cmp;
+ enum ft_result res;
+
+ ws_assert(a->ftype->cmp_order);
+ res = a->ftype->cmp_order(a, b, &cmp);
+ if (res != FT_OK)
+ return -res;
+ return cmp == 0 ? FT_TRUE : FT_FALSE;
+}
+
+ft_bool_t
+fvalue_ne(const fvalue_t *a, const fvalue_t *b)
+{
+ int cmp;
+ enum ft_result res;
+
+ ws_assert(a->ftype->cmp_order);
+ res = a->ftype->cmp_order(a, b, &cmp);
+ if (res != FT_OK)
+ return -res;
+ return cmp != 0 ? FT_TRUE : FT_FALSE;
+}
+
+ft_bool_t
+fvalue_gt(const fvalue_t *a, const fvalue_t *b)
+{
+ int cmp;
+ enum ft_result res;
+
+ ws_assert(a->ftype->cmp_order);
+ res = a->ftype->cmp_order(a, b, &cmp);
+ if (res != FT_OK)
+ return -res;
+ return cmp > 0 ? FT_TRUE : FT_FALSE;
+}
+
+ft_bool_t
+fvalue_ge(const fvalue_t *a, const fvalue_t *b)
+{
+ int cmp;
+ enum ft_result res;
+
+ ws_assert(a->ftype->cmp_order);
+ res = a->ftype->cmp_order(a, b, &cmp);
+ if (res != FT_OK)
+ return -res;
+ return cmp >= 0 ? FT_TRUE : FT_FALSE;
+}
+
+ft_bool_t
+fvalue_lt(const fvalue_t *a, const fvalue_t *b)
+{
+ int cmp;
+ enum ft_result res;
+
+ ws_assert(a->ftype->cmp_order);
+ res = a->ftype->cmp_order(a, b, &cmp);
+ if (res != FT_OK)
+ return -res;
+ return cmp < 0 ? FT_TRUE : FT_FALSE;
+}
+
+ft_bool_t
+fvalue_le(const fvalue_t *a, const fvalue_t *b)
+{
+ int cmp;
+ enum ft_result res;
+
+ ws_assert(a->ftype->cmp_order);
+ res = a->ftype->cmp_order(a, b, &cmp);
+ if (res != FT_OK)
+ return -res;
+ return cmp <= 0 ? FT_TRUE : FT_FALSE;
+}
+
+ft_bool_t
+fvalue_contains(const fvalue_t *a, const fvalue_t *b)
+{
+ bool yes;
+ enum ft_result res;
+
+ ws_assert(a->ftype->cmp_contains);
+ res = a->ftype->cmp_contains(a, b, &yes);
+ if (res != FT_OK)
+ return -res;
+ return yes ? FT_TRUE : FT_FALSE;
+}
+
+ft_bool_t
+fvalue_matches(const fvalue_t *a, const ws_regex_t *re)
+{
+ bool yes;
+ enum ft_result res;
+
+ ws_assert(a->ftype->cmp_matches);
+ res = a->ftype->cmp_matches(a, re, &yes);
+ if (res != FT_OK)
+ return -res;
+ return yes ? FT_TRUE : FT_FALSE;
+}
+
+bool
+fvalue_is_zero(const fvalue_t *a)
+{
+ return a->ftype->is_zero(a);
+}
+
+bool
+fvalue_is_negative(const fvalue_t *a)
+{
+ return a->ftype->is_negative(a);
+}
+
+static fvalue_t *
+_fvalue_binop(FvalueBinaryOp op, const fvalue_t *a, const fvalue_t *b, char **err_msg)
+{
+ fvalue_t *result;
+
+ result = fvalue_new(a->ftype->ftype);
+ if (op(result, a, b, err_msg) != FT_OK) {
+ fvalue_free(result);
+ return NULL;
+ }
+ return result;
+}
+
+fvalue_t *
+fvalue_bitwise_and(const fvalue_t *a, const fvalue_t *b, char **err_msg)
+{
+ /* XXX - check compatibility of a and b */
+ ws_assert(a->ftype->bitwise_and);
+ return _fvalue_binop(a->ftype->bitwise_and, a, b, err_msg);
+}
+
+fvalue_t *
+fvalue_add(const fvalue_t *a, const fvalue_t *b, char **err_msg)
+{
+ /* XXX - check compatibility of a and b */
+ ws_assert(a->ftype->add);
+ return _fvalue_binop(a->ftype->add, a, b, err_msg);
+}
+
+fvalue_t *
+fvalue_subtract(const fvalue_t *a, const fvalue_t *b, char **err_msg)
+{
+ /* XXX - check compatibility of a and b */
+ ws_assert(a->ftype->subtract);
+ return _fvalue_binop(a->ftype->subtract, a, b, err_msg);
+}
+
+fvalue_t *
+fvalue_multiply(const fvalue_t *a, const fvalue_t *b, char **err_msg)
+{
+ /* XXX - check compatibility of a and b */
+ ws_assert(a->ftype->multiply);
+ return _fvalue_binop(a->ftype->multiply, a, b, err_msg);
+}
+
+fvalue_t *
+fvalue_divide(const fvalue_t *a, const fvalue_t *b, char **err_msg)
+{
+ /* XXX - check compatibility of a and b */
+ ws_assert(a->ftype->divide);
+ return _fvalue_binop(a->ftype->divide, a, b, err_msg);
+}
+
+fvalue_t *
+fvalue_modulo(const fvalue_t *a, const fvalue_t *b, char **err_msg)
+{
+ /* XXX - check compatibility of a and b */
+ ws_assert(a->ftype->modulo);
+ return _fvalue_binop(a->ftype->modulo, a, b, err_msg);
+}
+
+fvalue_t*
+fvalue_unary_minus(const fvalue_t *fv, char **err_msg)
+{
+ fvalue_t *result;
+
+ ws_assert(fv->ftype->unary_minus);
+
+ result = fvalue_new(fv->ftype->ftype);
+ if (fv->ftype->unary_minus(result, fv, err_msg) != FT_OK) {
+ fvalue_free(result);
+ return NULL;
+ }
+ return result;
+}
+
+unsigned
+fvalue_hash(const fvalue_t *fv)
+{
+ ws_assert(fv->ftype->hash);
+ return fv->ftype->hash(fv);
+}
+
+bool
+fvalue_equal(const fvalue_t *a, const fvalue_t *b)
+{
+ return fvalue_eq(a, b) == FT_TRUE;
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/epan/ftypes/ftypes.h b/epan/ftypes/ftypes.h
new file mode 100644
index 0000000..c8e81b3
--- /dev/null
+++ b/epan/ftypes/ftypes.h
@@ -0,0 +1,539 @@
+/** @file
+ * Definitions for field types
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+
+#ifndef __FTYPES_H__
+#define __FTYPES_H__
+
+#include <wireshark.h>
+
+#include <wsutil/regex.h>
+#include <epan/wmem_scopes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* field types */
+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*/
+ FT_UINT32,
+ FT_UINT40, /* really a UINT64, but displayed as 10 hex-digits if FD_HEX*/
+ FT_UINT48, /* really a UINT64, but displayed as 12 hex-digits if FD_HEX*/
+ FT_UINT56, /* really a UINT64, but displayed as 14 hex-digits if FD_HEX*/
+ FT_UINT64,
+ FT_INT8,
+ FT_INT16,
+ FT_INT24, /* same as for UINT24 */
+ FT_INT32,
+ FT_INT40, /* same as for UINT40 */
+ FT_INT48, /* same as for UINT48 */
+ FT_INT56, /* same as for UINT56 */
+ FT_INT64,
+ FT_IEEE_11073_SFLOAT,
+ FT_IEEE_11073_FLOAT,
+ FT_FLOAT,
+ FT_DOUBLE,
+ FT_ABSOLUTE_TIME,
+ FT_RELATIVE_TIME,
+ FT_STRING, /* counted string, with no null terminator */
+ FT_STRINGZ, /* null-terminated string */
+ FT_UINT_STRING, /* counted string, with count being the first part of the value */
+ FT_ETHER,
+ FT_BYTES,
+ FT_UINT_BYTES,
+ FT_IPv4,
+ FT_IPv6,
+ FT_IPXNET,
+ FT_FRAMENUM, /* a UINT32, but if selected lets you go to frame with that number */
+ FT_GUID, /* GUID, UUID */
+ FT_OID, /* OBJECT IDENTIFIER */
+ FT_EUI64,
+ FT_AX25,
+ FT_VINES,
+ FT_REL_OID, /* RELATIVE-OID */
+ FT_SYSTEM_ID,
+ FT_STRINGZPAD, /* null-padded string */
+ FT_FCWWN,
+ FT_STRINGZTRUNC, /* null-truncated string */
+ FT_NUM_TYPES /* last item number plus one */
+};
+
+#define FT_IS_INT32(ft) \
+ ((ft) == FT_INT8 || \
+ (ft) == FT_INT16 || \
+ (ft) == FT_INT24 || \
+ (ft) == FT_INT32)
+
+#define FT_IS_INT64(ft) \
+ ((ft) == FT_INT40 || \
+ (ft) == FT_INT48 || \
+ (ft) == FT_INT56 || \
+ (ft) == FT_INT64)
+
+#define FT_IS_INT(ft) (FT_IS_INT32(ft) || FT_IS_INT64(ft))
+
+#define FT_IS_UINT32(ft) \
+ ((ft) == FT_CHAR || \
+ (ft) == FT_UINT8 || \
+ (ft) == FT_UINT16 || \
+ (ft) == FT_UINT24 || \
+ (ft) == FT_UINT32 || \
+ (ft) == FT_FRAMENUM)
+
+#define FT_IS_UINT64(ft) \
+ ((ft) == FT_UINT40 || \
+ (ft) == FT_UINT48 || \
+ (ft) == FT_UINT56 || \
+ (ft) == FT_UINT64)
+
+#define FT_IS_UINT(ft) (FT_IS_UINT32(ft) || FT_IS_UINT64(ft))
+
+#define FT_IS_INTEGER(ft) (FT_IS_INT(ft) || FT_IS_UINT(ft))
+
+#define FT_IS_FLOATING(ft) ((ft) == FT_FLOAT || (ft) == FT_DOUBLE)
+
+#define FT_IS_TIME(ft) \
+ ((ft) == FT_ABSOLUTE_TIME || (ft) == FT_RELATIVE_TIME)
+
+#define FT_IS_STRING(ft) \
+ ((ft) == FT_STRING || (ft) == FT_STRINGZ || (ft) == FT_STRINGZPAD || \
+ (ft) == FT_STRINGZTRUNC || (ft) == FT_UINT_STRING)
+
+/* field types lengths */
+#define FT_ETHER_LEN 6
+#define FT_GUID_LEN 16
+#define FT_IPv4_LEN 4
+#define FT_IPv6_LEN 16
+#define FT_IPXNET_LEN 4
+#define FT_EUI64_LEN 8
+#define FT_AX25_ADDR_LEN 7
+#define FT_VINES_ADDR_LEN 6
+#define FT_FCWWN_LEN 8
+#define FT_VARINT_MAX_LEN 10 /* Because 64 / 7 = 9 and 64 % 7 = 1, get an uint64 varint need reads up to 10 bytes. */
+
+typedef enum ftenum ftenum_t;
+
+enum ft_framenum_type {
+ FT_FRAMENUM_NONE,
+ FT_FRAMENUM_REQUEST,
+ FT_FRAMENUM_RESPONSE,
+ FT_FRAMENUM_ACK,
+ FT_FRAMENUM_DUP_ACK,
+ FT_FRAMENUM_RETRANS_PREV,
+ FT_FRAMENUM_RETRANS_NEXT,
+ FT_FRAMENUM_NUM_TYPES /* last item number plus one */
+};
+
+typedef enum ft_framenum_type ft_framenum_type_t;
+
+struct _ftype_t;
+typedef struct _ftype_t ftype_t;
+
+enum ft_result {
+ FT_OK = 0,
+ FT_OVERFLOW,
+ FT_BADARG,
+ FT_ERROR, /* Generic. */
+};
+
+/*
+ * True, false or error if negative.
+ * Note that
+ * ft_bool == FT_FALSE
+ * and
+ * ft_bool != FT_TRUE
+ * are different results (three-state logic).
+ */
+typedef bool ft_bool_t;
+#define FT_TRUE 1
+#define FT_FALSE 0
+
+/* String representation types. */
+enum ftrepr {
+ FTREPR_DISPLAY,
+ FTREPR_DFILTER,
+ FTREPR_JSON,
+};
+
+typedef enum ftrepr ftrepr_t;
+
+/* Initialize the ftypes subsystem. Called once. */
+void
+ftypes_initialize(void);
+
+void
+ftypes_register_pseudofields(void);
+
+/* ---------------- FTYPE ----------------- */
+
+/* given two types, are they similar - for example can two
+ * duplicate fields be registered of these two types. */
+bool
+ftype_similar_types(const enum ftenum ftype_a, const enum ftenum ftype_b);
+
+/* Return a string representing the name of the type */
+WS_DLL_PUBLIC
+const char*
+ftype_name(ftenum_t ftype);
+
+/* Return a string presenting a "pretty" representation of the
+ * name of the type. The pretty name means more to the user than
+ * that "FT_*" name. */
+WS_DLL_PUBLIC
+const char*
+ftype_pretty_name(ftenum_t ftype);
+
+/* Returns length of field in packet, or 0 if not determinable/defined. */
+int
+ftype_wire_size(ftenum_t ftype);
+
+bool
+ftype_can_length(enum ftenum ftype);
+
+WS_DLL_PUBLIC
+bool
+ftype_can_slice(enum ftenum ftype);
+
+WS_DLL_PUBLIC
+bool
+ftype_can_eq(enum ftenum ftype);
+
+WS_DLL_PUBLIC
+bool
+ftype_can_cmp(enum ftenum ftype);
+
+bool
+ftype_can_bitwise_and(enum ftenum ftype);
+
+bool
+ftype_can_unary_minus(enum ftenum ftype);
+
+bool
+ftype_can_add(enum ftenum ftype);
+
+bool
+ftype_can_subtract(enum ftenum ftype);
+
+bool
+ftype_can_multiply(enum ftenum ftype);
+
+bool
+ftype_can_divide(enum ftenum ftype);
+
+bool
+ftype_can_modulo(enum ftenum ftype);
+
+WS_DLL_PUBLIC
+bool
+ftype_can_contains(enum ftenum ftype);
+
+WS_DLL_PUBLIC
+bool
+ftype_can_matches(enum ftenum ftype);
+
+WS_DLL_PUBLIC
+bool
+ftype_can_is_zero(enum ftenum ftype);
+
+WS_DLL_PUBLIC
+bool
+ftype_can_is_negative(enum ftenum ftype);
+
+WS_DLL_PUBLIC
+bool
+ftype_can_val_to_sinteger(enum ftenum ftype);
+
+WS_DLL_PUBLIC
+bool
+ftype_can_val_to_uinteger(enum ftenum ftype);
+
+WS_DLL_PUBLIC
+bool
+ftype_can_val_to_sinteger64(enum ftenum ftype);
+
+WS_DLL_PUBLIC
+bool
+ftype_can_val_to_uinteger64(enum ftenum ftype);
+
+/* ---------------- FVALUE ----------------- */
+
+#include <epan/ipv4.h>
+#include <epan/ipv6.h>
+#include <epan/guid-utils.h>
+
+#include <epan/tvbuff.h>
+#include <wsutil/nstime.h>
+#include <epan/dfilter/drange.h>
+
+typedef struct _protocol_value_t
+{
+ tvbuff_t *tvb;
+ int length;
+ char *proto_string;
+ bool tvb_is_private;
+} protocol_value_t;
+
+typedef struct _fvalue_t fvalue_t;
+
+fvalue_t*
+fvalue_new(ftenum_t ftype);
+
+fvalue_t*
+fvalue_dup(const fvalue_t *fv);
+
+void
+fvalue_init(fvalue_t *fv, ftenum_t ftype);
+
+void
+fvalue_cleanup(fvalue_t *fv);
+
+void
+fvalue_free(fvalue_t *fv);
+
+WS_DLL_PUBLIC
+fvalue_t*
+fvalue_from_literal(ftenum_t ftype, const char *s, bool allow_partial_value, char **err_msg);
+
+/* String *MUST* be null-terminated. Length is optional (pass zero) and does not include the null terminator. */
+fvalue_t*
+fvalue_from_string(ftenum_t ftype, const char *s, size_t len, char **err_msg);
+
+fvalue_t*
+fvalue_from_charconst(ftenum_t ftype, unsigned long number, char **err_msg);
+
+/* Creates the string representation of the field value.
+ * Memory for the buffer is allocated based on wmem allocator
+ * provided.
+ *
+ * field_display parameter should be a BASE_ value (enum field_display_e)
+ * BASE_NONE should be used if field information isn't available.
+ *
+ * Returns NULL if the string cannot be represented in the given rtype.*/
+WS_DLL_PUBLIC char *
+fvalue_to_string_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display);
+
+#define fvalue_to_debug_repr(scope, fv) \
+ fvalue_to_string_repr(scope, fv, FTREPR_DFILTER, 0)
+
+WS_DLL_PUBLIC enum ft_result
+fvalue_to_uinteger(const fvalue_t *fv, uint32_t *repr);
+
+WS_DLL_PUBLIC enum ft_result
+fvalue_to_sinteger(const fvalue_t *fv, int32_t *repr);
+
+WS_DLL_PUBLIC enum ft_result
+fvalue_to_uinteger64(const fvalue_t *fv, uint64_t *repr);
+
+WS_DLL_PUBLIC enum ft_result
+fvalue_to_sinteger64(const fvalue_t *fv, int64_t *repr);
+
+WS_DLL_PUBLIC ftenum_t
+fvalue_type_ftenum(fvalue_t *fv);
+
+const char*
+fvalue_type_name(const fvalue_t *fv);
+
+/* GBytes reference count is automatically incremented. */
+void
+fvalue_set_bytes(fvalue_t *fv, GBytes *value);
+
+void
+fvalue_set_byte_array(fvalue_t *fv, GByteArray *value);
+
+void
+fvalue_set_bytes_data(fvalue_t *fv, const void *data, size_t size);
+
+void
+fvalue_set_fcwwn(fvalue_t *fv, const uint8_t *value);
+
+void
+fvalue_set_ax25(fvalue_t *fv, const uint8_t *value);
+
+void
+fvalue_set_vines(fvalue_t *fv, const uint8_t *value);
+
+void
+fvalue_set_ether(fvalue_t *fv, const uint8_t *value);
+
+void
+fvalue_set_guid(fvalue_t *fv, const e_guid_t *value);
+
+void
+fvalue_set_time(fvalue_t *fv, const nstime_t *value);
+
+void
+fvalue_set_string(fvalue_t *fv, const char *value);
+
+void
+fvalue_set_strbuf(fvalue_t *fv, wmem_strbuf_t *value);
+
+void
+fvalue_set_protocol(fvalue_t *fv, tvbuff_t *value, const char *name, int length);
+
+void
+fvalue_set_uinteger(fvalue_t *fv, uint32_t value);
+
+void
+fvalue_set_sinteger(fvalue_t *fv, int32_t value);
+
+void
+fvalue_set_uinteger64(fvalue_t *fv, uint64_t value);
+
+void
+fvalue_set_sinteger64(fvalue_t *fv, int64_t value);
+
+void
+fvalue_set_floating(fvalue_t *fv, double value);
+
+void
+fvalue_set_ipv6(fvalue_t *fv, const ws_in6_addr *value);
+
+/* GBytes reference count is automatically incremented. */
+WS_DLL_PUBLIC
+GBytes *
+fvalue_get_bytes(fvalue_t *fv);
+
+WS_DLL_PUBLIC
+size_t
+fvalue_get_bytes_size(fvalue_t *fv);
+
+/* Same as fvalue_length() */
+WS_DLL_PUBLIC
+const void *
+fvalue_get_bytes_data(fvalue_t *fv);
+
+WS_DLL_PUBLIC
+const e_guid_t *
+fvalue_get_guid(fvalue_t *fv);
+
+WS_DLL_PUBLIC
+const nstime_t *
+fvalue_get_time(fvalue_t *fv);
+
+WS_DLL_PUBLIC
+const char *
+fvalue_get_string(fvalue_t *fv);
+
+WS_DLL_PUBLIC
+const wmem_strbuf_t *
+fvalue_get_strbuf(fvalue_t *fv);
+
+WS_DLL_PUBLIC
+tvbuff_t *
+fvalue_get_protocol(fvalue_t *fv);
+
+WS_DLL_PUBLIC uint32_t
+fvalue_get_uinteger(fvalue_t *fv);
+
+WS_DLL_PUBLIC int32_t
+fvalue_get_sinteger(fvalue_t *fv);
+
+WS_DLL_PUBLIC
+uint64_t
+fvalue_get_uinteger64(fvalue_t *fv);
+
+WS_DLL_PUBLIC
+int64_t
+fvalue_get_sinteger64(fvalue_t *fv);
+
+WS_DLL_PUBLIC double
+fvalue_get_floating(fvalue_t *fv);
+
+WS_DLL_PUBLIC const ws_in6_addr *
+fvalue_get_ipv6(fvalue_t *fv);
+
+ft_bool_t
+fvalue_eq(const fvalue_t *a, const fvalue_t *b);
+
+ft_bool_t
+fvalue_ne(const fvalue_t *a, const fvalue_t *b);
+
+ft_bool_t
+fvalue_gt(const fvalue_t *a, const fvalue_t *b);
+
+ft_bool_t
+fvalue_ge(const fvalue_t *a, const fvalue_t *b);
+
+ft_bool_t
+fvalue_lt(const fvalue_t *a, const fvalue_t *b);
+
+ft_bool_t
+fvalue_le(const fvalue_t *a, const fvalue_t *b);
+
+ft_bool_t
+fvalue_contains(const fvalue_t *a, const fvalue_t *b);
+
+ft_bool_t
+fvalue_matches(const fvalue_t *a, const ws_regex_t *re);
+
+bool
+fvalue_is_zero(const fvalue_t *a);
+
+bool
+fvalue_is_negative(const fvalue_t *a);
+
+size_t
+fvalue_length2(fvalue_t *fv);
+
+fvalue_t*
+fvalue_slice(fvalue_t *fv, drange_t *dr);
+
+fvalue_t*
+fvalue_bitwise_and(const fvalue_t *a, const fvalue_t *b, char **err_msg);
+
+fvalue_t*
+fvalue_unary_minus(const fvalue_t *fv, char **err_msg);
+
+fvalue_t*
+fvalue_add(const fvalue_t *a, const fvalue_t *b, char **err_msg);
+
+fvalue_t*
+fvalue_subtract(const fvalue_t *a, const fvalue_t *b, char **err_msg);
+
+fvalue_t*
+fvalue_multiply(const fvalue_t *a, const fvalue_t *b, char **err_msg);
+
+fvalue_t*
+fvalue_divide(const fvalue_t *a, const fvalue_t *b, char **err_msg);
+
+fvalue_t*
+fvalue_modulo(const fvalue_t *a, const fvalue_t *b, char **err_msg);
+
+unsigned
+fvalue_hash(const fvalue_t *fv);
+
+bool
+fvalue_equal(const fvalue_t *a, const fvalue_t *b);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __FTYPES_H__ */
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */