summaryrefslogtreecommitdiff
path: root/src/gui_hexdump.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui_hexdump.cc')
-rw-r--r--src/gui_hexdump.cc136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/gui_hexdump.cc b/src/gui_hexdump.cc
new file mode 100644
index 0000000..fbda64d
--- /dev/null
+++ b/src/gui_hexdump.cc
@@ -0,0 +1,136 @@
+// -*- mode: c++; c-basic-offset: 2; -*-
+
+#include "common.hh"
+
+#include <string.h>
+
+#include "gui_attrtext.hh"
+#include "gui_hexdump.hh"
+
+namespace {
+
+AttributedText::Attribute const addr(0x90, 0x90, 0x90);
+
+inline size_t append(char* out, size_t max, char const* in, size_t len) {
+ if (len <= max) {
+ memcpy(out, in, len);
+ return len;
+ }
+ return 0;
+}
+
+inline size_t safe(char* out, size_t max, char const* in, size_t len) {
+ size_t ret = 0;
+ for (; len--; ++in) {
+ if (*in >= ' ' && *in < '\x7f') {
+ ret += append(out + ret, max - ret, in, 1);
+ continue;
+ }
+ switch (*in) {
+ case '\r':
+ ret += append(out + ret, max - ret, "\xe2\x86\xb5", 3); // U+21B5
+ break;
+ case '\n':
+ ret += append(out + ret, max - ret, "\xc2\xb6", 2); // U+00B6
+ break;
+ case '\x8':
+ ret += append(out + ret, max - ret, "\xe2\x8c\xab", 3); // U+232B
+ break;
+ case '\t':
+ ret += append(out + ret, max - ret, "\xe2\x86\xb9", 3); // U+21B9
+ break;
+ default:
+ ret += append(out + ret, max - ret, "\xef\xbf\xbd", 3); // U+FFFD
+ break;
+ }
+ }
+ return ret;
+}
+
+} // namespace
+
+
+// static
+void HexDump::write(AttributedText* text, uint8_t flags, std::string const& str,
+ size_t start, size_t length) {
+ if (start >= str.size()) return;
+ length = std::min(length, str.size() - start);
+ if (length == 0) return;
+
+ AttributedText::Attribute box(0x90, 0x90, 0x90);
+ box.set_bold(true);
+
+ size_t i = 0;
+ auto data = str.data() + start;
+ char tmp[80];
+ char tmp2[64];
+ int len;
+ while (i + 16 <= length) {
+ if (flags & ADDRESS) {
+ len = snprintf(tmp, sizeof(tmp), "%08lx ", static_cast<unsigned long>(i));
+ text->append(tmp, len, addr);
+ }
+ auto x = tmp2;
+ for (char c = 0; c < 2; ++c) {
+ len = snprintf(tmp, sizeof(tmp), "%02x %02x %02x %02x %02x %02x %02x %02x",
+ data[i], data[i + 1], data[i + 2], data[i + 3], data[i + 4], data[i + 5], data[i + 6],
+ data[i + 7]);
+ if (flags & CHARS) {
+ x += safe(x, sizeof(tmp2) - (x - tmp2), data + i, 8);
+ }
+ i += 8;
+ text->append(tmp, len);
+ if (c == 0) text->append(" ", 2);
+ }
+ if (flags & CHARS) {
+ text->append(" |", 3, box);
+ text->append(tmp2, x - tmp2);
+ text->append("|\n", 2, box);
+ } else {
+ text->append("\n", 1);
+ }
+ }
+ if (i < length) {
+ if (flags & ADDRESS) {
+ len = snprintf(tmp, sizeof(tmp), "%08lx ", static_cast<unsigned long>(i));
+ text->append(tmp, len, addr);
+ }
+ auto x = tmp2;
+ if (i + 8 <= length) {
+ len = snprintf(tmp, sizeof(tmp), "%02x %02x %02x %02x %02x %02x %02x %02x",
+ data[i], data[i + 1], data[i + 2], data[i + 3], data[i + 4], data[i + 5], data[i + 6],
+ data[i + 7]);
+ if (flags & CHARS) {
+ x += safe(x, sizeof(tmp2) - (x - tmp2), data + i, 8);
+ }
+ i += 8;
+ text->append(tmp, len);
+ text->append(" ");
+ }
+ for (; i < length; ++i) {
+ len = snprintf(tmp, sizeof(tmp), "%02x ", data[i]);
+ if (flags & CHARS) x += safe(x, sizeof(tmp2) - (x - tmp2), data + i, 1);
+ text->append(tmp, len);
+ }
+ if (flags & CHARS) {
+ auto extra = 16 - length % 16;
+ extra = extra * 3 + (extra > 8 ? 1 : 0);
+ memset(tmp, ' ', extra);
+ text->append(tmp, extra);
+ text->append(" |", 2, box);
+ text->append(tmp2, x - tmp2);
+ text->append("|\n", 2, box);
+ } else {
+ text->append("\n", 1);
+ }
+ if (flags & ADDRESS) {
+ len = snprintf(tmp, sizeof(tmp), "%08lx\n", static_cast<unsigned long>(length));
+ text->append(tmp, len, addr);
+ }
+ }
+}
+
+// static
+uint8_t const HexDump::ADDRESS = 1 << 0;
+// static
+uint8_t const HexDump::CHARS = 1 << 1;