/* * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "util/hexdump.h" #include #include // offset + gap + 8 hex bytes + gap + 8 hex bytes + gap + 8 ascii bytes // + mini gap + 8 ascii bytes + null: #define LINE_BUFFER_LENGTH (4 + 2 + (3 * 8) + 2 + (3 * 8) + 2 + 8 + 1 + 8 + 1) void hexdump(const char *src_filename, int src_line_number, int level, const uint8_t *data, size_t length, HexdumpLineCallback write_line_cb) { char line_buffer[LINE_BUFFER_LENGTH]; unsigned int offset = 0; while (offset < length) { unsigned int buffer_offset = 0; // Print data line offset snprintf(line_buffer, LINE_BUFFER_LENGTH, "%04x ", offset); buffer_offset += 6; // Print the hex bytes const unsigned int num_line_bytes = ((length - offset) > 16) ? 16 : (length - offset); for (unsigned int i = 0; i < num_line_bytes; ++i) { if (i == 8) { line_buffer[buffer_offset++] = ' '; } snprintf(line_buffer + buffer_offset, LINE_BUFFER_LENGTH - buffer_offset, "%02x ", data[offset + i]); buffer_offset += 3; } // Calculate and apply padding between the hex dump and the ascii dump. unsigned int required_padding = 2; if (num_line_bytes < 16) { // If we're printing a partial line, pad out the rest so the // ascii lines up. required_padding += (16 - num_line_bytes) * 3; if (num_line_bytes <= 8) { // Account for the gap between the 8 byte hex blocks. required_padding += 1; } } memset(line_buffer + buffer_offset, ' ', required_padding); buffer_offset += required_padding; // Print the ASCII bytes for (unsigned int i = 0; i < num_line_bytes; ++i) { if (i == 8) { line_buffer[buffer_offset++] = ' '; } char c = data[offset + i]; if (c < 32 || c > 126 || c == '`') // ` is used for log hash string delimiting { c = '.'; } line_buffer[buffer_offset++] = c; } // No need to pad after a partial ascii line, since we don't line up // anything after it. // Null terminate and print. line_buffer[buffer_offset] = 0; write_line_cb(level, src_filename, src_line_number, line_buffer); offset += 16; } }