summaryrefslogtreecommitdiffstats
path: root/epan/ftypes/ftype-ieee-11073-float.c
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/ftype-ieee-11073-float.c
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/ftype-ieee-11073-float.c')
-rw-r--r--epan/ftypes/ftype-ieee-11073-float.c1058
1 files changed, 1058 insertions, 0 deletions
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:
+ */