aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
authorwmeier <wmeier@f5534014-38df-0310-8fa8-9805f1628bb7>2010-10-14 17:50:35 +0000
committerwmeier <wmeier@f5534014-38df-0310-8fa8-9805f1628bb7>2010-10-14 17:50:35 +0000
commit29291ca8942e87eb7dc477a1cb9362f6ce099294 (patch)
treefc74c7baa8f4784253d68f6ff638e9850da12ab3 /epan
parente3cdbc3b5c76791e5d3294f5284aae493ab39f52 (diff)
Rework "extended value strings":
- Allow direct access when a range of values begins with a value other than 0; - Provide value_string_ext_new() for creating extended value strings at runtime; - Do access to value_string_ext members via a macro (all but value_string.c); - Update documentation. git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@34514 f5534014-38df-0310-8fa8-9805f1628bb7
Diffstat (limited to 'epan')
-rw-r--r--epan/dfilter/semcheck.c3
-rw-r--r--epan/dissectors/packet-diameter.c63
-rw-r--r--epan/libwireshark.def2
-rw-r--r--epan/proto.c2
-rw-r--r--epan/value_string.c209
-rw-r--r--epan/value_string.h87
6 files changed, 254 insertions, 112 deletions
diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c
index 82cde98243..45b6f7127c 100644
--- a/epan/dfilter/semcheck.c
+++ b/epan/dfilter/semcheck.c
@@ -232,9 +232,8 @@ mk_fvalue_from_val_string(header_field_info *hfinfo, char *s)
}
else {
const value_string *vals = hfinfo->strings;
-
if (hfinfo->display & BASE_EXT_STRING)
- vals = ((value_string_ext *) vals)->vals;
+ vals = VALUE_STRING_EXT_VS_P((value_string_ext *) vals);
while (vals->strptr != NULL) {
if (g_ascii_strcasecmp(s, vals->strptr) == 0) {
diff --git a/epan/dissectors/packet-diameter.c b/epan/dissectors/packet-diameter.c
index 6f55a9d8b1..ee7be3366d 100644
--- a/epan/dissectors/packet-diameter.c
+++ b/epan/dissectors/packet-diameter.c
@@ -130,8 +130,9 @@ struct _diam_avp_t {
void* type_data;
};
-#define VND_AVP_VS(v) ((value_string*)(void*)((v)->vs_avps->data))
-#define VND_CMD_VS(v) ((value_string*)(void*)((v)->vs_cmds->data))
+#define VND_AVP_VS(v) ((value_string*)(void*)((v)->vs_avps->data))
+#define VND_AVP_VS_LEN(v) ((v)->vs_avps->len)
+#define VND_CMD_VS(v) ((value_string*)(void*)((v)->vs_cmds->data))
typedef struct _diam_dictionary_t {
emem_tree_t* avps;
@@ -182,9 +183,8 @@ typedef struct _proto_avp_t {
static const char* simple_avp(diam_ctx_t*, diam_avp_t*, tvbuff_t*);
static const value_string no_vs[] = {{0, NULL} };
-static GArray no_garr = { (void*)no_vs, 1 };
-static value_string_ext no_vs_avps_ext = { (value_string_match_t) match_strval_ext_init, 0, (void*)no_vs};
-static diam_vnd_t unknown_vendor = { 0xffffffff, &no_garr, &no_vs_avps_ext, &no_garr };
+static GArray no_garr = { (void*)no_vs, 0 };
+static diam_vnd_t unknown_vendor = { 0xffffffff, &no_garr, NULL, &no_garr };
static diam_vnd_t no_vnd = { 0, NULL, NULL, NULL };
static diam_avp_t unknown_avp = {0, &unknown_vendor, simple_avp, simple_avp, -1, -1, NULL };
static GArray* all_cmds;
@@ -344,28 +344,24 @@ dissect_diameter_eap_payload(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tr
static int
dissect_diameter_avp(diam_ctx_t* c, tvbuff_t* tvb, int offset)
{
- guint32 code = tvb_get_ntohl(tvb,offset);
- guint32 len = tvb_get_ntohl(tvb,offset+4);
- guint32 vendor_flag = len & 0x80000000;
+ guint32 code = tvb_get_ntohl(tvb,offset);
+ guint32 len = tvb_get_ntohl(tvb,offset+4);
+ guint32 vendor_flag = len & 0x80000000;
guint32 flags_bits_idx = (len & 0xE0000000) >> 29;
- guint32 flags_bits = (len & 0xFF000000) >> 24;
- guint32 vendorid = vendor_flag ? tvb_get_ntohl(tvb,offset+8) : 0 ;
- emem_tree_key_t k[] = {
+ guint32 flags_bits = (len & 0xFF000000) >> 24;
+ guint32 vendorid = vendor_flag ? tvb_get_ntohl(tvb,offset+8) : 0 ;
+ emem_tree_key_t k[] = {
{1,&code},
{1,&vendorid},
{0,NULL}
};
- diam_avp_t* a = emem_tree_lookup32_array(dictionary.avps,k);
+ diam_avp_t* a = emem_tree_lookup32_array(dictionary.avps,k);
proto_item *pi, *avp_item;
proto_tree *avp_tree, *save_tree;
tvbuff_t* subtvb;
- const diam_vnd_t* vendor;
- value_string* vendor_avp_vs;
+ diam_vnd_t* vendor;
const char* code_str;
const char* avp_str;
-#if 0
- gint i = 0;
-#endif
len &= 0x00ffffff;
if (!a) {
@@ -378,24 +374,23 @@ dissect_diameter_avp(diam_ctx_t* c, tvbuff_t* tvb, int offset)
vendor = &no_vnd;
}
} else {
- vendor = a->vendor;
+ vendor = (diam_vnd_t *)a->vendor;
}
- if(vendor->vs_avps_ext->vals == NULL){
+ if(vendor->vs_avps_ext == NULL) {
g_array_sort(vendor->vs_avps, compare_avps);
- /* Get dictionary of AVPs matching found vendor */
- vendor_avp_vs = VND_AVP_VS(vendor);
- vendor->vs_avps_ext->vals = vendor_avp_vs;
+ vendor->vs_avps_ext = value_string_ext_new(VND_AVP_VS(vendor), VND_AVP_VS_LEN(vendor)+1,
+ "diameter_vendor");
#if 0
- Debug code
- while(vendor_avp_vs[i].strptr!=NULL){
- g_warning("%u %s",vendor_avp_vs[i].value,vendor_avp_vs[i].strptr);
- i++;
+ { /* Debug code */
+ value_string* vendor_avp_vs=VALUE_STRING_EXT_VS_P(vendor->vs_avps_ext);
+ gint i = 0;
+ while(vendor_avp_vs[i].strptr!=NULL){
+ g_warning("%u %s",vendor_avp_vs[i].value,vendor_avp_vs[i].strptr);
+ i++;
+ }
}
#endif
- }else{
- /* Get dictionary of AVPs matching found vendor */
- vendor_avp_vs = VND_AVP_VS(vendor);
}
/* Add root of tree for this AVP */
@@ -403,7 +398,7 @@ dissect_diameter_avp(diam_ctx_t* c, tvbuff_t* tvb, int offset)
avp_tree = proto_item_add_subtree(avp_item,a->ett);
pi = proto_tree_add_item(avp_tree,hf_diameter_avp_code,tvb,offset,4,FALSE);
- code_str = val_to_str_ext(code, vendor->vs_avps_ext, "Unknown");
+ code_str = val_to_str_ext_const(code, vendor->vs_avps_ext, "Unknown");
proto_item_append_text(pi," %s", code_str);
/* Code */
@@ -1230,9 +1225,6 @@ dictionary_load(void)
no_vnd.vs_cmds = g_array_new(TRUE,TRUE,sizeof(value_string));
no_vnd.vs_avps = g_array_new(TRUE,TRUE,sizeof(value_string));
- no_vnd.vs_avps_ext = g_malloc0(sizeof(value_string_ext));
- no_vnd.vs_avps_ext->match = (value_string_match_t) match_strval_ext_init;
- no_vnd.vs_avps_ext->length = 0;
all_cmds = g_array_new(TRUE,TRUE,sizeof(value_string));
@@ -1296,9 +1288,13 @@ dictionary_load(void)
vnd->code = v->code;
vnd->vs_cmds = g_array_new(TRUE,TRUE,sizeof(value_string));
vnd->vs_avps = g_array_new(TRUE,TRUE,sizeof(value_string));
+#if 0
vnd->vs_avps_ext = g_malloc0(sizeof(value_string_ext));
vnd->vs_avps_ext->match = (value_string_match_t) match_strval_ext_init;
+ vnd->vs_avps_ext->offset= 0;
vnd->vs_avps_ext->length= 0;
+#endif
+ vnd->vs_avps_ext = NULL;
pe_tree_insert32(dictionary.vnds,vnd->code,vnd);
g_hash_table_insert(vendors,v->name,vnd);
}
@@ -1331,7 +1327,6 @@ dictionary_load(void)
if ((vnd = g_hash_table_lookup(vendors,vend))) {
value_string vndvs = {a->code,a->name};
g_array_append_val(vnd->vs_avps,vndvs);
- vnd->vs_avps_ext->length++;
} else {
fprintf(stderr,"Diameter Dictionary: No Vendor: %s",vend);
vnd = &unknown_vendor;
diff --git a/epan/libwireshark.def b/epan/libwireshark.def
index a8f3a0d3e4..2ac377fa31 100644
--- a/epan/libwireshark.def
+++ b/epan/libwireshark.def
@@ -631,7 +631,7 @@ match_strrval
match_strrval_idx
match_strval
match_strval_ext
-match_strval_ext_init
+_match_strval_ext_init
match_strval_idx
md5_append
md5_finish
diff --git a/epan/proto.c b/epan/proto.c
index 7a2a690254..d04ee42a15 100644
--- a/epan/proto.c
+++ b/epan/proto.c
@@ -6007,7 +6007,7 @@ proto_registrar_dump_values(void)
hfinfo->type == FT_INT64)) {
if ((hfinfo->display & BASE_EXT_STRING)) {
- vals = ((value_string_ext *) hfinfo->strings)->vals;
+ vals = VALUE_STRING_EXT_VS_P((value_string_ext *) hfinfo->strings);
} else if ((hfinfo->display & BASE_RANGE_STRING) == 0) {
vals = hfinfo->strings;
} else {
diff --git a/epan/value_string.c b/epan/value_string.c
index 91c22bbda7..53bdb10436 100644
--- a/epan/value_string.c
+++ b/epan/value_string.c
@@ -33,6 +33,7 @@
#include "value_string.h"
#include <string.h>
+/* --------------------------------------------------------------------*/
/* 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. */
@@ -49,19 +50,7 @@ val_to_str(const guint32 val, const value_string *vs, const char *fmt) {
return ep_strdup_printf(fmt, val);
}
-const gchar*
-val_to_str_ext(const guint32 val, const value_string_ext *vs, const char *fmt) {
- const gchar *ret;
-
- g_assert(fmt != NULL);
-
- ret = match_strval_ext(val, vs);
- if (ret != NULL)
- return ret;
-
- return ep_strdup_printf(fmt, val);
-}
-
+/* --------------------------------------------------------------------*/
/* 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. */
@@ -78,19 +67,7 @@ val_to_str_const(const guint32 val, const value_string *vs, const char *unknown_
return unknown_str;
}
-const gchar*
-val_to_str_ext_const(const guint32 val, const value_string_ext *vs, const char *unknown_str) {
- const gchar *ret;
-
- g_assert(unknown_str != NULL);
-
- ret = match_strval_ext(val, vs);
- if (ret != NULL)
- return ret;
-
- return unknown_str;
-}
-
+/* --------------------------------------------------------------------*/
/* Tries to match val against each element in the value_string array vs.
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,
@@ -120,89 +97,205 @@ match_strval(const guint32 val, const value_string *vs) {
return match_strval_idx(val, vs, &ignore_me);
}
+/* --------------------------------------------------------------------*/
+/* value_string_ext functions
+ *
+ * Extended value strings allow fast(er) value_string array lookups by
+ * using (if possible) direct access or a binary search of the array.
+ *
+ * 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.
+ *
+ * If the values in the array are not contiguous (ie: there are "gaps"),
+ * but are in assending order a binary search will be used.
+ *
+ * If direct access or binary search cannot be used, then a linear search
+ * is used.
+ *
+ * Note that the value_string array used with VALUE_STRING_EXT_INIT
+ * *must* be terminated with {0, NULL}).
+ *
+ * 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);
+ *
+ * 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: <total number of entries in the value_string_array> should include the {0, NULL} entry
+ *
+ */
+
+/* --------------------------------------------------------------------*/
+
+/* Create a value_string_ext given a ptr to a value_string array and the total number of entries. */
+/* Note: The total number of entries should include the required {0, NULL} terminating entry of the array. */
+/* Return: a pointer to a gmalloc'd and initialized value_string_ext struct. */
+value_string_ext *
+value_string_ext_new(value_string *vs, guint vs_tot_num_entries, gchar *vs_name) {
+ value_string_ext *vse;
+ g_assert (vs_name != NULL);
+ g_assert (vs_tot_num_entries > 0);
+ g_assert (vs[vs_tot_num_entries-1].strptr == NULL); /* Null-terminated value-string ? */
+ vse = g_malloc(sizeof (value_string_ext));
+ vse->_vs_p = vs;
+ vse->_vs_num_entries = vs_tot_num_entries - 1; /* remember the actual number of entries */
+ vse->_vs_first_value = 0; /* initialized in _match_strval_ext_init */
+ vse->_vs_match = (_value_string_match_t) _match_strval_ext_init;
+ vse->_vs_name = vs_name;
+ return vse;
+}
+
+/* Looks up val in a value_string array using access method (direct, binary search
+ * or linear) determined at rutime during the initial access); (see _match_strval_ext_init)
+ * Returns the associated string ptr on a match, and returns NULL on failure.
+ */
+const gchar*
+match_strval_ext(const guint32 val, const value_string_ext *vse) {
+ if (vse)
+ return vse->_vs_match(val, vse);
+ return NULL;
+}
+
+/* Similar to match_strval_ext except that on failure
+ * Formats val with fmt, and returns the resulting string
+ */
+const gchar*
+val_to_str_ext(const guint32 val, const value_string_ext *vse, const char *fmt) {
+ const gchar *ret;
+
+ g_assert(fmt != NULL);
+
+ ret = match_strval_ext(val, vse);
+ if (ret != NULL)
+ return ret;
+
+ return ep_strdup_printf(fmt, val);
+}
+
+/* Similar to match_strval_ext except that on failure
+ * Returns 'unknown_str'
+ */
+const gchar*
+val_to_str_ext_const(const guint32 val, const value_string_ext *vse, const char *unknown_str) {
+ const gchar *ret;
+
+ g_assert(unknown_str != NULL);
+
+ ret = match_strval_ext(val, vse);
+ if (ret != NULL)
+ return ret;
+
+ return unknown_str;
+}
+
static const gchar *
-_match_strval_linear(const guint32 val, const value_string_ext *vs)
+_match_strval_linear(const guint32 val, const value_string_ext *vse)
{
- return match_strval(val, vs->vals);
+ 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].strptr;
+ }
+ }
+ return NULL;
}
static const gchar *
-_match_strval_index(const guint32 val, const value_string_ext *vs)
+_match_strval_index(const guint32 val, const value_string_ext *vse)
{
- return (val < vs->length) ? vs->vals[val].strptr : NULL;
+ if ((val - vse->_vs_first_value) < vse->_vs_num_entries) {
+ g_assert (val == vse->_vs_p[val - vse->_vs_first_value].value);
+ return vse->_vs_p[val - vse->_vs_first_value].strptr;
+ }
+ return NULL;
}
static const gchar *
-_match_strval_bsearch(const guint32 val, const value_string_ext *vs)
+_match_strval_bsearch(const guint32 val, const value_string_ext *vse)
{
guint low, idx, max;
guint32 item;
- for (low = 0, max = vs->length; low < max; ) {
+ for (low = 0, max = vse->_vs_num_entries; low < max; ) {
idx = (low + max) / 2;
- item = vs->vals[idx].value;
+ item = vse->_vs_p[idx].value;
if (val < item)
max = idx;
else if (val > item)
low = idx + 1;
else
- return vs->vals[idx].strptr;
+ return vse->_vs_p[idx].strptr;
}
return NULL;
}
+/* Init value_string_ext struct
+ - Go thru the value_string array to determine whether indexed access
+ or binary search access is possible;
+ - Verify that the value_string array does not contain any
+ NULL string pointers;
+ - Verify that the value_string array is terminated
+ by {0, NULL};
+*/
const gchar *
-match_strval_ext_init(const guint32 val, value_string_ext *vse)
+_match_strval_ext_init(const guint32 val, value_string_ext *vse)
{
- const value_string *vals = vse->vals;
+ const value_string *vs_p = vse->_vs_p;
+ const guint vs_num_entries = vse->_vs_num_entries;
/* The way matching of value is done in a value_string:
* 0 Sequential search (as in a normal value string)
* 1 Binary search, the values MUST be in numerical order.
- * 2 The value used as an index(the value string MUST have all values 0-max defined)
+ * 2 The value used as an index(the value string MUST have all values between first and last defined in numerical order)
*/
enum { VS_SEARCH = 0, VS_BIN_TREE, VS_INDEX } type = VS_INDEX;
- guint32 prev = 0;
- guint i;
+ guint32 prev_value;
+ guint first_value;
+ guint i;
- for (i = 0; i < vse->length; i++) {
- if (type == VS_INDEX && vals[i].value != i)
- type = VS_BIN_TREE;
+ g_assert((vs_p[vs_num_entries].value==0) && (vs_p[vs_num_entries].strptr==NULL));
- if (type == VS_BIN_TREE && prev > vals[i].value) {
+ 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++) {
+ g_assert(vs_p[i].strptr != NULL);
+ if ((type == VS_INDEX) && (vs_p[i].value != (i + first_value))) {
+ type = VS_BIN_TREE;
+ }
+ if ((type == VS_BIN_TREE) && (prev_value > vs_p[i].value)) {
type = VS_SEARCH;
break;
}
- prev = vals[i].value;
+ prev_value = vs_p[i].value;
}
-
+
switch (type) {
case VS_SEARCH:
- vse->match = _match_strval_linear;
- break;
- case VS_INDEX:
- vse->match = _match_strval_index;
+ vse->_vs_match = _match_strval_linear;
+ g_warning("Extended value string: %s not sorted; accessing linearly", vse->_vs_name);
break;
case VS_BIN_TREE:
- vse->match = _match_strval_bsearch;
+ vse->_vs_match = _match_strval_bsearch;
+ break;
+ case VS_INDEX:
+ vse->_vs_match = _match_strval_index;
break;
default:
g_assert_not_reached();
break;
}
- return vse->match(val, vse);
-}
-
-const gchar*
-match_strval_ext(const guint32 val, const value_string_ext *vs) {
- if (vs)
- return vs->match(val, vs);
- return NULL;
+ return vse->_vs_match(val, vse);
}
+/* ----------- */
/* Tries to match val against each element in the value_string array vs.
Returns the associated string ptr on a match.
diff --git a/epan/value_string.h b/epan/value_string.h
index cd30e9eb69..35c64b3507 100644
--- a/epan/value_string.h
+++ b/epan/value_string.h
@@ -34,18 +34,6 @@ typedef struct _value_string {
const gchar *strptr;
} value_string;
-struct _value_string_ext;
-typedef const char *(*value_string_match_t)(const guint32, const struct _value_string_ext *);
-
-typedef struct _value_string_ext {
- value_string_match_t match;
- guint length; /* length of the array */
- const value_string *vals; /* the value string */
-} value_string_ext;
-
-const gchar *match_strval_ext_init(const guint32 val, value_string_ext *vse);
-#define VALUE_STRING_EXT_INIT(x) { (value_string_match_t) match_strval_ext_init, array_length(x)-1, x }
-
/* Struct for the str_to_str, match_strstr_idx, and match_strstr functions */
typedef struct _string_string {
@@ -71,19 +59,17 @@ extern const gchar* match_strval_idx(const guint32 val, const value_string *vs,
/* Like match_strval_idx(), but doesn't return the index. */
extern const gchar* match_strval(const guint32 val, const value_string *vs);
-extern const gchar* match_strval_ext(const guint32 val, const value_string_ext *vs);
/* 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. */
extern const gchar* val_to_str(const guint32 val, const value_string *vs, const char *fmt);
-extern const gchar* val_to_str_ext(const guint32 val, const value_string_ext *vs, const char *fmt);
+
/* 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. */
extern const gchar* val_to_str_const(const guint32 val, const value_string *vs, const char *unknown_str);
-extern const gchar* val_to_str_ext_const(const guint32 val, const value_string_ext *vs, const char *unknown_str);
/* Tries to match val against each element in the string_string array vs.
Returns the associated string ptr, and sets "*idx" to the index in
@@ -91,7 +77,7 @@ extern const gchar* val_to_str_ext_const(const guint32 val, const value_string_e
on failure. */
extern const gchar* match_strstr_idx(const gchar *val, const string_string *vs, gint *idx);
-/* Like match_strval_idx(), but doesn't return the index. */
+/* Like match_strstr_idx(), but doesn't return the index. */
extern const gchar* match_strstr(const gchar *val, const string_string *vs);
/* Tries to match val against each element in the string_string array vs.
@@ -99,6 +85,75 @@ extern const gchar* match_strstr(const gchar *val, const string_string *vs);
Formats val with fmt, and returns the resulting string, on failure. */
extern const gchar* str_to_str(const gchar *val, const string_string *vs, const char *fmt);
+/* --------------------------------------------------------------------*/
+/* value_string_ext functions
+ *
+ * Extended value strings allow fast(er) value_string array lookups by
+ * using (if possible) direct access or a binary search of the array.
+ *
+ * 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.
+ *
+ * If the values in the array are not contiguous (ie: there are "gaps"),
+ * but are in assending order a binary search will be used.
+ *
+ * If direct access or binary search cannot be used, then a linear search
+ * is used.
+ *
+ * Note that the value_string array used with VALUE_STRING_EXT_INIT
+ * *must* be terminated with {0, NULL}).
+ *
+ * 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);
+ *
+ * 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: <total number of entries in the value_string_array> should include the {0, NULL} entry
+ */
+/* --------------------------------------------------------------------*/
+struct _value_string_ext;
+typedef const char *(*_value_string_match_t)(const guint32, const struct _value_string_ext *);
+
+typedef struct _value_string_ext {
+ _value_string_match_t _vs_match;
+ guint32 _vs_first_value; /* first value of the value_string array */
+ guint _vs_num_entries; /* number of entries in the value_string array */
+ /* (excluding final {0, NULL}) */
+ const value_string *_vs_p; /* the value string array address */
+ const gchar *_vs_name; /* vse "Name" (for error messages) */
+} value_string_ext;
+
+#define VALUE_STRING_EXT_VS_P(x) (x)->_vs_p
+
+extern const gchar *_match_strval_ext_init(const guint32 val, value_string_ext *vse);
+#define VALUE_STRING_EXT_INIT(x) { (_value_string_match_t) _match_strval_ext_init, 0, array_length(x)-1, x, #x }
+
+/* Create a value_string_ext given a ptr to a value_string array and the total number of entries. */
+/* Note: vs_tot_num_entries should include the required {0, NULL} terminating entry of the array. */
+/* Return: a pointer to a gmalloc'd and initialized value_string_ext struct. */
+extern value_string_ext *value_string_ext_new(value_string *vs, guint vs_tot_num_entries, gchar *vs_name);
+
+/* Looks up val in a value_string array using access method (direct, binary search
+ * or linear) determined at rutime during the initial access); (see _match_strval_ext_init)
+ * Returns the associated string ptr on a match or NULL on failure.
+ */
+extern const gchar* match_strval_ext(const guint32 val, const value_string_ext *vse);
+
+/* Similar to match_strval_ext except that on failure
+ * Formats val with fmt, and returns the resulting string
+ */
+extern const gchar* val_to_str_ext(const guint32 val, const value_string_ext *vs, const char *fmt);
+
+/* Similar to match_strval_ext except that on failure
+ * Returns 'unknown_str'
+ */
+extern const gchar* val_to_str_ext_const(const guint32 val, const value_string_ext *vs, const char *unknown_str);
+
+/* ---- ---- */
+
/* Generate a string describing an enumerated bitfield (an N-bit field
with various specific values having particular names). */
extern const char *decode_enumerated_bitfield(const guint32 val, const guint32 mask,