mirror of
https://github.com/nghttp2/nghttp2.git
synced 2025-12-06 18:18:52 +08:00
Rewrite hexdump
This commit is contained in:
202
src/util.cc
202
src/util.cc
@@ -1348,66 +1348,166 @@ StringRef make_hostport(BlockAllocator &balloc, const StringRef &host,
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void hexdump8(FILE *out, const uint8_t *first, const uint8_t *last) {
|
uint8_t *hexdump_addr(uint8_t *dest, size_t addr) {
|
||||||
auto stop = std::min(first + 8, last);
|
// Lower 32 bits are displayed.
|
||||||
for (auto k = first; k != stop; ++k) {
|
for (size_t i = 0; i < 4; ++i) {
|
||||||
fprintf(out, "%02x ", *k);
|
auto a = (addr >> (3 - i) * 8) & 0xff;
|
||||||
|
|
||||||
|
*dest++ = LOWER_XDIGITS[a >> 4];
|
||||||
|
*dest++ = LOWER_XDIGITS[a & 0xf];
|
||||||
}
|
}
|
||||||
// each byte needs 3 spaces (2 hex value and space)
|
|
||||||
for (; stop != first + 8; ++stop) {
|
return dest;
|
||||||
fputs(" ", out);
|
|
||||||
}
|
|
||||||
// we have extra space after 8 bytes
|
|
||||||
fputc(' ', out);
|
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void hexdump(FILE *out, const uint8_t *src, size_t len) {
|
namespace {
|
||||||
if (len == 0) {
|
uint8_t *hexdump_ascii(uint8_t *dest, const uint8_t *data, size_t datalen) {
|
||||||
return;
|
*dest++ = '|';
|
||||||
|
|
||||||
|
for (size_t i = 0; i < datalen; ++i) {
|
||||||
|
if (0x20 <= data[i] && data[i] <= 0x7e) {
|
||||||
|
*dest++ = data[i];
|
||||||
|
} else {
|
||||||
|
*dest++ = '.';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
size_t buflen = 0;
|
|
||||||
|
*dest++ = '|';
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
uint8_t *hexdump8(uint8_t *dest, const uint8_t *data, size_t datalen) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < datalen; ++i) {
|
||||||
|
*dest++ = LOWER_XDIGITS[data[i] >> 4];
|
||||||
|
*dest++ = LOWER_XDIGITS[data[i] & 0xf];
|
||||||
|
*dest++ = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < 8; ++i) {
|
||||||
|
*dest++ = ' ';
|
||||||
|
*dest++ = ' ';
|
||||||
|
*dest++ = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
uint8_t *hexdump16(uint8_t *dest, const uint8_t *data, size_t datalen) {
|
||||||
|
if (datalen > 8) {
|
||||||
|
dest = hexdump8(dest, data, 8);
|
||||||
|
*dest++ = ' ';
|
||||||
|
dest = hexdump8(dest, data + 8, datalen - 8);
|
||||||
|
*dest++ = ' ';
|
||||||
|
} else {
|
||||||
|
dest = hexdump8(dest, data, datalen);
|
||||||
|
*dest++ = ' ';
|
||||||
|
dest = hexdump8(dest, nullptr, 0);
|
||||||
|
*dest++ = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
uint8_t *hexdump_line(uint8_t *dest, const uint8_t *data, size_t datalen,
|
||||||
|
size_t addr) {
|
||||||
|
dest = hexdump_addr(dest, addr);
|
||||||
|
*dest++ = ' ';
|
||||||
|
*dest++ = ' ';
|
||||||
|
|
||||||
|
dest = hexdump16(dest, data, datalen);
|
||||||
|
|
||||||
|
return hexdump_ascii(dest, data, datalen);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int hexdump_write(int fd, const uint8_t *data, size_t datalen) {
|
||||||
|
ssize_t nwrite;
|
||||||
|
|
||||||
|
for (; (nwrite = write(fd, data, datalen)) == -1 && errno == EINTR;)
|
||||||
|
;
|
||||||
|
if (nwrite == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int hexdump(FILE *out, const void *data, size_t datalen) {
|
||||||
|
if (datalen == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// min_space is the additional minimum space that the buffer must
|
||||||
|
// accept, which is the size of a single full line output + one
|
||||||
|
// repeat line marker ("*\n"). If the remaining buffer size is less
|
||||||
|
// than that, flush the buffer and reset.
|
||||||
|
constexpr size_t min_space = 79 + 2;
|
||||||
|
|
||||||
|
auto fd = fileno(out);
|
||||||
|
std::array<uint8_t, 4096> buf;
|
||||||
|
auto last = buf.data();
|
||||||
|
auto in = reinterpret_cast<const uint8_t *>(data);
|
||||||
auto repeated = false;
|
auto repeated = false;
|
||||||
std::array<uint8_t, 16> buf{};
|
|
||||||
auto end = src + len;
|
for (size_t offset = 0; offset < datalen; offset += 16) {
|
||||||
auto i = src;
|
auto n = datalen - offset;
|
||||||
for (;;) {
|
auto s = in + offset;
|
||||||
auto nextlen =
|
|
||||||
std::min(static_cast<size_t>(16), static_cast<size_t>(end - i));
|
if (n >= 16) {
|
||||||
if (nextlen == buflen &&
|
n = 16;
|
||||||
std::equal(std::begin(buf), std::begin(buf) + buflen, i)) {
|
|
||||||
// as long as adjacent 16 bytes block are the same, we just
|
if (offset > 0) {
|
||||||
// print single '*'.
|
if (std::equal(s - 16, s, s)) {
|
||||||
if (!repeated) {
|
if (repeated) {
|
||||||
repeated = true;
|
continue;
|
||||||
fputs("*\n", out);
|
}
|
||||||
}
|
|
||||||
i += nextlen;
|
repeated = true;
|
||||||
continue;
|
|
||||||
}
|
*last++ = '*';
|
||||||
repeated = false;
|
*last++ = '\n';
|
||||||
fprintf(out, "%08lx", static_cast<unsigned long>(i - src));
|
|
||||||
if (i == end) {
|
continue;
|
||||||
fputc('\n', out);
|
}
|
||||||
break;
|
|
||||||
}
|
repeated = false;
|
||||||
fputs(" ", out);
|
|
||||||
hexdump8(out, i, end);
|
|
||||||
hexdump8(out, i + 8, std::max(i + 8, end));
|
|
||||||
fputc('|', out);
|
|
||||||
auto stop = std::min(i + 16, end);
|
|
||||||
buflen = stop - i;
|
|
||||||
auto p = buf.data();
|
|
||||||
for (; i != stop; ++i) {
|
|
||||||
*p++ = *i;
|
|
||||||
if (0x20 <= *i && *i <= 0x7e) {
|
|
||||||
fputc(*i, out);
|
|
||||||
} else {
|
|
||||||
fputc('.', out);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fputs("|\n", out);
|
|
||||||
|
last = hexdump_line(last, s, n, offset);
|
||||||
|
*last++ = '\n';
|
||||||
|
|
||||||
|
auto len = static_cast<size_t>(last - buf.data());
|
||||||
|
if (len + min_space > buf.size()) {
|
||||||
|
if (hexdump_write(fd, buf.data(), len) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = buf.data();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last = hexdump_addr(last, datalen);
|
||||||
|
*last++ = '\n';
|
||||||
|
|
||||||
|
auto len = static_cast<size_t>(last - buf.data());
|
||||||
|
if (len) {
|
||||||
|
return hexdump_write(fd, buf.data(), len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void put_uint16be(uint8_t *buf, uint16_t n) {
|
void put_uint16be(uint8_t *buf, uint16_t n) {
|
||||||
|
|||||||
@@ -840,8 +840,10 @@ StringRef make_http_hostport(OutputIt first, const StringRef &host,
|
|||||||
return StringRef{first, p};
|
return StringRef{first, p};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dumps |src| of length |len| in the format similar to `hexdump -C`.
|
// hexdump dumps |data| of length |datalen| in the format similar to
|
||||||
void hexdump(FILE *out, const uint8_t *src, size_t len);
|
// hexdump(1) with -C option. This function returns 0 if it succeeds,
|
||||||
|
// or -1.
|
||||||
|
int hexdump(FILE *out, const void *data, size_t datalen);
|
||||||
|
|
||||||
// Copies 2 byte unsigned integer |n| in host byte order to |buf| in
|
// Copies 2 byte unsigned integer |n| in host byte order to |buf| in
|
||||||
// network byte order.
|
// network byte order.
|
||||||
|
|||||||
Reference in New Issue
Block a user