// -*- mode: c++; c-basic-offset: 2; -*- #include "common.hh" #include #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(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] & 0xff, data[i + 1] & 0xff, data[i + 2] & 0xff, data[i + 3] & 0xff, data[i + 4] & 0xff, data[i + 5] & 0xff, data[i + 6] & 0xff, data[i + 7] & 0xff); 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(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] & 0xff, data[i + 1] & 0xff, data[i + 2] & 0xff, data[i + 3] & 0xff, data[i + 4] & 0xff, data[i + 5] & 0xff, data[i + 6] & 0xff, data[i + 7] & 0xff); 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] & 0xff); 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(length)); text->append(tmp, len, addr); } } } // static uint8_t const HexDump::ADDRESS = 1 << 0; // static uint8_t const HexDump::CHARS = 1 << 1;