Skip to content

Commit c27fae1

Browse files
committed
util:hex-dumper
1 parent d9245cd commit c27fae1

File tree

4 files changed

+149
-0
lines changed

4 files changed

+149
-0
lines changed

util/BUILD

+23
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,29 @@ cc_test(
9292
],
9393
)
9494

95+
cc_library(
96+
name = "hex-dumper",
97+
srcs = ["hex-dumper.cc"],
98+
hdrs = ["hex-dumper.h"],
99+
deps = [
100+
"//base:types",
101+
"//io:file",
102+
"//io:file-utils",
103+
"@com_google_absl//absl/container:fixed_array",
104+
],
105+
)
106+
107+
cc_test(
108+
name = "hex-dumper_test",
109+
srcs = ["hex-dumper_test.cc"],
110+
deps = [
111+
":hex-dumper",
112+
"//base:types",
113+
"//io:memory-file",
114+
"@com_google_googletest//:gtest_main",
115+
],
116+
)
117+
95118
cc_library(
96119
name = "pod",
97120
hdrs = ["pod.h"],

util/hex-dumper.cc

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include "util/hex-dumper.h"
2+
3+
#include "io/file-utils.h"
4+
5+
namespace util {
6+
namespace {
7+
8+
inline char to_hex(int value) {
9+
return value < 10 ? '0' + value : 'a' + value - 10;
10+
}
11+
12+
inline char to_char(int value) {
13+
return value >= 32 && value <= 127 ? value : '.';
14+
}
15+
16+
void put_uint8_hex(uint8_t value, char output[2]) {
17+
output[0] = to_hex(value >> 4);
18+
output[1] = to_hex(value & 0xf);
19+
}
20+
21+
void put_uint32_hex(uint32_t value, char output[8]) {
22+
for (int i = 0; i < 8; ++i) {
23+
output[i] = to_hex(value >> 28);
24+
value <<= 4;
25+
}
26+
}
27+
28+
} // namespace
29+
30+
HexDumper::HexDumper(int width)
31+
: width_(width),
32+
buffer_(char_start() + width_ + 1, ' ') {}
33+
34+
std::error_code HexDumper::dump(
35+
uint32_t offset, ConstBufferSpan input, io::File &output) {
36+
while (input.size() >= width_) {
37+
std::error_code ec = dump_line(offset, input, output);
38+
if (ec) {
39+
return ec;
40+
}
41+
offset += width_;
42+
input.remove_prefix(width_);
43+
}
44+
if (!input.empty()) {
45+
std::error_code ec = dump_line(offset, input, output);
46+
if (ec) {
47+
return ec;
48+
}
49+
}
50+
return {};
51+
}
52+
53+
std::error_code HexDumper::dump_line(
54+
uint32_t offset, ConstBufferSpan input, io::File &output) {
55+
const size_t size = std::min(input.size(), width_);
56+
put_uint32_hex(offset, &buffer_[0]);
57+
buffer_[8] = ':';
58+
size_t i;
59+
for (i = 0; i < size; ++i) {
60+
put_uint8_hex(input[i], &buffer_[i * 5 / 2 + 10]);
61+
buffer_[char_start() + i] = to_char(input[i]);
62+
}
63+
for (; i < width_; ++i) {
64+
buffer_[i * 5 / 2 + 10] = ' ';
65+
buffer_[i * 5 / 2 + 11] = ' ';
66+
}
67+
buffer_[char_start() + size] = '\n';
68+
return io::write(output, {buffer_.data(), char_start() + size + 1});
69+
}
70+
71+
} // namespace util

util/hex-dumper.h

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#ifndef _UTIL_HEX_DUMPER_H
2+
#define _UTIL_HEX_DUMPER_H
3+
4+
#include <cstddef>
5+
#include <cstdint>
6+
#include <system_error>
7+
8+
#include "absl/container/fixed_array.h"
9+
#include "base/types.h"
10+
#include "io/file.h"
11+
12+
namespace util {
13+
14+
class HexDumper {
15+
public:
16+
explicit HexDumper(int width = 16);
17+
18+
std::error_code dump(
19+
uint32_t offset, ConstBufferSpan input, io::File &output);
20+
std::error_code dump_line(
21+
uint32_t offset, ConstBufferSpan input, io::File &output);
22+
23+
private:
24+
size_t char_start() const { return (width_ * 5 + 23) / 2; }
25+
26+
const size_t width_;
27+
absl::FixedArray<char, 80> buffer_;
28+
};
29+
30+
} // namespace util
31+
32+
#endif // _UTIL_HEX_DUMPER_H

util/hex-dumper_test.cc

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include "util/hex-dumper.h"
2+
3+
#include <string_view>
4+
#include <system_error>
5+
#include <gtest/gtest.h>
6+
7+
#include "base/types.h"
8+
#include "io/memory-file.h"
9+
10+
namespace util {
11+
namespace {
12+
13+
TEST(DumpHexTest, basic) {
14+
HexDumper dumper(7);
15+
io::MemoryFile file;
16+
EXPECT_EQ(dumper.dump(12, "hello world\n", file), std::error_code());
17+
EXPECT_EQ(std::string_view(ConstBufferSpan(file.content())),
18+
"0000000c: 6865 6c6c 6f20 77 hello w\n"
19+
"00000013: 6f72 6c64 0a orld.\n");
20+
}
21+
22+
} // namespace
23+
} // namespace util

0 commit comments

Comments
 (0)