Skip to content

Commit 177d65d

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

File tree

4 files changed

+151
-0
lines changed

4 files changed

+151
-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

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