epan: Format column string input for display.

Format the input for display, by escaping some non printable characters,
using ws_label_strcpy().

In some cases with vsnprintf() this requires using a temporary buffer.

Add some debug checks for invalid UTF-8 errors.

The intention here is to pass dissection data directly to the column
API, and the column functions are responsible for formatting that
data for display. This avoids having to call format_text() before
adding a string to a column and separates the concerns better.
Display formatting is an UI concern.
This commit is contained in:
João Valverde 2022-10-21 13:37:42 +01:00
parent 92e1357bb4
commit c1cede8d7c
4 changed files with 72 additions and 24 deletions

View File

@ -34,11 +34,15 @@
#include <wsutil/utf8_entities.h>
#include <wsutil/ws_assert.h>
#include <wsutil/unicode-utils.h>
#ifdef HAVE_LUA
#include <epan/wslua/wslua.h>
#endif
#define COL_BUF_MAX_LEN (((COL_MAX_INFO_LEN) > (COL_MAX_LEN)) ? \
(COL_MAX_INFO_LEN) : (COL_MAX_LEN))
/* Used for locale decimal point */
static char *col_decimal_point;
@ -411,10 +415,11 @@ col_append_lstr(column_info *cinfo, const gint el, const gchar *str1, ...)
va_start(ap, str1);
str = str1;
do {
if (G_UNLIKELY(str == NULL))
str = "(null)";
pos += g_strlcpy(&col_item->col_buf[pos], str, max_len - pos);
if (G_UNLIKELY(str == NULL)) {
str = "(null)";
}
WS_UTF_8_CHECK(str, -1);
pos = ws_label_strcpy(col_item->col_buf, max_len, pos, str, 0);
} while (pos < max_len && (str = va_arg(ap, const char *)) != COL_ADD_LSTR_TERMINATOR);
va_end(ap);
@ -469,6 +474,7 @@ col_do_append_fstr(column_info *cinfo, const int el, const char *separator, cons
size_t len, max_len, sep_len;
int i;
col_item_t* col_item;
char tmp[COL_BUF_MAX_LEN];
sep_len = (separator) ? strlen(separator) : 0;
@ -491,7 +497,7 @@ col_do_append_fstr(column_info *cinfo, const int el, const char *separator, cons
* If we have a separator, append it if the column isn't empty.
*/
if (sep_len != 0 && len != 0) {
(void) g_strlcat(col_item->col_buf, separator, max_len);
(void) ws_label_strcat(col_item->col_buf, max_len, separator, 0);
len += sep_len;
}
@ -499,8 +505,10 @@ col_do_append_fstr(column_info *cinfo, const int el, const char *separator, cons
va_list ap2;
va_copy(ap2, ap);
vsnprintf(&col_item->col_buf[len], max_len - len, format, ap2);
vsnprintf(tmp, sizeof(tmp), format, ap2);
va_end(ap2);
WS_UTF_8_CHECK(tmp, -1);
ws_label_strcpy(col_item->col_buf, max_len, len, tmp, 0);
}
}
}
@ -541,8 +549,6 @@ col_append_sep_fstr(column_info *cinfo, const gint el, const gchar *separator,
}
/* Prepends a vararg list to a packet info string. */
#define COL_BUF_MAX_LEN (((COL_MAX_INFO_LEN) > (COL_MAX_LEN)) ? \
(COL_MAX_INFO_LEN) : (COL_MAX_LEN))
void
col_prepend_fstr(column_info *cinfo, const gint el, const gchar *format, ...)
{
@ -552,6 +558,7 @@ col_prepend_fstr(column_info *cinfo, const gint el, const gchar *format, ...)
const char *orig;
int max_len;
col_item_t* col_item;
char tmp[COL_BUF_MAX_LEN];
if (!CHECK_COL(cinfo, el))
return;
@ -572,8 +579,10 @@ col_prepend_fstr(column_info *cinfo, const gint el, const gchar *format, ...)
orig = orig_buf;
}
va_start(ap, format);
vsnprintf(col_item->col_buf, max_len, format, ap);
vsnprintf(tmp, sizeof(tmp), format, ap);
va_end(ap);
WS_UTF_8_CHECK(tmp, -1);
ws_label_strcpy(col_item->col_buf, max_len, 0, tmp, 0);
/*
* Move the fence, unless it's at the beginning of the string.
@ -595,6 +604,7 @@ col_prepend_fence_fstr(column_info *cinfo, const gint el, const gchar *format, .
const char *orig;
int max_len;
col_item_t* col_item;
char tmp[COL_BUF_MAX_LEN];
if (!CHECK_COL(cinfo, el))
return;
@ -615,8 +625,10 @@ col_prepend_fence_fstr(column_info *cinfo, const gint el, const gchar *format, .
orig = orig_buf;
}
va_start(ap, format);
vsnprintf(col_item->col_buf, max_len, format, ap);
vsnprintf(tmp, sizeof(tmp), format, ap);
va_end(ap);
WS_UTF_8_CHECK(tmp, -1);
ws_label_strcpy(col_item->col_buf, max_len, 0, tmp, 0);
/*
* Move the fence if it exists, else create a new fence at the
@ -665,7 +677,8 @@ col_add_str(column_info *cinfo, const gint el, const gchar* str)
*/
col_item->col_data = col_item->col_buf;
}
(void) g_strlcpy(&col_item->col_buf[col_item->col_fence], str, max_len - col_item->col_fence);
WS_UTF_8_CHECK(str, -1);
(void) ws_label_strcpy(col_item->col_buf, max_len, col_item->col_fence, str, 0);
}
}
}
@ -749,10 +762,11 @@ col_add_lstr(column_info *cinfo, const gint el, const gchar *str1, ...)
va_start(ap, str1);
str = str1;
do {
if (G_UNLIKELY(str == NULL))
str = "(null)";
pos += g_strlcpy(&col_item->col_buf[pos], str, max_len - pos);
if (G_UNLIKELY(str == NULL)) {
str = "(null)";
}
WS_UTF_8_CHECK(str, -1);
pos = ws_label_strcpy(col_item->col_buf, max_len, pos, str, 0);
} while (pos < max_len && (str = va_arg(ap, const char *)) != COL_ADD_LSTR_TERMINATOR);
va_end(ap);
@ -768,6 +782,7 @@ col_add_fstr(column_info *cinfo, const gint el, const gchar *format, ...)
int i;
int max_len;
col_item_t* col_item;
char tmp[COL_BUF_MAX_LEN];
if (!CHECK_COL(cinfo, el))
return;
@ -793,8 +808,10 @@ col_add_fstr(column_info *cinfo, const gint el, const gchar *format, ...)
col_item->col_data = col_item->col_buf;
}
va_start(ap, format);
vsnprintf(&col_item->col_buf[col_item->col_fence], max_len - col_item->col_fence, format, ap);
vsnprintf(tmp, sizeof(tmp), format, ap);
va_end(ap);
WS_UTF_8_CHECK(tmp, -1);
ws_label_strcpy(col_item->col_buf, max_len, col_item->col_fence, tmp, 0);
}
}
}
@ -827,10 +844,11 @@ col_do_append_str(column_info *cinfo, const gint el, const gchar* separator,
*/
if (separator != NULL) {
if (len != 0) {
(void) g_strlcat(col_item->col_buf, separator, max_len);
(void) ws_label_strcat(col_item->col_buf, max_len, separator, 0);
}
}
(void) g_strlcat(col_item->col_buf, str, max_len);
WS_UTF_8_CHECK(str, -1);
(void) ws_label_strcat(col_item->col_buf, max_len, str, 0);
}
}
}

View File

@ -103,7 +103,7 @@ enum {
* @param col the writable column, -1 for checking the state of all columns
* @return TRUE if it's writable, FALSE if not
*/
WS_DLL_PUBLIC gboolean col_get_writable(column_info *cinfo, const gint col);
WS_DLL_PUBLIC gboolean col_get_writable(column_info *cinfo, const gint col);
/** Set the columns writable.
*
@ -150,7 +150,10 @@ WS_DLL_PUBLIC const gchar *col_get_text(column_info *cinfo, const gint col);
*/
WS_DLL_PUBLIC void col_clear(column_info *cinfo, const gint col);
/** Set (replace) the text of a column element, the text won't be copied.
/** Set (replace) the text of a column element, the text won't be formatted or copied.
*
* Use this for simple static strings like protocol names. Don't use for untrusted strings
* or strings that may contain unprintable characters.
*
* Usually used to set const strings!
*
@ -160,7 +163,9 @@ WS_DLL_PUBLIC void col_clear(column_info *cinfo, const gint col);
*/
WS_DLL_PUBLIC void col_set_str(column_info *cinfo, const gint col, const gchar * str);
/** Add (replace) the text of a column element, the text will be copied.
/** Add (replace) the text of a column element, the text will be formatted and copied.
*
* Unprintable characters according to isprint() are escaped.
*
* @param cinfo the current packet row
* @param col the column to use, e.g. COL_INFO
@ -170,9 +175,12 @@ WS_DLL_PUBLIC void col_add_str(column_info *cinfo, const gint col, const gchar *
/* terminator argument for col_add_lstr() function */
#define COL_ADD_LSTR_TERMINATOR (const char *) -1
WS_DLL_PUBLIC void col_add_lstr(column_info *cinfo, const gint el, const gchar *str, ...);
/** Add (replace) the text of a column element, the text will be formatted and copied.
*
* Unprintable characters according to isprint() are escaped.
*
* Same function as col_add_str() but using a printf-like format string.
*
@ -184,7 +192,9 @@ WS_DLL_PUBLIC void col_add_lstr(column_info *cinfo, const gint el, const gchar *
WS_DLL_PUBLIC void col_add_fstr(column_info *cinfo, const gint col, const gchar *format, ...)
G_GNUC_PRINTF(3, 4);
/** Append the given text to a column element, the text will be copied.
/** Append the given text to a column element, the text will be formatted and copied.
*
* Unprintable characters according to isprint() are escaped.
*
* @param cinfo the current packet row
* @param col the column to use, e.g. COL_INFO
@ -229,6 +239,8 @@ WS_DLL_PUBLIC void col_append_frame_number(packet_info *pinfo, const gint col, c
WS_DLL_PUBLIC void col_append_lstr(column_info *cinfo, const gint el, const gchar *str, ...);
/** Append the given text to a column element, the text will be formatted and copied.
*
* Unprintable characters according to isprint() are escaped.
*
* Same function as col_append_str() but using a printf-like format string.
*
@ -241,6 +253,8 @@ WS_DLL_PUBLIC void col_append_fstr(column_info *cinfo, const gint col, const gch
G_GNUC_PRINTF(3, 4);
/** Prepend the given text to a column element, the text will be formatted and copied.
*
* Unprintable characters according to isprint() are escaped.
*
* @param cinfo the current packet row
* @param col the column to use, e.g. COL_INFO
@ -250,7 +264,10 @@ WS_DLL_PUBLIC void col_append_fstr(column_info *cinfo, const gint col, const gch
WS_DLL_PUBLIC void col_prepend_fstr(column_info *cinfo, const gint col, const gchar *format, ...)
G_GNUC_PRINTF(3, 4);
/**Prepend the given text to a column element, the text will be formatted and copied.
/** Prepend the given text to a column element, the text will be formatted and copied.
*
* Unprintable characters according to isprint() are escaped.
*
* This function is similar to col_prepend_fstr() but this function will
* unconditionally set a fence to the end of the prepended data even if there
* were no fence before.
@ -262,6 +279,8 @@ WS_DLL_PUBLIC void col_prepend_fence_fstr(column_info *cinfo, const gint col, co
G_GNUC_PRINTF(3, 4);
/** Append the given text (prepended by a separator) to a column element.
*
* Unprintable characters according to isprint() are escaped.
*
* Much like col_append_str() but will prepend the given separator if the column isn't empty.
*
@ -274,6 +293,8 @@ WS_DLL_PUBLIC void col_append_sep_str(column_info *cinfo, const gint col, const
const gchar *str);
/** Append the given text (prepended by a separator) to a column element.
*
* Unprintable characters according to isprint() are escaped.
*
* Much like col_append_fstr() but will prepend the given separator if the column isn't empty.
*
@ -297,7 +318,7 @@ WS_DLL_PUBLIC void col_append_sep_fstr(column_info *cinfo, const gint col, const
* @param fieldname the fieldname to use for creating a filter (when
* applying/preparing/copying as filter)
*/
WS_DLL_PUBLIC void col_set_time(column_info *cinfo, const int col,
WS_DLL_PUBLIC void col_set_time(column_info *cinfo, const int col,
const nstime_t *ts, const char *fieldname);
WS_DLL_PUBLIC void set_fd_time(const struct epan_session *epan, frame_data *fd, gchar *buf);

View File

@ -936,6 +936,12 @@ ws_label_strcpy(char *label_str, size_t buf_size, size_t pos,
return pos;
}
size_t
ws_label_strcat(char *label_str, size_t bufsize, const uint8_t *str, int flags)
{
return ws_label_strcpy(label_str, bufsize, strlen(label_str), str, flags);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*

View File

@ -195,6 +195,9 @@ void IA5_7BIT_decode(unsigned char * dest, const unsigned char* src, int len);
WS_DLL_PUBLIC
size_t ws_label_strcpy(char *label_str, size_t bufsize, gsize pos, const uint8_t *str, int flags);
WS_DLL_PUBLIC
size_t ws_label_strcat(char *label_str, size_t bufsize, const uint8_t *str, int flags);
/*
* Check name is valid. This covers names for display filter fields, dissector
* tables, preference modules, etc. Lower case is preferred.