mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
AK: Add a :hex-dump mode to AK::Format
This will just hexdump the given value. Note that not all formatters respect this, the ones that do are: - (Readonly)Bytes: formatter added in this commit - StringView / char const* - integral types
This commit is contained in:
parent
10f56166e5
commit
7eda164c25
Notes:
sideshowbarker
2024-07-18 12:07:59 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/7eda164c252 Pull-request: https://github.com/SerenityOS/serenity/pull/8106
2 changed files with 63 additions and 2 deletions
|
@ -377,6 +377,29 @@ void FormatBuilder::put_f64(
|
|||
}
|
||||
#endif
|
||||
|
||||
void FormatBuilder::put_hexdump(ReadonlyBytes bytes, size_t width, char fill)
|
||||
{
|
||||
auto put_char_view = [&](auto i) {
|
||||
put_padding(fill, 4);
|
||||
for (size_t j = i - width; j < i; ++j) {
|
||||
auto ch = bytes[j];
|
||||
m_builder.append(ch >= 32 && ch <= 127 ? ch : '.'); // silly hack
|
||||
}
|
||||
};
|
||||
for (size_t i = 0; i < bytes.size(); ++i) {
|
||||
if (width > 0) {
|
||||
if (i % width == 0 && i) {
|
||||
put_char_view(i);
|
||||
put_literal("\n");
|
||||
}
|
||||
}
|
||||
put_u64(bytes[i], 16, false, false, true, Align::Right, 2);
|
||||
}
|
||||
|
||||
if (width > 0 && bytes.size() && bytes.size() % width == 0)
|
||||
put_char_view(bytes.size());
|
||||
}
|
||||
|
||||
void vformat(StringBuilder& builder, StringView fmtstr, TypeErasedFormatParams params)
|
||||
{
|
||||
FormatBuilder fmtbuilder { builder };
|
||||
|
@ -456,6 +479,8 @@ void StandardFormatter::parse(TypeErasedFormatParams& params, FormatParser& pars
|
|||
m_mode = Mode::Hexfloat;
|
||||
else if (parser.consume_specific('A'))
|
||||
m_mode = Mode::HexfloatUppercase;
|
||||
else if (parser.consume_specific("hex-dump"))
|
||||
m_mode = Mode::HexDump;
|
||||
|
||||
if (!parser.is_eof())
|
||||
dbgln("{} did not consume '{}'", __PRETTY_FUNCTION__, parser.remaining());
|
||||
|
@ -471,7 +496,7 @@ void Formatter<StringView>::format(FormatBuilder& builder, StringView value)
|
|||
VERIFY_NOT_REACHED();
|
||||
if (m_zero_pad)
|
||||
VERIFY_NOT_REACHED();
|
||||
if (m_mode != Mode::Default && m_mode != Mode::String && m_mode != Mode::Character)
|
||||
if (m_mode != Mode::Default && m_mode != Mode::String && m_mode != Mode::Character && m_mode != Mode::HexDump)
|
||||
VERIFY_NOT_REACHED();
|
||||
if (m_width.has_value() && m_precision.has_value())
|
||||
VERIFY_NOT_REACHED();
|
||||
|
@ -479,7 +504,10 @@ void Formatter<StringView>::format(FormatBuilder& builder, StringView value)
|
|||
m_width = m_width.value_or(0);
|
||||
m_precision = m_precision.value_or(NumericLimits<size_t>::max());
|
||||
|
||||
builder.put_string(value, m_align, m_width.value(), m_precision.value(), m_fill);
|
||||
if (m_mode == Mode::HexDump)
|
||||
builder.put_hexdump(value.bytes(), m_width.value(), m_fill);
|
||||
else
|
||||
builder.put_string(value, m_align, m_width.value(), m_precision.value(), m_fill);
|
||||
}
|
||||
|
||||
void Formatter<FormatString>::vformat(FormatBuilder& builder, StringView fmtstr, TypeErasedFormatParams params)
|
||||
|
@ -535,6 +563,10 @@ void Formatter<T, typename EnableIf<IsIntegral<T>>::Type>::format(FormatBuilder&
|
|||
} else if (m_mode == Mode::HexadecimalUppercase) {
|
||||
base = 16;
|
||||
upper_case = true;
|
||||
} else if (m_mode == Mode::HexDump) {
|
||||
m_width = m_width.value_or(32);
|
||||
builder.put_hexdump({ &value, sizeof(value) }, m_width.value(), m_fill);
|
||||
return;
|
||||
} else {
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
@ -563,6 +595,8 @@ void Formatter<bool>::format(FormatBuilder& builder, bool value)
|
|||
if (m_mode == Mode::Binary || m_mode == Mode::BinaryUppercase || m_mode == Mode::Decimal || m_mode == Mode::Octal || m_mode == Mode::Hexadecimal || m_mode == Mode::HexadecimalUppercase) {
|
||||
Formatter<u8> formatter { *this };
|
||||
return formatter.format(builder, static_cast<u8>(value));
|
||||
} else if (m_mode == Mode::HexDump) {
|
||||
return builder.put_hexdump({ &value, sizeof(value) }, m_width.value_or(32), m_fill);
|
||||
} else {
|
||||
Formatter<StringView> formatter { *this };
|
||||
return formatter.format(builder, value ? "true" : "false");
|
||||
|
|
27
AK/Format.h
27
AK/Format.h
|
@ -196,6 +196,11 @@ public:
|
|||
SignMode sign_mode = SignMode::OnlyIfNeeded);
|
||||
#endif
|
||||
|
||||
void put_hexdump(
|
||||
ReadonlyBytes,
|
||||
size_t width,
|
||||
char fill = ' ');
|
||||
|
||||
const StringBuilder& builder() const
|
||||
{
|
||||
return m_builder;
|
||||
|
@ -261,6 +266,7 @@ struct StandardFormatter {
|
|||
Float,
|
||||
Hexfloat,
|
||||
HexfloatUppercase,
|
||||
HexDump,
|
||||
};
|
||||
|
||||
FormatBuilder::Align m_align = FormatBuilder::Align::Default;
|
||||
|
@ -296,6 +302,27 @@ struct Formatter<StringView> : StandardFormatter {
|
|||
|
||||
void format(FormatBuilder&, StringView value);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Formatter<ReadonlyBytes> : Formatter<StringView> {
|
||||
void format(FormatBuilder& builder, ReadonlyBytes const& value)
|
||||
{
|
||||
if (m_mode == Mode::Pointer) {
|
||||
Formatter<FlatPtr> formatter { *this };
|
||||
formatter.format(builder, reinterpret_cast<FlatPtr>(value.data()));
|
||||
} else if (m_mode == Mode::Default || m_mode == Mode::HexDump) {
|
||||
m_mode = Mode::HexDump;
|
||||
Formatter<StringView>::format(builder, value);
|
||||
} else {
|
||||
Formatter<StringView>::format(builder, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Formatter<Bytes> : Formatter<ReadonlyBytes> {
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Formatter<const char*> : Formatter<StringView> {
|
||||
void format(FormatBuilder& builder, const char* value)
|
||||
|
|
Loading…
Reference in a new issue