Skip to content

Commit af04a67

Browse files
BWF: Add UnHex (hexadecimal encoding to raw bytes).
1 parent 1229630 commit af04a67

File tree

3 files changed

+52
-2
lines changed

3 files changed

+52
-2
lines changed

code/include/swoc/bwf_ex.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,23 @@ SubText<ARG>
206206
Optional(TextView fmt, ARG &&arg) {
207207
return detail::Optional(meta::CaseArg, fmt, std::forward<ARG>(arg));
208208
}
209+
210+
/** Convert from ASCII hexadecimal to raw bytes.
211+
*
212+
* E.g. if the source span contains "4576696c20446176652052756c7a" then "Evil Dave Rulz" is the output.
213+
* For format specifier support, on lhe max width is used. Any @c MemSpan compatible class can be used
214+
* as the target, including @c std::string and @c std::string_view.
215+
*
216+
* @code
217+
* void f(std::string const& str) {
218+
* w.print("{}", bwf::UnHex(str));
219+
* // ...
220+
* @endcode
221+
*/
222+
struct UnHex {
223+
UnHex(MemSpan<void const> const& span) : _span(span) {}
224+
MemSpan<void const> _span; ///< Source span.
225+
};
209226
} // namespace bwf
210227

211228
/** Repeatedly output a pattern.
@@ -237,6 +254,8 @@ BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::Errno const
237254
*/
238255
BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::Date const &date);
239256

257+
BufferWriter &bwformat(BufferWriter &w, bwf::Spec const& spec, bwf::UnHex const& obj);
258+
240259
/** Output a nested formatted string.
241260
*
242261
* @tparam Args Argument pack for @a subtext.

code/src/bw_format.cc

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -960,8 +960,8 @@ bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::Pattern const &pattern) {
960960
return w;
961961
}
962962

963-
swoc::BufferWriter &
964-
bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const &spec, std::error_code const &ec) {
963+
BufferWriter &
964+
bwformat(BufferWriter &w, bwf::Spec const &spec, std::error_code const &ec) {
965965
static const auto G_CAT = &std::generic_category();
966966
static const auto S_CAT = &std::system_category();
967967

@@ -984,6 +984,17 @@ bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const &spec, std::error_code con
984984
return w;
985985
}
986986

987+
BufferWriter&
988+
bwformat(BufferWriter &w, bwf::Spec const& spec, bwf::UnHex const& obj) {
989+
auto span { obj._span };
990+
size_t limit = spec._max;
991+
while (span.size() >= 2 && limit--) {
992+
auto b = svto_radix<16>(span.clip_prefix(2).rebind<char const>());
993+
w.write(b);
994+
}
995+
return w;
996+
}
997+
987998
}} // namespace swoc::SWOC_VERSION_NS
988999

9891000
namespace std {

unit_tests/test_bw_format.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,26 @@ TEST_CASE("BWFormat numerics", "[bwprint][bwformat]") {
231231
REQUIRE(bw.view() == "Char 'a'");
232232
bw.clear().print("Byte '{}'", uint8_t{'a'});
233233
REQUIRE(bw.view() == "Byte '97'");
234+
235+
SECTION("Hexadecimal buffers") {
236+
swoc::MemSpan<void const> cvs{"Evil Dave Rulz"_tv}; // TextView intermediate keeps nul byte out.
237+
TextView const edr_in_hex{"4576696c20446176652052756c7a"};
238+
bw.clear().format(swoc::bwf::Spec(":x"), cvs);
239+
REQUIRE(bw.view() == edr_in_hex);
240+
bw.clear().format(swoc::bwf::Spec::DEFAULT, swoc::bwf::UnHex(edr_in_hex));
241+
REQUIRE(bw.view() == "Evil Dave Rulz");
242+
bw.clear().format(swoc::bwf::Spec::DEFAULT, swoc::bwf::UnHex("112233445566778800"));
243+
REQUIRE(memcmp(bw.view(), "\x11\x22\x33\x44\x55\x66\x77\x88\x00"_tv) == 0);
244+
// Check if max width in the spec works - should leave bytes from the previous.
245+
bw.clear().format(swoc::bwf::Spec{":,2"}, swoc::bwf::UnHex("deadbeef"));
246+
REQUIRE(memcmp(TextView(bw.data(), 4), "\xde\xad\x33\x44"_tv) == 0);
247+
std::string text, hex;
248+
bwprint(hex, "{:x}", cvs);
249+
bwprint(text, "{}", swoc::bwf::UnHex(edr_in_hex));
250+
REQUIRE(hex == edr_in_hex);
251+
REQUIRE(text == TextView(cvs.rebind<char const>()));
252+
}
253+
234254
}
235255

236256
TEST_CASE("bwstring", "[bwprint][bwappend][bwstring]") {

0 commit comments

Comments
 (0)