From 9806e2868d34422b55c975ea72b7a74893516084 Mon Sep 17 00:00:00 2001
From: Benny Baumann <BenBE@geshi.org>
Date: Fri, 8 Jan 2021 18:27:59 +0100
Subject: [PATCH] add: Utility functions for generating hex dumps

---
 src/utils/hexdump.cpp | 201 ++++++++++++++++++++++++++++++++++++++++++
 src/utils/hexdump.hpp |  86 ++++++++++++++++++
 2 files changed, 287 insertions(+)
 create mode 100644 src/utils/hexdump.cpp
 create mode 100644 src/utils/hexdump.hpp

diff --git a/src/utils/hexdump.cpp b/src/utils/hexdump.cpp
new file mode 100644
index 0000000..c20c25c
--- /dev/null
+++ b/src/utils/hexdump.cpp
@@ -0,0 +1,201 @@
+#include "utils/hexdump.hpp"
+
+#include <algorithm>
+#include <iomanip>
+#include <sstream>
+
+
+namespace rmrf::utils {
+
+void hexdump_to_stream(
+    std::ostream &os,
+    size_t bytes_per_line,
+    size_t bytes_per_group,
+    size_t space_per_byte,
+    size_t space_per_group,
+    off_t offset_start,
+    off_t offset_end,
+    off_t voffset_at_zero,
+    bool display_textual,
+    bool display_uppercase,
+    hexdump_getdata_t get_data
+) {
+    off_t offset_line = voffset_at_zero + offset_start;
+
+    for (
+        off_t offset = offset_start;
+        offset <= offset_end;
+        offset += (off_t)bytes_per_line, offset_line += (off_t)bytes_per_line
+    ) {
+        if (display_uppercase) {
+            os << std::uppercase;
+        }
+
+        os << std::setw(8) << std::setfill('0') << std::hex << (size_t)offset_line << " : ";
+
+        std::string display_textual_data(bytes_per_line, ' ');
+        size_t display_textual_last = 0;
+
+        std::stringstream display_hex_data;
+
+        for (size_t idx = 0; idx < bytes_per_line; idx++) {
+            off_t offset_data = offset + (off_t)idx;
+            auto data = get_data(offset_data);
+
+            if (space_per_group && idx && !(idx % bytes_per_group)) {
+                display_hex_data << std::string(space_per_group, ' ');
+            }
+
+            if (space_per_byte && idx) {
+                display_hex_data << std::string(space_per_byte, ' ');
+            }
+
+            if (std::holds_alternative<hexdump_data_t>(data)) {
+                hexdump_data_t hd_data = std::get<hexdump_data_t>(data);
+
+                if (hexdump_data_t::unknown == hd_data) {
+                    display_hex_data << "??";
+                    display_textual_last = idx + 1;
+                    display_textual_data[idx] = '?';
+                } else {
+                    display_hex_data << "  ";
+                    display_textual_data[idx] = ' ';
+                }
+            } else if (std::holds_alternative<uint8_t>(data)) {
+                uint8_t hd_data = std::get<uint8_t>(data);
+
+                if (display_uppercase) {
+                    display_hex_data << std::uppercase;
+                }
+
+                display_hex_data << std::setw(2) << std::setfill('0') << std::hex << (uint32_t)hd_data;
+                display_textual_last = idx + 1;
+                display_textual_data[idx] = (hd_data >= 32 && hd_data < 127) ? (char)hd_data : '.';
+            } else {
+                display_hex_data << "!!";
+                display_textual_last = idx + 1;
+                display_textual_data[idx] = '!';
+            }
+        }
+
+        if (display_textual) {
+            os << display_hex_data.str();
+            os << " : ";
+            os << display_textual_data.substr(0, display_textual_last);
+        } else {
+            os << display_hex_data.str().substr(0, std::max(size_t{}, display_textual_last * 2 + ((off_t)display_textual_last - 1) * space_per_byte + (((off_t)display_textual_last - 1) / bytes_per_group) * space_per_group));
+        }
+
+        os << "\n";
+    }
+}
+
+void hexdump_to_stream(
+    std::ostream &os,
+    size_t bytes_per_line,
+    size_t bytes_per_group,
+    size_t space_per_byte,
+    size_t space_per_group,
+    off_t offset_start,
+    off_t offset_end,
+    off_t voffset_at_zero,
+    bool display_textual,
+    bool display_uppercase,
+    uint8_t* buffer,
+    size_t buffer_length
+) {
+    hexdump_to_stream(
+        os,
+        bytes_per_line,
+        bytes_per_group,
+        space_per_byte,
+        space_per_group,
+        offset_start,
+        offset_end,
+        voffset_at_zero,
+        display_textual,
+        display_uppercase,
+        make_getdata_t(buffer, buffer_length)
+    );
+}
+
+std::string hexdump_to_string(
+    size_t bytes_per_line,
+    size_t bytes_per_group,
+    size_t space_per_byte,
+    size_t space_per_group,
+    off_t offset_start,
+    off_t offset_end,
+    off_t voffset_at_zero,
+    bool display_textual,
+    bool display_uppercase,
+    hexdump_getdata_t get_data
+) {
+    std::stringstream ss;
+    hexdump_to_stream(
+        ss,
+        bytes_per_line,
+        bytes_per_group,
+        space_per_byte,
+        space_per_group,
+        offset_start,
+        offset_end,
+        voffset_at_zero,
+        display_textual,
+        display_uppercase,
+        get_data
+    );
+    return ss.str();
+}
+
+std::string hexdump_to_string(
+    size_t bytes_per_line,
+    size_t bytes_per_group,
+    size_t space_per_byte,
+    size_t space_per_group,
+    off_t offset_start,
+    off_t offset_end,
+    off_t voffset_at_zero,
+    bool display_textual,
+    bool display_uppercase,
+    uint8_t* buffer,
+    size_t buffer_length
+) {
+    return hexdump_to_string(
+        bytes_per_line,
+        bytes_per_group,
+        space_per_byte,
+        space_per_group,
+        offset_start,
+        offset_end,
+        voffset_at_zero,
+        display_textual,
+        display_uppercase,
+        make_getdata_t(buffer, buffer_length)
+    );
+}
+
+hexdump_getdata_t make_getdata_t(
+    uint8_t* buffer,
+    size_t buflen
+) {
+    return [buffer, buflen](off_t offset) -> std::variant<uint8_t, hexdump_data_t> {
+        if (offset < 0) {
+            return hexdump_data_t::non_existent;
+        } else if ((size_t)offset >= buflen) {
+            return hexdump_data_t::non_existent;
+        } else {
+            return buffer[offset];
+        }
+    };
+}
+
+off_t hexdump_align(
+    off_t voffset_at_zero,
+    size_t bytes_per_line
+) {
+    off_t offset = voffset_at_zero % (off_t)bytes_per_line;
+    return voffset_at_zero - offset;
+}
+
+}
diff --git a/src/utils/hexdump.hpp b/src/utils/hexdump.hpp
new file mode 100644
index 0000000..3a83a82
--- /dev/null
+++ b/src/utils/hexdump.hpp
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <stdint.h>
+
+#include <functional>
+#include <iostream>
+#include <string>
+#include <variant>
+
+
+namespace rmrf::utils {
+
+enum class hexdump_data_t : uint8_t {
+    non_existent,
+    unknown
+};
+
+typedef std::function<std::variant<uint8_t, hexdump_data_t>(off_t)> hexdump_getdata_t;
+
+void hexdump_to_stream(
+    std::ostream &os,
+    size_t bytes_per_line,
+    size_t bytes_per_group,
+    size_t space_per_byte,
+    size_t space_per_group,
+    off_t offset_start,
+    off_t offset_end,
+    off_t voffset_at_zero,
+    bool display_textual,
+    bool display_uppercase,
+    hexdump_getdata_t get_data
+);
+
+void hexdump_to_stream(
+    std::ostream &os,
+    size_t bytes_per_line,
+    size_t bytes_per_group,
+    size_t space_per_byte,
+    size_t space_per_group,
+    off_t offset_start,
+    off_t offset_end,
+    off_t voffset_at_zero,
+    bool display_textual,
+    bool display_uppercase,
+    uint8_t* buffer,
+    size_t buffer_length
+);
+
+std::string hexdump_to_string(
+    size_t bytes_per_line,
+    size_t bytes_per_group,
+    size_t space_per_byte,
+    size_t space_per_group,
+    off_t offset_start,
+    off_t offset_end,
+    off_t voffset_at_zero,
+    bool display_textual,
+    bool display_uppercase,
+    hexdump_getdata_t get_data
+);
+
+std::string hexdump_to_string(
+    size_t bytes_per_line,
+    size_t bytes_per_group,
+    size_t space_per_byte,
+    size_t space_per_group,
+    off_t offset_start,
+    off_t offset_end,
+    off_t voffset_at_zero,
+    bool display_textual,
+    bool display_uppercase,
+    uint8_t* buffer,
+    size_t buffer_length
+);
+
+hexdump_getdata_t make_getdata_t(
+    uint8_t* buffer,
+    size_t buflen
+);
+
+off_t hexdump_align(
+    off_t voffset_at_zero,
+    size_t bytes_per_line
+);
+
+}
-- 
GitLab