2001-04-01 03:18:41 +00:00
|
|
|
/* value_string.c
|
|
|
|
* Routines for value_strings
|
|
|
|
*
|
2006-05-21 05:12:17 +00:00
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
2001-04-01 03:18:41 +00:00
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
2018-02-08 16:59:17 +00:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
2001-04-01 03:18:41 +00:00
|
|
|
*/
|
|
|
|
|
2013-08-14 01:15:59 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2001-04-01 03:18:41 +00:00
|
|
|
#include <stdio.h>
|
2013-03-28 22:02:04 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
2013-07-06 18:25:27 +00:00
|
|
|
#include "wmem/wmem.h"
|
2013-03-28 22:02:04 +00:00
|
|
|
#include "proto.h"
|
|
|
|
#include "to_str.h"
|
2001-04-01 03:18:41 +00:00
|
|
|
#include "value_string.h"
|
2016-07-26 02:58:09 +00:00
|
|
|
#include <wsutil/ws_printf.h> /* ws_g_warning */
|
2001-04-01 03:18:41 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* REGULAR VALUE STRING */
|
|
|
|
|
2001-04-01 03:18:41 +00:00
|
|
|
/* Tries to match val against each element in the value_string array vs.
|
|
|
|
Returns the associated string ptr on a match.
|
|
|
|
Formats val with fmt, and returns the resulting string, on failure. */
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2013-03-28 22:02:04 +00:00
|
|
|
val_to_str(const guint32 val, const value_string *vs, const char *fmt)
|
|
|
|
{
|
2016-05-11 04:22:20 +00:00
|
|
|
const gchar *ret;
|
|
|
|
|
|
|
|
DISSECTOR_ASSERT(fmt != NULL);
|
|
|
|
|
|
|
|
ret = try_val_to_str(val, vs);
|
|
|
|
if (ret != NULL)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return wmem_strdup_printf(wmem_packet_scope(), fmt, val);
|
2001-04-01 03:18:41 +00:00
|
|
|
}
|
|
|
|
|
2015-02-03 00:58:29 +00:00
|
|
|
gchar *
|
2015-01-31 13:06:05 +00:00
|
|
|
val_to_str_wmem(wmem_allocator_t *scope, const guint32 val, const value_string *vs, const char *fmt)
|
|
|
|
{
|
|
|
|
const gchar *ret;
|
|
|
|
|
|
|
|
DISSECTOR_ASSERT(fmt != NULL);
|
|
|
|
|
|
|
|
ret = try_val_to_str(val, vs);
|
|
|
|
if (ret != NULL)
|
2015-02-03 00:58:29 +00:00
|
|
|
return wmem_strdup(scope, ret);
|
2015-01-31 13:06:05 +00:00
|
|
|
|
|
|
|
return wmem_strdup_printf(scope, fmt, val);
|
|
|
|
}
|
|
|
|
|
2009-09-06 04:26:50 +00:00
|
|
|
/* Tries to match val against each element in the value_string array vs.
|
|
|
|
Returns the associated string ptr on a match.
|
|
|
|
Returns 'unknown_str', on failure. */
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2013-03-28 22:02:04 +00:00
|
|
|
val_to_str_const(const guint32 val, const value_string *vs,
|
|
|
|
const char *unknown_str)
|
|
|
|
{
|
|
|
|
const gchar *ret;
|
2009-09-06 04:26:50 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
DISSECTOR_ASSERT(unknown_str != NULL);
|
2009-09-06 04:26:50 +00:00
|
|
|
|
2013-03-29 00:26:23 +00:00
|
|
|
ret = try_val_to_str(val, vs);
|
2013-03-28 22:02:04 +00:00
|
|
|
if (ret != NULL)
|
|
|
|
return ret;
|
2009-09-06 04:26:50 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
return unknown_str;
|
2009-09-06 04:26:50 +00:00
|
|
|
}
|
|
|
|
|
2001-04-01 03:18:41 +00:00
|
|
|
/* Tries to match val against each element in the value_string array vs.
|
2005-06-26 19:56:52 +00:00
|
|
|
Returns the associated string ptr, and sets "*idx" to the index in
|
|
|
|
that table, on a match, and returns NULL, and sets "*idx" to -1,
|
|
|
|
on failure. */
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2013-03-29 00:26:23 +00:00
|
|
|
try_val_to_str_idx(const guint32 val, const value_string *vs, gint *idx)
|
2013-03-28 22:02:04 +00:00
|
|
|
{
|
|
|
|
gint i = 0;
|
|
|
|
|
|
|
|
DISSECTOR_ASSERT(idx != NULL);
|
|
|
|
|
|
|
|
if(vs) {
|
|
|
|
while (vs[i].strptr) {
|
|
|
|
if (vs[i].value == val) {
|
|
|
|
*idx = i;
|
|
|
|
return(vs[i].strptr);
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
2005-06-26 19:56:52 +00:00
|
|
|
}
|
2001-04-01 03:18:41 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
*idx = -1;
|
|
|
|
return NULL;
|
2001-04-01 03:18:41 +00:00
|
|
|
}
|
|
|
|
|
2013-03-29 00:26:23 +00:00
|
|
|
/* Like try_val_to_str_idx(), but doesn't return the index. */
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2013-03-29 00:26:23 +00:00
|
|
|
try_val_to_str(const guint32 val, const value_string *vs)
|
2013-03-28 22:02:04 +00:00
|
|
|
{
|
2005-06-26 19:56:52 +00:00
|
|
|
gint ignore_me;
|
2013-03-29 00:26:23 +00:00
|
|
|
return try_val_to_str_idx(val, vs, &ignore_me);
|
2005-06-26 19:56:52 +00:00
|
|
|
}
|
|
|
|
|
2013-07-26 21:51:39 +00:00
|
|
|
/* 64-BIT VALUE STRING */
|
|
|
|
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2013-07-26 21:51:39 +00:00
|
|
|
val64_to_str(const guint64 val, const val64_string *vs, const char *fmt)
|
|
|
|
{
|
|
|
|
const gchar *ret;
|
|
|
|
|
|
|
|
DISSECTOR_ASSERT(fmt != NULL);
|
|
|
|
|
|
|
|
ret = try_val64_to_str(val, vs);
|
|
|
|
if (ret != NULL)
|
|
|
|
return ret;
|
|
|
|
|
2015-01-31 12:55:10 +00:00
|
|
|
return wmem_strdup_printf(wmem_packet_scope(), fmt, val);
|
2013-07-26 21:51:39 +00:00
|
|
|
}
|
|
|
|
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2013-07-26 21:51:39 +00:00
|
|
|
val64_to_str_const(const guint64 val, const val64_string *vs,
|
|
|
|
const char *unknown_str)
|
|
|
|
{
|
|
|
|
const gchar *ret;
|
|
|
|
|
|
|
|
DISSECTOR_ASSERT(unknown_str != NULL);
|
|
|
|
|
|
|
|
ret = try_val64_to_str(val, vs);
|
|
|
|
if (ret != NULL)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return unknown_str;
|
|
|
|
}
|
|
|
|
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2013-07-26 21:51:39 +00:00
|
|
|
try_val64_to_str_idx(const guint64 val, const val64_string *vs, gint *idx)
|
|
|
|
{
|
|
|
|
gint i = 0;
|
|
|
|
|
|
|
|
DISSECTOR_ASSERT(idx != NULL);
|
|
|
|
|
|
|
|
if(vs) {
|
|
|
|
while (vs[i].strptr) {
|
|
|
|
if (vs[i].value == val) {
|
|
|
|
*idx = i;
|
|
|
|
return(vs[i].strptr);
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*idx = -1;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2013-07-26 21:51:39 +00:00
|
|
|
try_val64_to_str(const guint64 val, const val64_string *vs)
|
|
|
|
{
|
|
|
|
gint ignore_me;
|
|
|
|
return try_val64_to_str_idx(val, vs, &ignore_me);
|
|
|
|
}
|
|
|
|
|
2013-03-29 23:23:28 +00:00
|
|
|
/* REVERSE VALUE STRING */
|
|
|
|
|
|
|
|
/* We use the same struct as for regular value strings, but we look up strings
|
|
|
|
* and return values instead */
|
|
|
|
|
|
|
|
/* Like val_to_str except backwards */
|
|
|
|
guint32
|
|
|
|
str_to_val(const gchar *val, const value_string *vs, const guint32 err_val)
|
|
|
|
{
|
2013-03-30 00:11:00 +00:00
|
|
|
gint i;
|
2013-03-29 23:23:28 +00:00
|
|
|
|
2013-03-30 00:11:00 +00:00
|
|
|
i = str_to_val_idx(val, vs);
|
2013-03-29 23:23:28 +00:00
|
|
|
|
2013-03-30 00:11:00 +00:00
|
|
|
if (i >= 0) {
|
|
|
|
return vs[i].value;
|
2013-03-29 23:23:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return err_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the index of a string in a value_string, or -1 when not present */
|
|
|
|
gint
|
|
|
|
str_to_val_idx(const gchar *val, const value_string *vs)
|
|
|
|
{
|
|
|
|
gint i = 0;
|
|
|
|
|
|
|
|
if(vs) {
|
|
|
|
|
|
|
|
while (vs[i].strptr) {
|
|
|
|
|
|
|
|
if (strcmp(vs[i].strptr, val) == 0) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* EXTENDED VALUE STRING */
|
|
|
|
|
|
|
|
/* Extended value strings allow fast(er) value_string array lookups by
|
|
|
|
* using (if possible) direct access or a binary search of the array.
|
2010-10-14 17:50:35 +00:00
|
|
|
*
|
2013-03-28 22:02:04 +00:00
|
|
|
* If the values in the value_string array are a contiguous range of values
|
|
|
|
* from min to max, the value will be used as as a direct index into the array.
|
2010-10-14 17:50:35 +00:00
|
|
|
*
|
2013-03-28 22:02:04 +00:00
|
|
|
* If the values in the array are not contiguous (ie: there are "gaps"),
|
|
|
|
* but are in assending order a binary search will be used.
|
2010-10-14 17:50:35 +00:00
|
|
|
*
|
2013-03-28 22:02:04 +00:00
|
|
|
* If direct access or binary search cannot be used, then a linear search
|
|
|
|
* is used and a warning is emitted.
|
2010-10-14 17:50:35 +00:00
|
|
|
*
|
2013-03-28 22:02:04 +00:00
|
|
|
* Note that the value_string array used with VALUE_STRING_EXT_INIT
|
|
|
|
* *must* be terminated with {0, NULL}).
|
2010-10-14 17:50:35 +00:00
|
|
|
*
|
2013-03-28 22:02:04 +00:00
|
|
|
* Extended value strings are defined at compile time as follows:
|
|
|
|
* static const value_string vs[] = { {value1, "string1"},
|
|
|
|
* {value2, "string2"},
|
|
|
|
* ...,
|
|
|
|
* {0, NULL}};
|
|
|
|
* static value_string_ext vse = VALUE_STRING_EXT_INIT(vs);
|
2010-10-14 17:50:35 +00:00
|
|
|
*
|
2013-03-28 22:02:04 +00:00
|
|
|
* Extended value strings can be created at runtime by calling
|
|
|
|
* value_string_ext_new(<ptr to value_string array>,
|
|
|
|
* <total number of entries in the value_string_array>,
|
|
|
|
* <value_string_name>);
|
|
|
|
* Note: The <total number of entries in the value_string_array> should include
|
|
|
|
* the {0, NULL} entry.
|
2010-10-14 17:50:35 +00:00
|
|
|
*/
|
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* Create a value_string_ext given a ptr to a value_string array and the total
|
|
|
|
* number of entries. Note that the total number of entries should include the
|
|
|
|
* required {0, NULL} terminating entry of the array.
|
2013-07-06 18:25:27 +00:00
|
|
|
* Returns a pointer to an epan-scoped'd and initialized value_string_ext
|
|
|
|
* struct. */
|
2014-07-25 16:29:04 +00:00
|
|
|
value_string_ext *
|
2013-11-21 18:46:40 +00:00
|
|
|
value_string_ext_new(const value_string *vs, guint vs_tot_num_entries,
|
2013-03-28 22:02:04 +00:00
|
|
|
const gchar *vs_name)
|
|
|
|
{
|
2010-10-14 17:50:35 +00:00
|
|
|
value_string_ext *vse;
|
2013-03-28 22:02:04 +00:00
|
|
|
|
|
|
|
DISSECTOR_ASSERT (vs_name != NULL);
|
|
|
|
DISSECTOR_ASSERT (vs_tot_num_entries > 0);
|
|
|
|
/* Null-terminated value-string ? */
|
2013-07-06 18:25:27 +00:00
|
|
|
DISSECTOR_ASSERT (vs[vs_tot_num_entries-1].strptr == NULL);
|
2013-03-28 22:02:04 +00:00
|
|
|
|
2013-07-06 18:25:27 +00:00
|
|
|
vse = wmem_new(wmem_epan_scope(), value_string_ext);
|
2010-10-14 17:50:35 +00:00
|
|
|
vse->_vs_p = vs;
|
2013-03-28 22:02:04 +00:00
|
|
|
vse->_vs_num_entries = vs_tot_num_entries - 1;
|
|
|
|
/* We set our 'match' function to the init function, which finishes by
|
|
|
|
* setting the match function properly and then calling it. This is a
|
|
|
|
* simple way to do lazy initialization of extended value strings.
|
|
|
|
* The init function also sets up _vs_first_value for us. */
|
|
|
|
vse->_vs_first_value = 0;
|
2013-03-29 00:26:23 +00:00
|
|
|
vse->_vs_match2 = _try_val_to_str_ext_init;
|
2010-10-14 17:50:35 +00:00
|
|
|
vse->_vs_name = vs_name;
|
2013-03-28 22:02:04 +00:00
|
|
|
|
2010-10-14 17:50:35 +00:00
|
|
|
return vse;
|
|
|
|
}
|
|
|
|
|
2013-11-21 18:46:40 +00:00
|
|
|
void
|
2016-06-30 10:09:07 +00:00
|
|
|
value_string_ext_free(value_string_ext *vse)
|
2013-11-21 18:46:40 +00:00
|
|
|
{
|
2016-06-30 10:09:07 +00:00
|
|
|
wmem_free(wmem_epan_scope(), vse);
|
2013-11-21 18:46:40 +00:00
|
|
|
}
|
|
|
|
|
2013-03-29 00:26:23 +00:00
|
|
|
/* Like try_val_to_str for extended value strings */
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2014-07-25 16:29:04 +00:00
|
|
|
try_val_to_str_ext(const guint32 val, value_string_ext *vse)
|
2013-03-28 22:02:04 +00:00
|
|
|
{
|
2011-04-28 11:15:46 +00:00
|
|
|
if (vse) {
|
2013-03-28 22:02:04 +00:00
|
|
|
const value_string *vs = vse->_vs_match2(val, vse);
|
|
|
|
|
|
|
|
if (vs) {
|
|
|
|
return vs->strptr;
|
|
|
|
}
|
2011-04-28 11:15:46 +00:00
|
|
|
}
|
2013-03-28 22:02:04 +00:00
|
|
|
|
2010-10-14 17:50:35 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-03-29 00:26:23 +00:00
|
|
|
/* Like try_val_to_str_idx for extended value strings */
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2014-07-25 16:29:04 +00:00
|
|
|
try_val_to_str_idx_ext(const guint32 val, value_string_ext *vse, gint *idx)
|
2013-03-28 22:02:04 +00:00
|
|
|
{
|
2011-04-28 11:15:46 +00:00
|
|
|
if (vse) {
|
2013-03-28 22:02:04 +00:00
|
|
|
const value_string *vs = vse->_vs_match2(val, vse);
|
|
|
|
if (vs) {
|
|
|
|
*idx = (gint) (vs - vse->_vs_p);
|
|
|
|
return vs->strptr;
|
|
|
|
}
|
2011-04-28 11:15:46 +00:00
|
|
|
}
|
|
|
|
*idx = -1;
|
|
|
|
return NULL;
|
2011-01-10 14:31:33 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* Like val_to_str for extended value strings */
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2014-07-25 16:29:04 +00:00
|
|
|
val_to_str_ext(const guint32 val, value_string_ext *vse, const char *fmt)
|
2013-03-28 22:02:04 +00:00
|
|
|
{
|
2016-05-11 04:22:20 +00:00
|
|
|
const gchar *ret;
|
|
|
|
|
|
|
|
DISSECTOR_ASSERT(fmt != NULL);
|
|
|
|
|
|
|
|
ret = try_val_to_str_ext(val, vse);
|
|
|
|
if (ret != NULL)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return wmem_strdup_printf(wmem_packet_scope(), fmt, val);
|
2010-10-14 17:50:35 +00:00
|
|
|
}
|
|
|
|
|
2015-02-03 00:58:29 +00:00
|
|
|
gchar *
|
2015-01-31 13:06:05 +00:00
|
|
|
val_to_str_ext_wmem(wmem_allocator_t *scope, const guint32 val, value_string_ext *vse, const char *fmt)
|
|
|
|
{
|
|
|
|
const gchar *ret;
|
|
|
|
|
|
|
|
DISSECTOR_ASSERT(fmt != NULL);
|
|
|
|
|
|
|
|
ret = try_val_to_str_ext(val, vse);
|
|
|
|
if (ret != NULL)
|
2015-02-03 00:58:29 +00:00
|
|
|
return wmem_strdup(scope, ret);
|
2015-01-31 13:06:05 +00:00
|
|
|
|
|
|
|
return wmem_strdup_printf(scope, fmt, val);
|
|
|
|
}
|
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* Like val_to_str_const for extended value strings */
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2014-07-25 16:29:04 +00:00
|
|
|
val_to_str_ext_const(const guint32 val, value_string_ext *vse,
|
2013-03-28 22:02:04 +00:00
|
|
|
const char *unknown_str)
|
|
|
|
{
|
|
|
|
const gchar *ret;
|
2010-10-14 17:50:35 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
DISSECTOR_ASSERT(unknown_str != NULL);
|
2010-10-14 17:50:35 +00:00
|
|
|
|
2013-03-29 00:26:23 +00:00
|
|
|
ret = try_val_to_str_ext(val, vse);
|
2013-03-28 22:02:04 +00:00
|
|
|
if (ret != NULL)
|
|
|
|
return ret;
|
2010-10-14 17:50:35 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
return unknown_str;
|
2010-10-14 17:50:35 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* Fallback linear matching algorithm for extended value strings */
|
2011-04-28 11:15:46 +00:00
|
|
|
static const value_string *
|
2014-07-25 16:29:04 +00:00
|
|
|
_try_val_to_str_linear(const guint32 val, value_string_ext *vse)
|
2010-04-27 12:38:49 +00:00
|
|
|
{
|
2013-03-28 22:02:04 +00:00
|
|
|
const value_string *vs_p = vse->_vs_p;
|
|
|
|
guint i;
|
|
|
|
for (i=0; i<vse->_vs_num_entries; i++) {
|
|
|
|
if (vs_p[i].value == val)
|
|
|
|
return &(vs_p[i]);
|
|
|
|
}
|
|
|
|
return NULL;
|
2010-04-27 12:38:49 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* Constant-time matching algorithm for contiguous extended value strings */
|
2011-04-28 11:15:46 +00:00
|
|
|
static const value_string *
|
2014-07-25 16:29:04 +00:00
|
|
|
_try_val_to_str_index(const guint32 val, value_string_ext *vse)
|
2010-04-27 12:38:49 +00:00
|
|
|
{
|
2013-03-28 22:02:04 +00:00
|
|
|
guint i;
|
|
|
|
|
|
|
|
i = val - vse->_vs_first_value;
|
|
|
|
if (i < vse->_vs_num_entries) {
|
|
|
|
g_assert (val == vse->_vs_p[i].value);
|
|
|
|
return &(vse->_vs_p[i]);
|
|
|
|
}
|
|
|
|
return NULL;
|
2010-04-27 12:38:49 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* log(n)-time matching algorithm for sorted extended value strings */
|
2011-04-28 11:15:46 +00:00
|
|
|
static const value_string *
|
2014-07-25 16:29:04 +00:00
|
|
|
_try_val_to_str_bsearch(const guint32 val, value_string_ext *vse)
|
2010-04-27 12:38:49 +00:00
|
|
|
{
|
2013-03-28 22:02:04 +00:00
|
|
|
guint low, i, max;
|
|
|
|
guint32 item;
|
|
|
|
|
|
|
|
for (low = 0, max = vse->_vs_num_entries; low < max; ) {
|
|
|
|
i = (low + max) / 2;
|
|
|
|
item = vse->_vs_p[i].value;
|
|
|
|
|
|
|
|
if (val < item)
|
|
|
|
max = i;
|
|
|
|
else if (val > item)
|
|
|
|
low = i + 1;
|
|
|
|
else
|
|
|
|
return &(vse->_vs_p[i]);
|
|
|
|
}
|
|
|
|
return NULL;
|
2010-04-27 12:38:49 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* Initializes an extended value string. Behaves like a match function to
|
|
|
|
* permit lazy initialization of extended value strings.
|
|
|
|
* - Goes through the value_string array to determine the fastest possible
|
|
|
|
* access method.
|
|
|
|
* - Verifies that the value_string contains no NULL string pointers.
|
|
|
|
* - Verifies that the value_string is terminated by {0, NULL}
|
|
|
|
*/
|
2011-04-28 11:15:46 +00:00
|
|
|
const value_string *
|
2014-07-25 16:29:04 +00:00
|
|
|
_try_val_to_str_ext_init(const guint32 val, value_string_ext *vse)
|
2010-04-27 12:38:49 +00:00
|
|
|
{
|
2013-03-28 22:02:04 +00:00
|
|
|
const value_string *vs_p = vse->_vs_p;
|
|
|
|
const guint vs_num_entries = vse->_vs_num_entries;
|
|
|
|
|
|
|
|
/* The matching algorithm used:
|
|
|
|
* VS_SEARCH - slow sequential search (as in a normal value string)
|
|
|
|
* VS_BIN_TREE - log(n)-time binary search, the values must be sorted
|
|
|
|
* VS_INDEX - constant-time index lookup, the values must be contiguous
|
|
|
|
*/
|
|
|
|
enum { VS_SEARCH, VS_BIN_TREE, VS_INDEX } type = VS_INDEX;
|
|
|
|
|
|
|
|
/* Note: The value_string 'value' is *unsigned*, but we do a little magic
|
|
|
|
* to help with value strings that have negative values.
|
|
|
|
*
|
|
|
|
* { -3, -2, -1, 0, 1, 2 }
|
|
|
|
* will be treated as "ascending ordered" (although it isn't technically),
|
|
|
|
* thus allowing constant-time index search
|
|
|
|
*
|
|
|
|
* { -3, -2, 0, 1, 2 } and { -3, -2, -1, 0, 2 }
|
|
|
|
* will both be considered as "out-of-order with gaps", thus falling
|
|
|
|
* back to the slow linear search
|
|
|
|
*
|
|
|
|
* { 0, 1, 2, -3, -2 } and { 0, 2, -3, -2, -1 }
|
|
|
|
* will be considered "ascending ordered with gaps" thus allowing
|
|
|
|
* a log(n)-time 'binary' search
|
|
|
|
*
|
|
|
|
* If you're confused, think of how negative values are represented, or
|
|
|
|
* google two's complement.
|
|
|
|
*/
|
|
|
|
|
|
|
|
guint32 prev_value;
|
|
|
|
guint first_value;
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
DISSECTOR_ASSERT((vs_p[vs_num_entries].value == 0) &&
|
|
|
|
(vs_p[vs_num_entries].strptr == NULL));
|
|
|
|
|
|
|
|
vse->_vs_first_value = vs_p[0].value;
|
|
|
|
first_value = vs_p[0].value;
|
|
|
|
prev_value = first_value;
|
|
|
|
|
|
|
|
for (i = 0; i < vs_num_entries; i++) {
|
|
|
|
DISSECTOR_ASSERT(vs_p[i].strptr != NULL);
|
|
|
|
if ((type == VS_INDEX) && (vs_p[i].value != (i + first_value))) {
|
|
|
|
type = VS_BIN_TREE;
|
|
|
|
}
|
|
|
|
/* XXX: Should check for dups ?? */
|
|
|
|
if (type == VS_BIN_TREE) {
|
|
|
|
if (prev_value > vs_p[i].value) {
|
2016-07-26 02:58:09 +00:00
|
|
|
ws_g_warning("Extended value string '%s' forced to fall back to linear search:\n"
|
2013-11-21 18:46:40 +00:00
|
|
|
" entry %u, value %u [%#x] < previous entry, value %u [%#x]",
|
|
|
|
vse->_vs_name, i, vs_p[i].value, vs_p[i].value, prev_value, prev_value);
|
2013-03-28 22:02:04 +00:00
|
|
|
type = VS_SEARCH;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (first_value > vs_p[i].value) {
|
2016-07-26 02:58:09 +00:00
|
|
|
ws_g_warning("Extended value string '%s' forced to fall back to linear search:\n"
|
2013-11-21 18:46:40 +00:00
|
|
|
" entry %u, value %u [%#x] < first entry, value %u [%#x]",
|
|
|
|
vse->_vs_name, i, vs_p[i].value, vs_p[i].value, first_value, first_value);
|
2013-03-28 22:02:04 +00:00
|
|
|
type = VS_SEARCH;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
prev_value = vs_p[i].value;
|
2010-04-27 10:32:34 +00:00
|
|
|
}
|
2010-04-27 12:38:49 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
switch (type) {
|
|
|
|
case VS_SEARCH:
|
2013-03-29 00:26:23 +00:00
|
|
|
vse->_vs_match2 = _try_val_to_str_linear;
|
2013-03-28 22:02:04 +00:00
|
|
|
break;
|
|
|
|
case VS_BIN_TREE:
|
2013-03-29 00:26:23 +00:00
|
|
|
vse->_vs_match2 = _try_val_to_str_bsearch;
|
2013-03-28 22:02:04 +00:00
|
|
|
break;
|
|
|
|
case VS_INDEX:
|
2013-03-29 00:26:23 +00:00
|
|
|
vse->_vs_match2 = _try_val_to_str_index;
|
2013-03-28 22:02:04 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
break;
|
|
|
|
}
|
2010-11-12 19:48:30 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
return vse->_vs_match2(val, vse);
|
2010-11-14 16:30:56 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* STRING TO STRING MATCHING */
|
2010-11-12 19:48:30 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* string_string is like value_string except the values being matched are
|
|
|
|
* also strings (instead of unsigned integers) */
|
2010-04-27 10:32:34 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* Like val_to_str except for string_string */
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2013-03-28 22:02:04 +00:00
|
|
|
str_to_str(const gchar *val, const string_string *vs, const char *fmt)
|
|
|
|
{
|
|
|
|
const gchar *ret;
|
2009-05-26 00:49:38 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
DISSECTOR_ASSERT(fmt != NULL);
|
2009-05-26 00:49:38 +00:00
|
|
|
|
2013-03-29 00:26:23 +00:00
|
|
|
ret = try_str_to_str(val, vs);
|
2013-03-28 22:02:04 +00:00
|
|
|
if (ret != NULL)
|
|
|
|
return ret;
|
2009-05-26 00:49:38 +00:00
|
|
|
|
2015-01-31 12:55:10 +00:00
|
|
|
return wmem_strdup_printf(wmem_packet_scope(), fmt, val);
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
|
|
|
|
2013-03-29 00:26:23 +00:00
|
|
|
/* Like try_val_to_str_idx except for string_string */
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2013-03-29 00:26:23 +00:00
|
|
|
try_str_to_str_idx(const gchar *val, const string_string *vs, gint *idx)
|
2013-03-28 22:02:04 +00:00
|
|
|
{
|
|
|
|
gint i = 0;
|
|
|
|
|
|
|
|
if(vs) {
|
|
|
|
while (vs[i].strptr) {
|
|
|
|
if (!strcmp(vs[i].value,val)) {
|
|
|
|
*idx = i;
|
|
|
|
return(vs[i].strptr);
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
*idx = -1;
|
|
|
|
return NULL;
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
|
|
|
|
2013-03-29 00:26:23 +00:00
|
|
|
/* Like try_val_to_str except for string_string */
|
2013-11-21 18:46:40 +00:00
|
|
|
const gchar *
|
2013-03-29 00:26:23 +00:00
|
|
|
try_str_to_str(const gchar *val, const string_string *vs)
|
2013-03-28 22:02:04 +00:00
|
|
|
{
|
2009-05-26 00:49:38 +00:00
|
|
|
gint ignore_me;
|
2013-03-29 00:26:23 +00:00
|
|
|
return try_str_to_str_idx(val, vs, &ignore_me);
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* RANGE TO STRING MATCHING */
|
2006-12-07 20:29:40 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* range_string is like value_string except the values being matched are
|
|
|
|
* integer ranges (for example, 0-10, 11-19, etc.) instead of single values. */
|
2006-12-07 20:29:40 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* Like val_to_str except for range_string */
|
2012-12-12 01:50:44 +00:00
|
|
|
const gchar *
|
|
|
|
rval_to_str(const guint32 val, const range_string *rs, const char *fmt)
|
2006-12-07 20:29:40 +00:00
|
|
|
{
|
2013-03-28 22:02:04 +00:00
|
|
|
const gchar *ret = NULL;
|
2006-12-07 20:29:40 +00:00
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
DISSECTOR_ASSERT(fmt != NULL);
|
2006-12-07 20:29:40 +00:00
|
|
|
|
2013-03-29 00:26:23 +00:00
|
|
|
ret = try_rval_to_str(val, rs);
|
2013-03-28 22:02:04 +00:00
|
|
|
if(ret != NULL)
|
|
|
|
return ret;
|
2006-12-07 20:29:40 +00:00
|
|
|
|
2015-01-31 12:55:10 +00:00
|
|
|
return wmem_strdup_printf(wmem_packet_scope(), fmt, val);
|
2006-12-07 20:29:40 +00:00
|
|
|
}
|
|
|
|
|
2013-09-29 12:44:50 +00:00
|
|
|
/* Like val_to_str_const except for range_string */
|
|
|
|
const gchar *
|
|
|
|
rval_to_str_const(const guint32 val, const range_string *rs,
|
|
|
|
const char *unknown_str)
|
|
|
|
{
|
|
|
|
const gchar *ret = NULL;
|
|
|
|
|
|
|
|
DISSECTOR_ASSERT(unknown_str != NULL);
|
|
|
|
|
|
|
|
ret = try_rval_to_str(val, rs);
|
|
|
|
if(ret != NULL)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return unknown_str;
|
|
|
|
}
|
|
|
|
|
2013-03-29 00:26:23 +00:00
|
|
|
/* Like try_val_to_str_idx except for range_string */
|
2012-12-12 01:50:44 +00:00
|
|
|
const gchar *
|
2013-03-29 00:26:23 +00:00
|
|
|
try_rval_to_str_idx(const guint32 val, const range_string *rs, gint *idx)
|
2006-12-07 20:29:40 +00:00
|
|
|
{
|
2013-03-28 22:02:04 +00:00
|
|
|
gint i = 0;
|
|
|
|
|
|
|
|
if(rs) {
|
|
|
|
while(rs[i].strptr) {
|
|
|
|
if( (val >= rs[i].value_min) && (val <= rs[i].value_max) ) {
|
|
|
|
*idx = i;
|
|
|
|
return (rs[i].strptr);
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
2006-12-07 20:29:40 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
*idx = -1;
|
|
|
|
return NULL;
|
2006-12-07 20:29:40 +00:00
|
|
|
}
|
|
|
|
|
2013-03-29 00:26:23 +00:00
|
|
|
/* Like try_val_to_str except for range_string */
|
2012-12-12 01:50:44 +00:00
|
|
|
const gchar *
|
2013-03-29 00:26:23 +00:00
|
|
|
try_rval_to_str(const guint32 val, const range_string *rs)
|
2006-12-07 20:29:40 +00:00
|
|
|
{
|
|
|
|
gint ignore_me = 0;
|
2013-03-29 00:26:23 +00:00
|
|
|
return try_rval_to_str_idx(val, rs, &ignore_me);
|
2006-12-07 20:29:40 +00:00
|
|
|
}
|
|
|
|
|
2016-08-07 02:45:19 +00:00
|
|
|
/* Like try_val_to_str_idx except for range_string */
|
|
|
|
const gchar *
|
|
|
|
try_rval64_to_str_idx(const guint64 val, const range_string *rs, gint *idx)
|
|
|
|
{
|
|
|
|
gint i = 0;
|
|
|
|
|
|
|
|
if(rs) {
|
|
|
|
while(rs[i].strptr) {
|
|
|
|
if( (val >= rs[i].value_min) && (val <= rs[i].value_max) ) {
|
|
|
|
*idx = i;
|
|
|
|
return (rs[i].strptr);
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*idx = -1;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Like try_val64_to_str except for range_string */
|
|
|
|
const gchar *
|
|
|
|
try_rval64_to_str(const guint64 val, const range_string *rs)
|
|
|
|
{
|
|
|
|
gint ignore_me = 0;
|
|
|
|
return try_rval64_to_str_idx(val, rs, &ignore_me);
|
|
|
|
}
|
|
|
|
|
2017-03-04 00:40:51 +00:00
|
|
|
|
|
|
|
/* BYTE BUFFER TO STRING MATCHING */
|
|
|
|
|
|
|
|
/* Like val_to_str except for bytes_string */
|
|
|
|
const gchar *
|
|
|
|
bytesval_to_str(const guint8 *val, const size_t val_len, const bytes_string *bs, const char *fmt)
|
|
|
|
{
|
|
|
|
const gchar *ret;
|
|
|
|
|
|
|
|
DISSECTOR_ASSERT(fmt != NULL);
|
|
|
|
|
|
|
|
ret = try_bytesval_to_str(val, val_len, bs);
|
|
|
|
if (ret != NULL)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX should this use bytes_to_str as format parameter for consistency?
|
|
|
|
* Though for bytes I guess most of the time you want to show "Unknown"
|
|
|
|
* anyway rather than "Unknown (\x13\x37...)"
|
|
|
|
*/
|
|
|
|
return wmem_strdup(wmem_packet_scope(), fmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Like try_val_to_str except for bytes_string */
|
|
|
|
const gchar *
|
|
|
|
try_bytesval_to_str(const guint8 *val, const size_t val_len, const bytes_string *bs)
|
|
|
|
{
|
|
|
|
guint i = 0;
|
|
|
|
|
|
|
|
if (bs) {
|
|
|
|
while (bs[i].strptr) {
|
|
|
|
if (bs[i].value_length == val_len && !memcmp(bs[i].value, val, val_len)) {
|
|
|
|
return bs[i].strptr;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Like val_to_str, but tries to find a prefix (instead of an exact) match
|
2017-03-13 16:02:23 +00:00
|
|
|
of any prefix from the bytes_string array bs against the haystack. */
|
2017-03-04 00:40:51 +00:00
|
|
|
const gchar *
|
2017-03-13 16:02:23 +00:00
|
|
|
bytesprefix_to_str(const guint8 *haystack, const size_t haystack_len, const bytes_string *bs, const char *fmt)
|
2017-03-04 00:40:51 +00:00
|
|
|
{
|
|
|
|
const gchar *ret;
|
|
|
|
|
|
|
|
DISSECTOR_ASSERT(fmt != NULL);
|
|
|
|
|
2017-03-13 16:02:23 +00:00
|
|
|
ret = try_bytesprefix_to_str(haystack, haystack_len, bs);
|
2017-03-04 00:40:51 +00:00
|
|
|
if (ret != NULL)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* XXX See note at bytesval_to_str. */
|
|
|
|
return wmem_strdup(wmem_packet_scope(), fmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Like try_val_to_str, but tries to find a prefix (instead of an exact) match
|
2017-03-13 16:02:23 +00:00
|
|
|
of any prefix from the bytes_string array bs against the haystack. */
|
2017-03-04 00:40:51 +00:00
|
|
|
const gchar *
|
2017-03-13 16:02:23 +00:00
|
|
|
try_bytesprefix_to_str(const guint8 *haystack, const size_t haystack_len, const bytes_string *bs)
|
2017-03-04 00:40:51 +00:00
|
|
|
{
|
|
|
|
guint i = 0;
|
|
|
|
|
|
|
|
if (bs) {
|
|
|
|
while (bs[i].strptr) {
|
2017-03-13 16:02:23 +00:00
|
|
|
if (haystack_len >= bs[i].value_length &&
|
|
|
|
!memcmp(bs[i].value, haystack, bs[i].value_length)) {
|
2017-03-04 00:40:51 +00:00
|
|
|
return bs[i].strptr;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-03-28 22:02:04 +00:00
|
|
|
/* MISC */
|
|
|
|
|
|
|
|
/* Functions for use by proto_registrar_dump_values(), see proto.c */
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
value_string_ext_validate(const value_string_ext *vse)
|
|
|
|
{
|
|
|
|
if (vse == NULL)
|
|
|
|
return FALSE;
|
2013-12-13 14:39:19 +00:00
|
|
|
#ifndef _WIN32 /* doesn't work on Windows for refs from another DLL ?? */
|
|
|
|
if ((vse->_vs_match2 != _try_val_to_str_ext_init) &&
|
|
|
|
(vse->_vs_match2 != _try_val_to_str_linear) &&
|
|
|
|
(vse->_vs_match2 != _try_val_to_str_bsearch) &&
|
|
|
|
(vse->_vs_match2 != _try_val_to_str_index))
|
|
|
|
return FALSE;
|
|
|
|
#endif
|
|
|
|
return TRUE;
|
2013-03-28 22:02:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
value_string_ext_match_type_str(const value_string_ext *vse)
|
|
|
|
{
|
2014-07-25 16:29:04 +00:00
|
|
|
if (vse->_vs_match2 == _try_val_to_str_ext_init)
|
|
|
|
return "[Not Initialized]";
|
2013-03-29 00:26:23 +00:00
|
|
|
if (vse->_vs_match2 == _try_val_to_str_linear)
|
2013-03-28 22:02:04 +00:00
|
|
|
return "[Linear Search]";
|
2013-03-29 00:26:23 +00:00
|
|
|
if (vse->_vs_match2 == _try_val_to_str_bsearch)
|
2013-03-28 22:02:04 +00:00
|
|
|
return "[Binary Search]";
|
2013-03-29 00:26:23 +00:00
|
|
|
if (vse->_vs_match2 == _try_val_to_str_index)
|
2013-03-28 22:02:04 +00:00
|
|
|
return "[Direct (indexed) Access]";
|
2014-07-25 16:29:04 +00:00
|
|
|
return "[Invalid]";
|
2013-03-28 22:02:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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:
|
|
|
|
*/
|