# Capitalising hex strings in dissector field output?

Hello,

Is there a way to capitalise hex output in the field output like we can with the string formatter "0x%04X"?

I'm using that to add the details to the INFO column but not sure how to get similar formatting in the dissected fields:

PACKED_SIM_GROUP_M3UA_S (0xCFDC) from IPDU-3 to GISU-7 via EMB-0


For example, I have the field is being output like below:

DMX message number: PACKED_SIM_GROUP_M3UA_S (0xcfdc)


But I'd prefer to have the hex number printed as 0xCFDC (just makes it simpler for us to see the message number).

I am poking around the source for proto_tree_add_item to pin down where the actual hex digit printing occurs ... haven't figured it out yet.

In my dissector I'm doing this:

            static const value_string dmxMessageNumber[] = {
...
{ 0xCFDC, "PACKED_SIM_GROUP_M3UA_S" },
...
};

offset, 2, ENC_LITTLE_ENDIAN);
...

{"DMX message number", "emb.dmx.number",
FT_UINT16, BASE_HEX, VALS(dmxMessageNumber),
0x0, "DX message number (message_number_t)", HFILL}},


Thanks, Brett.

edit retag close merge delete

I guess one workaround would be to simply use the column editing mode to copy the hex number in my dmxMessageNumber array so it's part of the text output string, something like:

{ 0xCFDC, "0xCFDC, PACKED_SIM_GROUP_M3UA_S" }


That would only take a few seconds to do for all 120+ array members I have at the moment.

In that case, is there any way to suppress the output of the (0xcfdc)?

( 2020-06-24 06:26:36 +0000 )edit

Ah huh, in PROTO.C I think I've found where the actual formatting is done?

So I could get it to print all hex strings capitalised by modifying this function and recompiling?

hfinfo_char_value_format_display(int display, char buf[7], guint32 value)
{
char *ptr = &buf[6];
static const gchar hex_digits[16] =
{ '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

case BASE_HEX:
*(--ptr) = hex_digits[value & 0x0F];
value >>= 4;
*(--ptr) = hex_digits[value & 0x0F];
*(--ptr) = 'x';
break;

( 2020-06-24 06:42:26 +0000 )edit

Nope and nope. I've modified in EPAN/PROTO.C and also a similar one I found in EPAN/PRINT.C and neither had any effect:

static gboolean
print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
guint length, packet_char_enc encoding)
{

static gchar binhex[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

( 2020-06-24 06:56:32 +0000 )edit

I'm a big fan of "patch and pray" coding so maybe try changing epan/to_str.c. Or maybe a better long term solution is to use BASE_CUSTOM: doc/README.dissector

For integer fields (FT_UINT* and FT_INT*), this variable represents the
base in which you would like the value displayed. The acceptable bases
are:

BASE_DEC,
BASE_HEX,
BASE_OCT,
BASE_DEC_HEX,
BASE_HEX_DEC,
BASE_CUSTOM

BASE_DEC, BASE_HEX, and BASE_OCT are decimal, hexadecimal, and octal,
respectively. BASE_DEC_HEX and BASE_HEX_DEC display value in two bases
(the 1st representation followed by the 2nd in parenthesis).

BASE_CUSTOM allows one to specify a callback function pointer that will
format the value.

( 2020-06-24 13:06:31 +0000 )edit

Ha ha, indeed! It's also a good way to figure out how things work.

I did consider BASE_CUSTOM when I came upon it in the code but then also saw a comment in PROTO.C that said:

case BASE_CUSTOM: /* hfinfo_numeric_value_format() treats this as decimal */


So I discounted it without further investigation - I'll have a proper look at how it works.

And you're right about TO_STR.C ... patched that one and now all my hex strings are capitalised ... happiness ;)

static inline char
low_nibble_of_octet_to_hex(guint8 oct)
{
/* At least one version of Apple's C compiler/linker is buggy, causing
not ending with '\0' if we initialize a 16-element "char" array with
a 16-character string, the fact that initializing such an array with
such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
'\0' byte in the string ...
(more)
( 2020-06-24 21:15:47 +0000 )edit

Sort by » oldest newest most voted

Perhaps this would be better done as a general preference so users, rather than dissector writers, can choose whether to show a-f or A-F in hex displays?

Or should we just say "capital letters" and be done with it?

more

I'd be happy with that. For me, I just find it instantly clearer to read 0xABCD rather than 0xabcd.

( 2020-06-25 07:56:04 +0000 )edit

Thanks for the advice Chuck - using BASE_CUSTOM was exactly what I needed!

A little convoluted but I found a good example of what I needed to implement in one of the GSM Abis dissectors (epan/dissectors/packet-gsm_abis_oml.c) .

I created five new functions - one each to handle bytes (0x%02X) & words (0x%04X), and then three to handle outputs that included value strings.

Revisiting my original example, I now call print_dmx_message which both prints out the message name and also prints the message number in upper case hex:

static void
print_dmx_message(gchar *result, guint16 message_number )
{
/* print message name and number 0xABCD (or 0x000A, etc.) */
const gchar *tmp = NULL;

tmp = try_val_to_str(message_number, dmxMessageNumber);
if (tmp)
g_snprintf(result, ITEM_LABEL_LENGTH, "%s (0x%04X)", tmp,message_number);
else
g_snprintf(result, ITEM_LABEL_LENGTH, "Unknown (0x%04X)", message_number);
}
...
{"DMX message number", "emb.dmx.number",
FT_UINT16, BASE_CUSTOM, CF_FUNC(print_dmx_message), 0x0,
"DX message number (message_number_t)", HFILL}},

more

Glad it worked out. Wasn't looking forward to opening a new bug if that comment in proto.c was applicable. :-)

( 2020-06-25 05:19:08 +0000 )edit

It also meant I could customise the output of the internal program block IDs we use - they're stored as a word value but really are only three digit hex numbers.

So instead of just having the default 0x0abc output, I now have something that looks nicer (for my needs):

static void
print_dmx_family(gchar *result, guint16 family_id )
{
/* print 00A, 0AB, or ABC */
const gchar *tmp = NULL;

tmp = try_val_to_str(family_id, dmxFamily);
if (tmp)
g_snprintf(result, ITEM_LABEL_LENGTH, "%s (%03X)", tmp,family_id);
else
g_snprintf(result, ITEM_LABEL_LENGTH, "Unknown (%03X)", family_id);
}


which results in

DMX family: ZS4PRB (SIP access side signalling service) (68C)

( 2020-06-25 05:41:36 +0000 )edit

I had originally tried calling the val_to_str within the g_snprintf function but this caused Wireshark to crash when it returned a NULL (I'm guessing), something like:

g_snprintf(result, ITEM_LABEL_LENGTH, "%s (0x%04X)", val_to_str(message_number, dmxMessageNumber, "Unknown"), message_number);


Hence why I had to grep around a bit more until I found the example in the Abis dissector, and hence why I've implemented it the way I have.

( 2020-06-25 06:03:30 +0000 )edit