diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index fa0676286e..2f61110dd8 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -1518,6 +1518,7 @@ set(FTYPE_FILES ftypes/ftypes.c ftypes/ftype-bytes.c ftypes/ftype-double.c + ftypes/ftype-ieee-11073-float.c ftypes/ftype-integer.c ftypes/ftype-ipv4.c ftypes/ftype-ipv6.c diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c index 524accc2aa..8a0d827d77 100644 --- a/epan/dfilter/semcheck.c +++ b/epan/dfilter/semcheck.c @@ -68,6 +68,8 @@ compatible_ftypes(ftenum_t a, ftenum_t b) case FT_DOUBLE: /* XXX - should be able to compare with INT */ case FT_ABSOLUTE_TIME: case FT_RELATIVE_TIME: + case FT_IEEE_11073_SFLOAT: + case FT_IEEE_11073_FLOAT: case FT_IPv4: case FT_IPv6: case FT_IPXNET: @@ -202,6 +204,8 @@ mk_fvalue_from_val_string(dfwork_t *dfw, header_field_info *hfinfo, char *s) case FT_PROTOCOL: case FT_FLOAT: case FT_DOUBLE: + case FT_IEEE_11073_SFLOAT: + case FT_IEEE_11073_FLOAT: case FT_ABSOLUTE_TIME: case FT_RELATIVE_TIME: case FT_IPv4: @@ -351,6 +355,8 @@ is_bytes_type(enum ftenum type) case FT_PROTOCOL: case FT_FLOAT: case FT_DOUBLE: + case FT_IEEE_11073_SFLOAT: + case FT_IEEE_11073_FLOAT: case FT_ABSOLUTE_TIME: case FT_RELATIVE_TIME: case FT_IPv4: diff --git a/epan/dissectors/packet-btatt.c b/epan/dissectors/packet-btatt.c index 6b3fe9f12a..cdeb117581 100644 --- a/epan/dissectors/packet-btatt.c +++ b/epan/dissectors/packet-btatt.c @@ -8453,16 +8453,14 @@ proto_register_btatt(void) FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_glucose_measurement_glucose_concentration_kg_per_l, {"Glucose Concentration [kg/l]", "btatt.glucose_measurement.glucose_concentration.kg_per_l", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_glucose_measurement_glucose_concentration_mol_per_l, {"Glucose Concentration [mol/l]", "btatt.glucose_measurement.glucose_concentration.mol_per_l", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, {&hf_btatt_glucose_measurement_type_and_sample_location, @@ -8710,16 +8708,14 @@ proto_register_btatt(void) FT_UINT8, BASE_HEX, VALS(temperature_measurement_flags_temperature_unit_vals), 0x01, NULL, HFILL} }, -/* TODO: This field should be FLOAT: IEEE-11073 32-bit SFLOAT */ {&hf_btatt_temperature_measurement_value_celsius, {"Value [Celsius]", "btatt.temperature_measurement.value.celsius", - FT_UINT32, BASE_HEX, NULL, 0x00, + FT_IEEE_11073_FLOAT, BASE_FLOAT, NULL, 0x00, NULL, HFILL} }, -/* TODO: This field should be FLOAT: IEEE-11073 32-bit SFLOAT */ {&hf_btatt_temperature_measurement_value_fahrenheit, {"Value [Fahrenheit]", "btatt.temperature_measurement.value.fahrenheit", - FT_UINT32, BASE_HEX, NULL, 0x00, + FT_IEEE_11073_FLOAT, BASE_FLOAT, NULL, 0x00, NULL, HFILL} }, {&hf_btatt_temperature_measurement_timestamp, @@ -8792,10 +8788,9 @@ proto_register_btatt(void) FT_UINT8, BASE_HEX, VALS(glucose_measurement_context_carbohydrate_id_vals), 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_glucose_measurement_context_carbohydrate_kg, {"Carbohydrate [kg]", "btatt.glucose_measurement_context.carbohydrate.kg", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, {&hf_btatt_glucose_measurement_context_meal, @@ -8833,22 +8828,19 @@ proto_register_btatt(void) FT_UINT8, BASE_HEX, VALS(glucose_measurement_context_medication_id_vals), 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_glucose_measurement_context_medication_l, {"Medication [l]", "btatt.glucose_measurement_context.medication.l", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_glucose_measurement_context_medication_kg, {"Medication [kg]", "btatt.glucose_measurement_context.medication.kg", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_glucose_measurement_context_hba1c, {"HbA1c", "btatt.glucose_measurement_context.hba1c", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, {&hf_btatt_blood_pressure_measurement_flags, @@ -8886,40 +8878,34 @@ proto_register_btatt(void) FT_UINT8, BASE_HEX, VALS(blood_pressure_measurement_unit_vals), 0x01, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_blood_pressure_measurement_compound_value_systolic_kpa, {"Systolic [kPa]", "btatt.blood_pressure_measurement.compound_value.systolic.kpa", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_blood_pressure_measurement_compound_value_diastolic_kpa, {"Diastolic [kPa]", "btatt.blood_pressure_measurement.compound_value.diastolic.kpa", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_blood_pressure_measurement_compound_value_mean_arterial_pressure_kpa, {"Arterial Pressure [kPa]", "btatt.blood_pressure_measurement.compound_value.arterial_pressure.kpa", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_blood_pressure_measurement_compound_value_systolic_mmhg, {"Systolic [mmHg]", "btatt.blood_pressure_measurement.compound_value.systolic.mmhg", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_blood_pressure_measurement_compound_value_diastolic_mmhg, {"Diastolic [mmHg]", "btatt.blood_pressure_measurement.compound_value.diastolic.mmhg", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_blood_pressure_measurement_compound_value_mean_arterial_pressure_mmhg, {"Arterial Pressure [mmHg]", "btatt.blood_pressure_measurement.compound_value.arterial_pressure.mmhg", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, {&hf_btatt_blood_pressure_measurement_timestamp, @@ -8927,10 +8913,9 @@ proto_register_btatt(void) FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_blood_pressure_measurement_pulse_rate, {"Pulse Rate", "btatt.blood_pressure_measurement.pulse_rate", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, {&hf_btatt_blood_pressure_measurement_user_id, @@ -10315,10 +10300,9 @@ proto_register_btatt(void) FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_cgm_measurement_glucose_concentration, {"Glucose Concentration", "btatt.cgm_measurement.glucose_concentration", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, {&hf_btatt_cgm_measurement_time_offset, @@ -10456,16 +10440,14 @@ proto_register_btatt(void) FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_cgm_measurement_trend_information, {"Trend Information", "btatt.cgm_measurement.trend_information", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_cgm_measurement_quality, {"Quality", "btatt.cgm_measurement.quality", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, {&hf_btatt_cgm_e2e_crc, @@ -10618,10 +10600,9 @@ proto_register_btatt(void) FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_cgm_specific_ops_control_point_calibration_glucose_concentration, {"Calibration Glucose Concentration", "btatt.cgm_specific_ops_control_point.operand.calibration_glucose_concentration", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, {&hf_btatt_cgm_specific_ops_control_point_calibration_time, @@ -10669,16 +10650,14 @@ proto_register_btatt(void) FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_cgm_specific_ops_control_point_operand_alert_level, {"Alert Level [mg/dL]", "btatt.cgm_specific_ops_control_point.operand.alert_level", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, -/* TODO: This field should be SFLOAT: IEEE-11073 16-bit SFLOAT */ {&hf_btatt_cgm_specific_ops_control_point_operand_alert_level_rate, {"Alert Level Rate [mg/dL/min]", "btatt.cgm_specific_ops_control_point.operand.alert_level_rate", - FT_UINT16, BASE_HEX, NULL, 0x0, + FT_IEEE_11073_SFLOAT, BASE_FLOAT, NULL, 0x0, NULL, HFILL} }, {&hf_btatt_cgm_specific_ops_control_point_request_opcode, diff --git a/epan/ftypes/Makefile.common b/epan/ftypes/Makefile.common index 222949b8bb..dba0bf6860 100644 --- a/epan/ftypes/Makefile.common +++ b/epan/ftypes/Makefile.common @@ -30,6 +30,7 @@ NONGENERATED_C_FILES = \ ftypes.c \ ftype-bytes.c \ ftype-double.c \ + ftype-ieee-11073-float.c \ ftype-integer.c \ ftype-ipv4.c \ ftype-ipv6.c \ diff --git a/epan/ftypes/ftype-ieee-11073-float.c b/epan/ftypes/ftype-ieee-11073-float.c new file mode 100644 index 0000000000..1a99b84367 --- /dev/null +++ b/epan/ftypes/ftype-ieee-11073-float.c @@ -0,0 +1,1561 @@ +/* IEEE 11073 FLOATs + * + * 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 + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#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 gboolean +sfloat_ieee_11073_val_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg _U_) +{ + const char *i_char = s; + char c; + guint8 mantissa_sign = 0; + guint32 mantissa = 0; + gint8 exponent = 0; + gboolean fraction_mode = FALSE; + const guint16 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 > (guint32) 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 <= (guint32) 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 > (guint32) 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 void +sfloat_ieee_11073_val_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_, char *buf) +{ + gint8 exponent; + guint16 mantissa; + guint16 mantissa_sign; + guint32 offset = 0; + gchar mantissa_str[5]; + guint8 mantissa_digits; + + if (fv->value.sfloat_ieee_11073 >= 0x07FE && fv->value.sfloat_ieee_11073 <= 0x0802) { + switch (fv->value.sfloat_ieee_11073) { + case SFLOAT_VALUE_INFINITY_PLUS: + g_snprintf(buf, 10, "+INFINITY"); + break; + case SFLOAT_VALUE_NAN: + g_snprintf(buf, 4, "NaN"); + break; + case SFLOAT_VALUE_NRES: + g_snprintf(buf, 5, "NRes"); + break; + case SFLOAT_VALUE_RFU: + g_snprintf(buf, 4, "RFU"); + break; + case SFLOAT_VALUE_INFINITY_MINUS: + g_snprintf(buf, 10, "-INFINITY"); + break; + } + } + + exponent = fv->value.sfloat_ieee_11073 >> 12; + if (exponent & 0x8) + exponent |= 0xF0; /* It is signed (4bits), so make it signed in gint8 */ + mantissa = fv->value.sfloat_ieee_11073 & 0x07FF; + mantissa_sign = (fv->value.sfloat_ieee_11073 & 0x0800); + if (mantissa_sign) + mantissa = -((gint16)mantissa | 0xF800); + + if (mantissa == 0) { + buf[0] = '0'; + buf[1] = '\0'; + + return; + } + + if (mantissa_sign) { + buf[0] = '-'; + offset += 1; + } + + mantissa_digits = g_snprintf(mantissa_str, 5, "%u", mantissa); + + 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'; +} + +static int +sfloat_ieee_11073_val_repr_len(fvalue_t *fv _U_, ftrepr_t rtype _U_, int field_display _U_) +{ + /* Predefinied: +INFINITY, -INFINITY, RFU, NRes, NaN */ + /* 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) */ + /* NOTE: Possible memory optimization: compute length, but watch out for speed */ + return 13; +} + +static void +sfloat_ieee_11073_value_set(fvalue_t *fv, guint32 value) +{ + fv->value.sfloat_ieee_11073 = (guint16) value; +} + +static guint32 +sfloat_ieee_11073_value_get(fvalue_t *fv) +{ + return (guint32) fv->value.sfloat_ieee_11073; +} + +static guint16 sfloat_to_normal_form(guint16 value) +{ + gint8 exponent; + guint16 mantissa; + guint8 mantissa_sign; + + if (value >= 0x07FE && value <= 0x0802) /* Save special values */ + return value; + + mantissa = value & 0x07FF; + if (value & 0x0800) { + mantissa = -((gint16)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 gboolean +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 gboolean +sfloat_ieee_11073_cmp_ne(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 gboolean +sfloat_ieee_11073_cmp_gt(const fvalue_t *a, const fvalue_t *b) +{ + guint16 a_norm; + guint16 b_norm; + gint16 a_norm_mantissa; + gint16 b_norm_mantissa; + gint8 a_norm_exponent; + gint8 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_MINUS: + return FALSE; + case SFLOAT_VALUE_INFINITY_PLUS: + switch (b_norm) { + case SFLOAT_VALUE_NAN: + case SFLOAT_VALUE_NRES: + case SFLOAT_VALUE_RFU: + case SFLOAT_VALUE_INFINITY_PLUS: /* Dead, informative case */ + return FALSE; + case SFLOAT_VALUE_INFINITY_MINUS: + default: + return TRUE; + } + } + + a_norm_mantissa = a_norm & 0x0FFF; + b_norm_mantissa = b_norm & 0x0FFF; + if (a_norm & 0x0800) + a_norm_mantissa |= 0xF000; + + if (b_norm & 0x0800) + b_norm_mantissa |= 0xF000; + + 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) { + guint8 exponent_difference; + + exponent_difference = b_norm_exponent - a_norm_exponent; + + if (exponent_difference >= 4) + return FALSE; + + while (exponent_difference--) { + b_norm_mantissa *= 10; + } + } else { + guint8 exponent_difference; + + exponent_difference = a_norm_exponent - b_norm_exponent; + + if (exponent_difference >= 4) + return TRUE; + + while (exponent_difference--) { + a_norm_mantissa *= 10; + } + } + + if (a_norm_mantissa > b_norm_mantissa) + return TRUE; + + return FALSE; +} + +static gboolean +sfloat_ieee_11073_cmp_ge(const fvalue_t *a, const fvalue_t *b) +{ + guint16 a_norm; + guint16 b_norm; + gint16 a_norm_mantissa; + gint16 b_norm_mantissa; + gint8 a_norm_exponent; + gint8 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 TRUE; + + switch (a_norm) { + case SFLOAT_VALUE_NAN: + case SFLOAT_VALUE_NRES: + case SFLOAT_VALUE_RFU: + case SFLOAT_VALUE_INFINITY_MINUS: + return FALSE; + case SFLOAT_VALUE_INFINITY_PLUS: + switch (b_norm) { + case SFLOAT_VALUE_NAN: + case SFLOAT_VALUE_NRES: + case SFLOAT_VALUE_RFU: + case SFLOAT_VALUE_INFINITY_PLUS: /* Dead, informative case */ + return FALSE; + case SFLOAT_VALUE_INFINITY_MINUS: + default: + return TRUE; + } + } + + a_norm_mantissa = a_norm & 0x0FFF; + b_norm_mantissa = b_norm & 0x0FFF; + if (a_norm & 0x0800) + a_norm_mantissa |= 0xF000; + + if (b_norm & 0x0800) + b_norm_mantissa |= 0xF000; + + 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) { + guint8 exponent_difference; + + exponent_difference = b_norm_exponent - a_norm_exponent; + + if (exponent_difference >= 4) + return FALSE; + + while (exponent_difference--) { + b_norm_mantissa *= 10; + } + } else { + guint8 exponent_difference; + + exponent_difference = a_norm_exponent - b_norm_exponent; + + if (exponent_difference >= 4) + return TRUE; + + while (exponent_difference--) { + a_norm_mantissa *= 10; + } + } + + if (a_norm_mantissa > b_norm_mantissa) + return TRUE; + + return FALSE; +} + +static gboolean +sfloat_ieee_11073_cmp_lt(const fvalue_t *a, const fvalue_t *b) +{ + guint16 a_norm; + guint16 b_norm; + gint16 a_norm_mantissa; + gint16 b_norm_mantissa; + gint8 a_norm_exponent; + gint8 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) { + guint8 exponent_difference; + + exponent_difference = b_norm_exponent - a_norm_exponent; + + if (exponent_difference >= 4) + return TRUE; + + while (exponent_difference--) { + b_norm_mantissa *= 10; + } + } else { + guint8 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 gboolean +sfloat_ieee_11073_cmp_le(const fvalue_t *a, const fvalue_t *b) +{ + guint16 a_norm; + guint16 b_norm; + gint16 a_norm_mantissa; + gint16 b_norm_mantissa; + gint8 a_norm_exponent; + gint8 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 TRUE; + + 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 |= 0xF000; + + if (b_norm & 0x0800) + b_norm_mantissa |= 0xF000; + + 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) { + guint8 exponent_difference; + + exponent_difference = b_norm_exponent - a_norm_exponent; + + if (exponent_difference >= 4) + return TRUE; + + while (exponent_difference--) { + b_norm_mantissa *= 10; + } + } else { + guint8 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 gboolean +sfloat_ieee_11073_cmp_bitwise_and(const fvalue_t *a, const fvalue_t *b) +{ + return ((a->value.uinteger & b->value.uinteger) != 0); +} + +/*============================================================================*/ + +static void +float_ieee_11073_fvalue_new(fvalue_t *fv) +{ + fv->value.float_ieee_11073 = 0x0000; +} + +static gboolean +float_ieee_11073_val_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg _U_) +{ + const char *i_char = s; + char c; + guint8 mantissa_sign = 0; + guint32 mantissa = 0; + gint16 exponent = 0; + gboolean fraction_mode = FALSE; + const guint32 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 void +float_ieee_11073_val_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_, char *buf) +{ + gint8 exponent; + guint32 mantissa; + guint32 mantissa_sign; + guint32 offset = 0; + gchar mantissa_str[8]; + guint8 mantissa_digits; + + if (fv->value.float_ieee_11073 >= 0x007FFFFE && fv->value.float_ieee_11073 <= 0x00800002) { + switch (fv->value.float_ieee_11073) { + case FLOAT_VALUE_INFINITY_PLUS: + g_snprintf(buf, 10, "+INFINITY"); + break; + case FLOAT_VALUE_NAN: + g_snprintf(buf, 4, "NaN"); + break; + case FLOAT_VALUE_NRES: + g_snprintf(buf, 5, "NRes"); + break; + case FLOAT_VALUE_RFU: + g_snprintf(buf, 4, "RFU"); + break; + case FLOAT_VALUE_INFINITY_MINUS: + g_snprintf(buf, 10, "-INFINITY"); + break; + } + } + + 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 = (guint32)(-((gint32)(mantissa | 0xFF000000))); + + if (mantissa == 0) { + buf[0] = '0'; + buf[1] = '\0'; + + return; + } + + if (mantissa_sign) { + buf[0] = '-'; + offset += 1; + } + + mantissa_digits = g_snprintf(mantissa_str, 9, "%u", mantissa); + + 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'; +} + +static int +float_ieee_11073_val_repr_len(fvalue_t *fv _U_, ftrepr_t rtype _U_, int field_display _U_) +{ + /* Predefinied: +INFINITY, -INFINITY, RFU, NRes, NaN */ + /* Longest Signed Nonfloat Number: -8388608*(10^-128) (1 character for sign, 7 for mantisa digits, 127 zeros, 1 character for NULL) */ + /* NOTE: Possible memory optimization: compute length, but watch out for speed */ + return 136; +} + +static void +float_ieee_11073_value_set(fvalue_t *fv, guint32 value) +{ + fv->value.float_ieee_11073 = value; +} + +static guint32 +float_ieee_11073_value_get(fvalue_t *fv) +{ + return fv->value.float_ieee_11073; +} + +static guint32 float_to_normal_form(guint32 value) +{ + gint8 exponent; + guint16 mantissa; + guint8 mantissa_sign; + + if (value >= 0x007FFFFE && value <= 0x00800002) /* Save special values */ + return value; + + mantissa = value & 0x907FFFFF; + if (value & 0x00800000) { + mantissa = (guint32)(-((gint32)(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 gboolean +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 gboolean +float_ieee_11073_cmp_ne(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 gboolean +float_ieee_11073_cmp_gt(const fvalue_t *a, const fvalue_t *b) +{ + guint32 a_norm; + guint32 b_norm; + gint32 a_norm_mantissa; + gint32 b_norm_mantissa; + gint8 a_norm_exponent; + gint8 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_MINUS: + return FALSE; + case FLOAT_VALUE_INFINITY_PLUS: + switch (b_norm) { + case FLOAT_VALUE_NAN: + case FLOAT_VALUE_NRES: + case FLOAT_VALUE_RFU: + case FLOAT_VALUE_INFINITY_PLUS: /* Dead, informative case */ + return FALSE; + case FLOAT_VALUE_INFINITY_MINUS: + 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) { + guint8 exponent_difference; + + exponent_difference = b_norm_exponent - a_norm_exponent; + + if (exponent_difference >= 7) + return FALSE; + + while (exponent_difference--) { + b_norm_mantissa *= 10; + } + } else { + guint8 exponent_difference; + + exponent_difference = a_norm_exponent - b_norm_exponent; + + if (exponent_difference >= 7) + return TRUE; + + while (exponent_difference--) { + a_norm_mantissa *= 10; + } + } + + if (a_norm_mantissa > b_norm_mantissa) + return TRUE; + + return FALSE; +} + +static gboolean +float_ieee_11073_cmp_ge(const fvalue_t *a, const fvalue_t *b) +{ + guint32 a_norm; + guint32 b_norm; + gint32 a_norm_mantissa; + gint32 b_norm_mantissa; + gint8 a_norm_exponent; + gint8 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 TRUE; + + switch (a_norm) { + case FLOAT_VALUE_NAN: + case FLOAT_VALUE_NRES: + case FLOAT_VALUE_RFU: + case FLOAT_VALUE_INFINITY_MINUS: + return FALSE; + case FLOAT_VALUE_INFINITY_PLUS: + switch (b_norm) { + case FLOAT_VALUE_NAN: + case FLOAT_VALUE_NRES: + case FLOAT_VALUE_RFU: + case FLOAT_VALUE_INFINITY_PLUS: /* Dead, informative case */ + return FALSE; + case FLOAT_VALUE_INFINITY_MINUS: + 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) { + guint8 exponent_difference; + + exponent_difference = b_norm_exponent - a_norm_exponent; + + if (exponent_difference >= 7) + return FALSE; + + while (exponent_difference--) { + b_norm_mantissa *= 10; + } + } else { + guint8 exponent_difference; + + exponent_difference = a_norm_exponent - b_norm_exponent; + + if (exponent_difference >= 7) + return TRUE; + + while (exponent_difference--) { + a_norm_mantissa *= 10; + } + } + + if (a_norm_mantissa > b_norm_mantissa) + return TRUE; + + return FALSE; +} + +static gboolean +float_ieee_11073_cmp_lt(const fvalue_t *a, const fvalue_t *b) +{ + guint32 a_norm; + guint32 b_norm; + gint32 a_norm_mantissa; + gint32 b_norm_mantissa; + gint8 a_norm_exponent; + gint8 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) { + guint8 exponent_difference; + + exponent_difference = b_norm_exponent - a_norm_exponent; + + if (exponent_difference >= 7) + return TRUE; + + while (exponent_difference--) { + b_norm_mantissa *= 10; + } + } else { + guint8 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 gboolean +float_ieee_11073_cmp_le(const fvalue_t *a, const fvalue_t *b) +{ + guint32 a_norm; + guint32 b_norm; + gint32 a_norm_mantissa; + gint32 b_norm_mantissa; + gint8 a_norm_exponent; + gint8 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 TRUE; + + 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) { + guint8 exponent_difference; + + exponent_difference = b_norm_exponent - a_norm_exponent; + + if (exponent_difference >= 7) + return TRUE; + + while (exponent_difference--) { + b_norm_mantissa *= 10; + } + } else { + guint8 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 gboolean +float_ieee_11073_cmp_bitwise_and(const fvalue_t *a, const fvalue_t *b) +{ + return ((a->value.uinteger & b->value.uinteger) != 0); +} + +/*============================================================================*/ + +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, /* free_value */ + sfloat_ieee_11073_val_from_unparsed, /* val_from_unparsed */ + NULL, /* val_from_string */ + sfloat_ieee_11073_val_to_repr, /* val_to_string_repr */ + sfloat_ieee_11073_val_repr_len, /* len_string_repr */ + + NULL, /* set_value_byte_array */ + NULL, /* set_value_bytes */ + NULL, /* set_value_guid */ + NULL, /* set_value_time */ + NULL, /* set_value_string */ + NULL, /* set_value_tvbuff */ + sfloat_ieee_11073_value_set, /* set_value_uinteger */ + NULL, /* set_value_sinteger */ + NULL, /* set_value_uinteger64 */ + NULL, /* set_value_sinteger64 */ + NULL, /* set_value_floating */ + + NULL, /* get_value */ + sfloat_ieee_11073_value_get, /* get_value_uinteger */ + NULL, /* get_value_sinteger */ + NULL, /* get_value_uinteger64 */ + NULL, /* get_value_sinteger64 */ + NULL, /* get_value_floating */ + + sfloat_ieee_11073_cmp_eq, + sfloat_ieee_11073_cmp_ne, + sfloat_ieee_11073_cmp_gt, + sfloat_ieee_11073_cmp_ge, + sfloat_ieee_11073_cmp_lt, + sfloat_ieee_11073_cmp_le, + sfloat_ieee_11073_cmp_bitwise_and, /* cmp_bitwise_and */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + NULL, /* len */ + NULL, /* slice */ + }; + +/* +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, /* free_value */ + float_ieee_11073_val_from_unparsed, /* val_from_unparsed */ + NULL, /* val_from_string */ + float_ieee_11073_val_to_repr, /* val_to_string_repr */ + float_ieee_11073_val_repr_len, /* len_string_repr */ + + NULL, /* set_value_byte_array */ + NULL, /* set_value_bytes */ + NULL, /* set_value_guid */ + NULL, /* set_value_time */ + NULL, /* set_value_string */ + NULL, /* set_value_tvbuff */ + float_ieee_11073_value_set, /* set_value_uinteger */ + NULL, /* set_value_sinteger */ + NULL, /* set_value_uinteger64 */ + NULL, /* set_value_sinteger64 */ + NULL, /* set_value_floating */ + + NULL, /* get_value */ + float_ieee_11073_value_get, /* get_value_uinteger */ + NULL, /* get_value_sinteger */ + NULL, /* get_value_uinteger64 */ + NULL, /* get_value_sinteger64 */ + NULL, /* get_value_floating */ + + float_ieee_11073_cmp_eq, + float_ieee_11073_cmp_ne, + float_ieee_11073_cmp_gt, + float_ieee_11073_cmp_ge, + float_ieee_11073_cmp_lt, + float_ieee_11073_cmp_le, + float_ieee_11073_cmp_bitwise_and, /* cmp_bitwise_and */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + NULL, /* len */ + NULL, /* slice */ + }; + + ftype_register(FT_IEEE_11073_SFLOAT, &sfloat_type); + ftype_register(FT_IEEE_11073_FLOAT, &float_type); +} + +/* + * Editor modelines - http://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/ftypes-int.h b/epan/ftypes/ftypes-int.h index 912a0dbdbc..9fba4f1c55 100644 --- a/epan/ftypes/ftypes-int.h +++ b/epan/ftypes/ftypes-int.h @@ -34,6 +34,7 @@ ftype_register(enum ftenum ftype, ftype_t *ft); * that I don't mind doing it by hand for now. */ void ftype_register_bytes(void); void ftype_register_double(void); +void ftype_register_ieee_11073_float(void); void ftype_register_fc(void); void ftype_register_integers(void); void ftype_register_ipv4(void); diff --git a/epan/ftypes/ftypes.c b/epan/ftypes/ftypes.c index 9dc8f9afe1..6f26f7249d 100644 --- a/epan/ftypes/ftypes.c +++ b/epan/ftypes/ftypes.c @@ -34,6 +34,7 @@ ftypes_initialize(void) { ftype_register_bytes(); ftype_register_double(); + ftype_register_ieee_11073_float(); ftype_register_integers(); ftype_register_ipv4(); ftype_register_ipv6(); diff --git a/epan/ftypes/ftypes.h b/epan/ftypes/ftypes.h index 4c3a5ad47a..74dc8e6d2c 100644 --- a/epan/ftypes/ftypes.h +++ b/epan/ftypes/ftypes.h @@ -52,6 +52,8 @@ enum ftenum { 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, @@ -214,6 +216,8 @@ typedef struct _fvalue_t { nstime_t time; tvbuff_t *tvb; GRegex *re; + guint16 sfloat_ieee_11073; + guint32 float_ieee_11073; } value; /* The following is provided for private use diff --git a/epan/proto.c b/epan/proto.c index 396eac480d..f9fab2d91c 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -2126,7 +2126,26 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree, proto_tree_set_time(new_fi, &time_stamp); break; + case FT_IEEE_11073_SFLOAT: + if (encoding) + encoding = ENC_LITTLE_ENDIAN; + if (length != 2) { + length_error = length < 2 ? TRUE : FALSE; + report_type_length_mismatch(tree, "a IEEE 11073 SFLOAT", length, length_error); + } + fvalue_set_uinteger(&new_fi->value, tvb_get_guint16(tvb, start, encoding)); + + break; + case FT_IEEE_11073_FLOAT: + if (encoding) + encoding = ENC_LITTLE_ENDIAN; + if (length != 4) { + length_error = length < 4 ? TRUE : FALSE; + report_type_length_mismatch(tree, "a IEEE 11073 FLOAT", length, length_error); + } + + break; default: g_error("new_fi->hfinfo->type %d (%s) not handled\n", new_fi->hfinfo->type, @@ -4859,6 +4878,28 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence, size-offset_r); break; + case FT_IEEE_11073_SFLOAT: + { + guint8 buf[240]; + fvalue_to_string_repr(&finfo->value, FTREPR_DISPLAY, hfinfo->display, buf); + g_snprintf(result+offset_r, size-offset_r, + "%s: %s", + hfinfo->name, buf); + } + offset_r = (int)strlen(result); + break; + + case FT_IEEE_11073_FLOAT: + { + guint8 buf[240]; + fvalue_to_string_repr(&finfo->value, FTREPR_DISPLAY, hfinfo->display, buf); + g_snprintf(result+offset_r, size-offset_r, + "%s: %s", + hfinfo->name, buf); + } + offset_r = (int)strlen(result); + break; + case FT_IPXNET: /*XXX really No column custom ?*/ case FT_PCRE: default: @@ -5974,7 +6015,8 @@ static const value_string hf_display[] = { { BASE_DEC_HEX|BASE_VAL64_STRING, "BASE_DEC_HEX|BASE_VAL64_STRING" }, { BASE_HEX_DEC|BASE_VAL64_STRING, "BASE_HEX_DEC|BASE_VAL64_STRING" }, { BASE_CUSTOM|BASE_VAL64_STRING, "BASE_CUSTOM|BASE_VAL64_STRING" }, - /* { STR_ASCII, "STR_ASCII" }, */ + /* Alias: BASE_NONE { BASE_FLOAT, "BASE_FLOAT" }, */ + /* Alias: BASE_NONE { STR_ASCII, "STR_ASCII" }, */ { STR_UNICODE, "STR_UNICODE" }, { ABSOLUTE_TIME_LOCAL, "ABSOLUTE_TIME_LOCAL" }, { ABSOLUTE_TIME_UTC, "ABSOLUTE_TIME_UTC" }, @@ -6870,6 +6912,25 @@ proto_item_fill_label(field_info *fi, gchar *label_str) label_fill(label_str, 0, hfinfo, hfinfo_format_text(hfinfo, bytes)); break; + case FT_IEEE_11073_SFLOAT: + { + guint8 buf[240]; + fvalue_to_string_repr(&fi->value, FTREPR_DISPLAY, hfinfo->display, buf); + g_snprintf(label_str, ITEM_LABEL_LENGTH, + "%s: %s", + hfinfo->name, buf); + } + break; + case FT_IEEE_11073_FLOAT: + { + guint8 buf[240]; + fvalue_to_string_repr(&fi->value, FTREPR_DISPLAY, hfinfo->display, buf); + g_snprintf(label_str, ITEM_LABEL_LENGTH, + "%s: %s", + hfinfo->name, buf); + } + break; + default: g_error("hfinfo->type %d (%s) not handled\n", hfinfo->type, ftype_name(hfinfo->type)); diff --git a/epan/proto.h b/epan/proto.h index 8a3dd4968e..eb45d5259b 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -510,6 +510,9 @@ typedef enum { BASE_HEX_DEC = 5, /**< hexadecimal (decimal) */ BASE_CUSTOM = 6, /**< call custom routine (in ->strings) to format */ +/* Float types */ + BASE_FLOAT = BASE_NONE, /**< decimal-format float */ + /* String types */ STR_ASCII = BASE_NONE, /**< shows non-printable ASCII characters as C-style escapes */ /* XXX, support for format_text_wsp() ? */