diff options
author | Alexandre Quesnel <131881+aquesnel@users.noreply.github.com> | 2021-02-28 22:50:16 +0300 |
---|---|---|
committer | Alexandre Quesnel <131881+aquesnel@users.noreply.github.com> | 2021-03-26 16:58:27 +0300 |
commit | b8d02823d1d02a4231cff7cf747dd4bd0c76428b (patch) | |
tree | 42116bce65d7f0c55e7c233dcf4809fa0210f8cd | |
parent | ec52c6466d70a56fec2a454f6c60130f05a6cf2f (diff) |
Extracting bytes_to_hexdump function from logging implementation
-rw-r--r-- | common/log.c | 150 | ||||
-rw-r--r-- | common/log.h | 21 | ||||
-rw-r--r-- | common/string_calls.c | 126 | ||||
-rw-r--r-- | common/string_calls.h | 23 |
4 files changed, 201 insertions, 119 deletions
diff --git a/common/log.c b/common/log.c index 0c5465d3..ad076090 100644 --- a/common/log.c +++ b/common/log.c @@ -764,7 +764,18 @@ log_end(void) } /*****************************************************************************/ -/* produce a hex dump */ +/* log a hex dump */ +enum logReturns +log_hexdump(const enum logLevels log_level, + const char *message, + const char *src, + int len) +{ + return log_hexdump_with_location("", "", 0, log_level, message, src, len); +} + +/*****************************************************************************/ +/* log a hex dump */ enum logReturns log_hexdump_with_location(const char *function_name, const char *file_name, @@ -774,38 +785,11 @@ log_hexdump_with_location(const char *function_name, const char *src, int len) { - unsigned char *line; - int i; - int dump_number_lines; - int dump_line_length; - int dump_length; - int dump_offset; - int thisline; - int offset; char *dump_buffer; - enum logReturns rv; + enum logReturns rv = LOG_STARTUP_OK; enum logLevels override_log_level; bool_t override_destination_level = 0; - /* Start the dump on a new line so that the first line of the dump is - aligned to the first column instead of to after the log message - preamble (eg. time, log level, ...) - */ -#define HEX_DUMP_SOURCE_BYTES_PER_LINE (16) -#ifdef _WIN32 -#define HEX_DUMP_HEADER ("%s Hex Dump:\r\n") -#define HEX_DUMP_NEWLINE_SIZE (2) -#else -#ifdef _MACOS -#define HEX_DUMP_HEADER ("%s Hex Dump:\r") -#define HEX_DUMP_NEWLINE_SIZE (1) -#else -#define HEX_DUMP_HEADER ("%s Hex Dump:\n") -#define HEX_DUMP_NEWLINE_SIZE (1) -#endif -#endif -#define HEX_DUMP_HEADER_SIZE (sizeof(HEX_DUMP_HEADER) - 1) - override_destination_level = internal_log_location_overrides_level( function_name, file_name, @@ -815,107 +799,37 @@ log_hexdump_with_location(const char *function_name, return LOG_STARTUP_OK; } - dump_line_length = (4 + 3 /* = 4 offset + 3 space */ - + ((2 + 1) * HEX_DUMP_SOURCE_BYTES_PER_LINE) /* + (2 hex char + 1 space) per source byte */ - + 2 /* + 2 space */ - + HEX_DUMP_SOURCE_BYTES_PER_LINE - + HEX_DUMP_NEWLINE_SIZE); - - dump_number_lines = (len / HEX_DUMP_SOURCE_BYTES_PER_LINE) + 1; /* +1 to round up */ - dump_length = (dump_number_lines *dump_line_length /* hex dump lines */ - + HEX_DUMP_HEADER_SIZE - + 1); /* terminating NULL */ - dump_buffer = (char *)g_malloc(dump_length, 1); - if (dump_buffer == NULL) - { - LOG_DEVEL(LOG_LEVEL_WARNING, - "Failed to allocate buffer for hex dump of size %d", - dump_length); - return LOG_ERROR_MALLOC; - } - - line = (unsigned char *)src; - offset = 0; - - g_memcpy(dump_buffer, HEX_DUMP_HEADER, HEX_DUMP_HEADER_SIZE); - dump_offset = HEX_DUMP_HEADER_SIZE; - - while (offset < len) - { - g_sprintf(dump_buffer + dump_offset, "%04x ", offset); - dump_offset += 7; - thisline = len - offset; - - if (thisline > HEX_DUMP_SOURCE_BYTES_PER_LINE) - { - thisline = HEX_DUMP_SOURCE_BYTES_PER_LINE; - } - - for (i = 0; i < thisline; i++) - { - g_sprintf(dump_buffer + dump_offset, "%02x ", line[i]); - dump_offset += 3; - } - - for (; i < HEX_DUMP_SOURCE_BYTES_PER_LINE; i++) - { - dump_buffer[dump_offset++] = ' '; - dump_buffer[dump_offset++] = ' '; - dump_buffer[dump_offset++] = ' '; - } - - dump_buffer[dump_offset++] = ' '; - dump_buffer[dump_offset++] = ' '; - - for (i = 0; i < thisline; i++) - { - dump_buffer[dump_offset++] = (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'; - } - - for (; i < HEX_DUMP_SOURCE_BYTES_PER_LINE; i++) - { - dump_buffer[dump_offset++] = ' '; - } - + /* Start the dump on a new line so that the first line of the dump is + aligned to the first column instead of to after the log message + preamble (eg. time, log level, ...) + */ #ifdef _WIN32 - dump_buffer[dump_offset++] = '\r'; - dump_buffer[dump_offset++] = '\n'; +#define HEX_DUMP_HEADER ("Hex Dump:\r\n") #else #ifdef _MACOS - dump_buffer[dump_offset++] = '\r'; +#define HEX_DUMP_HEADER ("Hex Dump:\r") #else - dump_buffer[dump_offset++] = '\n'; +#define HEX_DUMP_HEADER ("Hex Dump:\n") #endif #endif - offset += thisline; - line += thisline; + dump_buffer = g_bytes_to_hexdump(src, len); - if ((dump_offset - HEX_DUMP_HEADER_SIZE) % dump_line_length != 0) + if (dump_buffer != NULL) + { + if (g_strlen(file_name) > 0) { - LOG_DEVEL(LOG_LEVEL_ERROR, - "BUG: dump_offset (%d) at the end of a line is not a " - "multiple of the line length (%d)", - dump_offset, dump_line_length); + rv = log_message_with_location(function_name, file_name, line_number, + log_level, "%s %s%s", + message, HEX_DUMP_HEADER, dump_buffer); + } + else + { + rv = log_message(log_level, "%s %s%s", + message, HEX_DUMP_HEADER, dump_buffer); } - - } - if (dump_offset > dump_length) - { - LOG_DEVEL(LOG_LEVEL_ERROR, - "BUG: dump_offset (%d) is larger than the dump_buffer length (%d)", - dump_offset, dump_length); g_free(dump_buffer); - return LOG_GENERAL_ERROR; } - - /* replace the last new line with the end of the string since log_message - will add a new line */ - dump_buffer[dump_offset - HEX_DUMP_NEWLINE_SIZE] = '\0'; - - rv = log_message_with_location(function_name, file_name, line_number, - log_level, dump_buffer, message); - g_free(dump_buffer); return rv; } diff --git a/common/log.h b/common/log.h index bc86c1e5..97f17d86 100644 --- a/common/log.h +++ b/common/log.h @@ -127,8 +127,23 @@ enum logReturns #define LOG_DEVEL_HEXDUMP(log_level, message, buffer, length) \ log_hexdump_with_location(__func__, __FILE__, __LINE__, log_level, message, buffer, length) +/** + * @brief Logging macro for logging the contents of a byte array using a hex + * dump format. + * + * @param log_level, the log level + * @param message, a message prefix for the hex dump. Note: no printf like + * formatting is done to this message. + * @param buffer, a pointer to the byte array to log as a hex dump + * @param length, the length of the byte array to log + */ +#define LOG_HEXDUMP(log_level, message, buffer, length) \ + log_hexdump_with_location(__func__, __FILE__, __LINE__, log_level, message, buffer, length) + #else #define LOG(log_level, args...) log_message(log_level, args) +#define LOG_HEXDUMP(log_level, message, buffer, length) \ + log_hexdump(log_level, message, buffer, length) /* Since log_message() returns a value ensure that the elided versions of * LOG_DEVEL and LOG_DEVEL_HEXDUMP also "fake" returning the success value @@ -345,6 +360,12 @@ log_end(void); enum logReturns log_message(const enum logLevels lvl, const char *msg, ...) printflike(2, 3); +enum logReturns +log_hexdump(const enum logLevels log_level, + const char *msg, + const char *p, + int len); + /** * the log function that all files use to log an event, * with the function name and file line. diff --git a/common/string_calls.c b/common/string_calls.c index 6023347b..18b6acf4 100644 --- a/common/string_calls.c +++ b/common/string_calls.c @@ -25,8 +25,9 @@ #include <strings.h> #include <stdlib.h> -#include "string_calls.h" +#include "log.h" #include "os_calls.h" +#include "string_calls.h" unsigned int g_format_info_string(char *dest, unsigned int len, @@ -471,6 +472,129 @@ g_bytes_to_hexstr(const void *bytes, int num_bytes, char *out_str, } /*****************************************************************************/ +/* convert a byte array into a hex dump */ +char * +g_bytes_to_hexdump(const char *src, int len) +{ + unsigned char *line; + int i; + int dump_number_lines; + int dump_line_length; + int dump_length; + int dump_offset; + int thisline; + int offset; + char *dump_buffer; + +#define HEX_DUMP_SOURCE_BYTES_PER_LINE (16) +#ifdef _WIN32 +#define HEX_DUMP_NEWLINE_SIZE (2) +#else +#ifdef _MACOS +#define HEX_DUMP_NEWLINE_SIZE (1) +#else +#define HEX_DUMP_NEWLINE_SIZE (1) +#endif +#endif + + dump_line_length = (4 + 3 /* = 4 offset + 3 space */ + + ((2 + 1) * HEX_DUMP_SOURCE_BYTES_PER_LINE) /* + (2 hex char + 1 space) per source byte */ + + 2 /* + 2 space */ + + HEX_DUMP_SOURCE_BYTES_PER_LINE + + HEX_DUMP_NEWLINE_SIZE); + + dump_number_lines = (len / HEX_DUMP_SOURCE_BYTES_PER_LINE) + 1; /* +1 to round up */ + dump_length = (dump_number_lines *dump_line_length /* hex dump lines */ + + 1); /* terminating NULL */ + dump_buffer = (char *)g_malloc(dump_length, 1); + if (dump_buffer == NULL) + { + LOG_DEVEL(LOG_LEVEL_WARNING, + "Failed to allocate buffer for hex dump of size %d", + dump_length); + return NULL; + } + + line = (unsigned char *)src; + offset = 0; + dump_offset = 0; + + while (offset < len) + { + g_sprintf(dump_buffer + dump_offset, "%04x ", offset); + dump_offset += 7; + thisline = len - offset; + + if (thisline > HEX_DUMP_SOURCE_BYTES_PER_LINE) + { + thisline = HEX_DUMP_SOURCE_BYTES_PER_LINE; + } + + for (i = 0; i < thisline; i++) + { + g_sprintf(dump_buffer + dump_offset, "%02x ", line[i]); + dump_offset += 3; + } + + for (; i < HEX_DUMP_SOURCE_BYTES_PER_LINE; i++) + { + dump_buffer[dump_offset++] = ' '; + dump_buffer[dump_offset++] = ' '; + dump_buffer[dump_offset++] = ' '; + } + + dump_buffer[dump_offset++] = ' '; + dump_buffer[dump_offset++] = ' '; + + for (i = 0; i < thisline; i++) + { + dump_buffer[dump_offset++] = (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'; + } + + for (; i < HEX_DUMP_SOURCE_BYTES_PER_LINE; i++) + { + dump_buffer[dump_offset++] = ' '; + } + +#ifdef _WIN32 + dump_buffer[dump_offset++] = '\r'; + dump_buffer[dump_offset++] = '\n'; +#else +#ifdef _MACOS + dump_buffer[dump_offset++] = '\r'; +#else + dump_buffer[dump_offset++] = '\n'; +#endif +#endif + offset += thisline; + line += thisline; + + + if (dump_offset % dump_line_length != 0) + { + LOG_DEVEL(LOG_LEVEL_WARNING, + "BUG: dump_offset (%d) at the end of a line is not a " + "multiple of the line length (%d)", + dump_offset, dump_line_length); + } + + } + if (dump_offset > dump_length) + { + LOG_DEVEL(LOG_LEVEL_WARNING, + "BUG: dump_offset (%d) is larger than the dump_buffer length (%d)", + dump_offset, dump_length); + dump_buffer[0] = '\0'; + return dump_buffer; + } + + /* replace the last new line with the end of the string since log_message + will add a new line */ + dump_buffer[dump_offset - HEX_DUMP_NEWLINE_SIZE] = '\0'; + return dump_buffer; +} + +/*****************************************************************************/ int g_pos(const char *str, const char *to_find) { diff --git a/common/string_calls.h b/common/string_calls.h index cce332ac..4b20a595 100644 --- a/common/string_calls.h +++ b/common/string_calls.h @@ -80,6 +80,29 @@ g_bool2text(int value); int g_text2bool(const char *s); +/** + * Converts a binary array into a hux dump suitable for displaying to a user. + * + * The format of the hex dump is: + * 0000 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 ................ + * /\ /\ /\ + * | | | + * | | ascii representation of bytes + * | hex representation of bytes + * offset from beining of the byte array in hex + * + * Note: the ascii representation uses '.' for all non-printable + * characters (eg. below 32 or above 127). + * + * Note: the string contains embedded new lines, but is not new line terminated. + * + * @param[in] src Value to convert + * @param[in] len The number of bytes in src to convert + * @return string containing the hex dump that must be free'd by the caller + */ +char * +g_bytes_to_hexdump(const char *src, int len); + int g_strlen(const char *text); const char *g_strchr(const char *text, int c); char *g_strcpy(char *dest, const char *src); |