diff --git a/lib/include/pl/patterns/pattern.hpp b/lib/include/pl/patterns/pattern.hpp index e2574e05..386dad4e 100644 --- a/lib/include/pl/patterns/pattern.hpp +++ b/lib/include/pl/patterns/pattern.hpp @@ -259,6 +259,12 @@ namespace pl::ptrn { [[nodiscard]] virtual std::string getFormattedName() const = 0; + /** + * @brief Pattern's short string representation. + * + * Tries the user [[format]] function first, then falls back to defaultToDisplayValue() to format with pattern's default display value formatter. + * The result is cached. + */ [[nodiscard]] std::string getFormattedValue() { if (this->m_cachedDisplayValue != nullptr) return *this->m_cachedDisplayValue; @@ -271,7 +277,8 @@ namespace pl::ptrn { this->m_evaluator->setReadOffset(startOffset); }; - auto result = this->formatDisplayValue(); + auto userResult = this->callUserFormatFunc(); + auto result = userResult.has_value() ? std::move(*userResult) : this->defaultToDisplayValue(); this->m_cachedDisplayValue = std::make_unique(result); this->m_validDisplayValue = true; @@ -288,20 +295,34 @@ namespace pl::ptrn { return this->m_validDisplayValue; } - [[nodiscard]] virtual std::string toString() { - auto result = fmt::format("{} {} @ 0x{:X}", this->getTypeName(), this->getVariableName(), this->getOffset()); - + /** + * @brief Pattern's full string representation. + * + * Tries to format with user [[format]] function, then uses defaultToString() to format with pattern's default formatter + */ + [[nodiscard]] std::string toString() const { try { - return this->callUserFormatFunc(this->getValue(), true).value_or(result); + auto userResult = this->callUserFormatFunc(true); + return userResult.has_value() ? std::move(*userResult) : this->defaultToString(); } catch (std::exception &e) { return e.what(); } } - [[nodiscard]] virtual core::Token::Literal getValue() const { - auto pattern = this->clone(); + /** + * @brief Pattern's value after [[transform]] function is applied. + */ + [[nodiscard]] core::Token::Literal getValue() const { + return this->transformValue(this->getRawValue()); + } - return this->transformValue(std::move(pattern)); + /** + * @brief Pattern's value before [[transform]] function is applied. + * + * Default implementation clones pattern by calling clone() method. + */ + [[nodiscard]] virtual core::Token::Literal getRawValue() const { + return this->clone(); } [[nodiscard]] virtual std::vector> getChildren() { @@ -581,11 +602,27 @@ namespace pl::ptrn { m_arrayIndex = index; } - [[nodiscard]] virtual std::string formatDisplayValue() = 0; - protected: std::optional m_endian; + /** + * @brief Fallback for toString() when no user [[format]] function applies. + * @note Implementations of this method should use getValue() instead of getRawValue(), because default formatter should respect [[transform]]. + */ + [[nodiscard]] virtual std::string defaultToString() const { + return fmt::format("{} {} @ 0x{:X}", this->getTypeName(), this->getVariableName(), this->getOffset()); + } + + /** + * @brief Fallback for getFormattedValue() when no user [[format]] function applies. Cached by getFormattedValue(). + * @note Implementations of this method should use getValue() instead of getRawValue(), because default formatter should respect [[transform]]. + * + * Default implementation calls defaultToString(). + */ + [[nodiscard]] virtual std::string defaultToDisplayValue() const { + return this->defaultToString(); + } + [[nodiscard]] core::Token::Literal transformValue(const core::Token::Literal &value) const { auto evaluator = this->getEvaluator(); @@ -612,39 +649,42 @@ namespace pl::ptrn { } /** - * @brief Calls an user-defined PL function to format the given literal (pattern), if existing. Else, returns defaultValue + * @brief Runs the user [[format]] function if one is registered. + * + * The argument passed to the [[format]] function is getRawValue() (before [[transform]] is applied). */ - [[nodiscard]] std::optional callUserFormatFunc(const core::Token::Literal &literal, bool fromCast = false) const { + [[nodiscard]] std::optional callUserFormatFunc(bool fromCast = false) const { const auto &formatterFunctionName = this->getReadFormatterFunction(); - if (formatterFunctionName.empty()) - return {}; - else { - const auto function = this->m_evaluator->findFunction(formatterFunctionName); - if (function.has_value()) { - auto startHeap = this->m_evaluator->getHeap(); - ON_SCOPE_EXIT { this->m_evaluator->getHeap() = startHeap; }; - - // Preserve pattern variable name - std::string patternName; - if (literal.isPattern()) { - patternName = literal.toPattern()->getVariableName(); - } - ON_SCOPE_EXIT { - if (!patternName.empty()) - literal.toPattern()->setVariableName(patternName); - }; - - auto result = function->func(this->m_evaluator, { literal }); - if (result.has_value()) { - if (fromCast && result->isPattern() && result->toPattern()->getTypeName() == this->getTypeName()) { - return {}; - } else { - return result->toString(true); - } + if (formatterFunctionName.empty()) { + return std::nullopt; + } + const auto literal = this->getRawValue(); + + const auto function = this->m_evaluator->findFunction(formatterFunctionName); + if (function.has_value()) { + auto startHeap = this->m_evaluator->getHeap(); + ON_SCOPE_EXIT { this->m_evaluator->getHeap() = startHeap; }; + + // Preserve pattern variable name + std::string patternName; + if (literal.isPattern()) { + patternName = literal.toPattern()->getVariableName(); + } + ON_SCOPE_EXIT { + if (!patternName.empty()) + literal.toPattern()->setVariableName(patternName); + }; + + auto result = function->func(this->m_evaluator, { literal }); + if (result.has_value()) { + if (fromCast && result->isPattern() && result->toPattern()->getTypeName() == this->getTypeName()) { + return {}; + } else { + return result->toString(true); } } - return {}; } + return std::nullopt; } template diff --git a/lib/include/pl/patterns/pattern_array_dynamic.hpp b/lib/include/pl/patterns/pattern_array_dynamic.hpp index b2d3fb9c..f7d35b41 100644 --- a/lib/include/pl/patterns/pattern_array_dynamic.hpp +++ b/lib/include/pl/patterns/pattern_array_dynamic.hpp @@ -158,33 +158,6 @@ namespace pl::ptrn { this->setBaseColor(this->m_entries.front()->getColor()); } - [[nodiscard]] std::string toString() override { - std::string result; - - result += "[ "; - - size_t entryCount = 0; - for (const auto &entry : this->m_entries) { - if (entryCount > 50) { - result += fmt::format("..., "); - break; - } - - result += fmt::format("{}, ", entry->toString()); - entryCount++; - } - - if (entryCount > 0) { - // Remove trailing ", " - result.pop_back(); - result.pop_back(); - } - - result += " ]"; - - return Pattern::callUserFormatFunc(this->reference(), true).value_or(result); - } - [[nodiscard]] bool operator==(const Pattern &other) const override { if (!compareCommonProperties(other)) return false; @@ -216,10 +189,6 @@ namespace pl::ptrn { v.visit(*this); } - std::string formatDisplayValue() override { - return Pattern::callUserFormatFunc(this->reference()).value_or("[ ... ]"); - } - std::vector getRawBytes() override { std::vector result; @@ -243,6 +212,36 @@ namespace pl::ptrn { Pattern::clearFormatCache(); } + protected: + std::string defaultToString() const override { + std::string result; + + result += "[ "; + + size_t entryCount = 0; + for (const auto &entry : this->m_entries) { + if (entryCount > 50) { + result += fmt::format("..., "); + break; + } + + result += fmt::format("{}, ", entry->toString()); + entryCount++; + } + + if (entryCount > 0) { + // Remove trailing ", " + result.pop_back(); + result.pop_back(); + } + + result += " ]"; + return result; + } + + std::string defaultToDisplayValue() const override { + return "[ ... ]"; + } private: std::vector> m_entries; diff --git a/lib/include/pl/patterns/pattern_array_static.hpp b/lib/include/pl/patterns/pattern_array_static.hpp index 1453ac9d..428a66b7 100644 --- a/lib/include/pl/patterns/pattern_array_static.hpp +++ b/lib/include/pl/patterns/pattern_array_static.hpp @@ -199,11 +199,32 @@ namespace pl::ptrn { v.visit(*this); } - std::string formatDisplayValue() override { - return Pattern::callUserFormatFunc(this->reference()).value_or("[ ... ]"); + std::vector getRawBytes() override { + std::vector result; + + if (this->isSealed()) { + result.resize(this->getSize()); + this->getEvaluator()->readData(this->getOffset(), result.data(), result.size(), this->getSection()); + } else { + this->forEachEntry(0, this->getEntryCount(), [&](u64, const auto &entry) { + auto bytes = entry->getBytes(); + std::copy(bytes.begin(), bytes.end(), std::back_inserter(result)); + }); + } + + return result; } - [[nodiscard]] std::string toString() override { + void clearFormatCache() override { + this->m_template->clearFormatCache(); + + for (auto &highlightTemplate : this->m_highlightTemplates) + highlightTemplate->clearFormatCache(); + + Pattern::clearFormatCache(); + } + protected: + std::string defaultToString() const override { std::string result; result += "[ "; @@ -228,33 +249,11 @@ namespace pl::ptrn { } result += " ]"; - - return Pattern::callUserFormatFunc(this->reference(), true).value_or(result); - } - - std::vector getRawBytes() override { - std::vector result; - - if (this->isSealed()) { - result.resize(this->getSize()); - this->getEvaluator()->readData(this->getOffset(), result.data(), result.size(), this->getSection()); - } else { - this->forEachEntry(0, this->getEntryCount(), [&](u64, const auto &entry) { - auto bytes = entry->getBytes(); - std::copy(bytes.begin(), bytes.end(), std::back_inserter(result)); - }); - } - return result; } - void clearFormatCache() override { - this->m_template->clearFormatCache(); - - for (auto &highlightTemplate : this->m_highlightTemplates) - highlightTemplate->clearFormatCache(); - - Pattern::clearFormatCache(); + std::string defaultToDisplayValue() const override { + return "[ ... ]"; } private: diff --git a/lib/include/pl/patterns/pattern_bitfield.hpp b/lib/include/pl/patterns/pattern_bitfield.hpp index 6ffb9a06..019f6654 100644 --- a/lib/include/pl/patterns/pattern_bitfield.hpp +++ b/lib/include/pl/patterns/pattern_bitfield.hpp @@ -73,10 +73,6 @@ namespace pl::ptrn { return this->getEvaluator()->readBits(this->getOffset(), this->getBitOffset(), this->getBitSize(), this->getSection(), this->getEndian()); } - [[nodiscard]] core::Token::Literal getValue() const override { - return transformValue(this->readValue()); - } - [[nodiscard]] std::string getFormattedName() const override { return this->m_bitSize == 1 ? "bit" : "bits"; } @@ -105,17 +101,6 @@ namespace pl::ptrn { v.visit(*this); } - std::string formatDisplayValue() override { - auto literal = this->getValue(); - auto value = literal.toUnsigned(); - return Pattern::callUserFormatFunc(literal).value_or(fmt::format("{}", value)); - } - - [[nodiscard]] std::string toString() override { - auto value = this->readValue(); - return Pattern::callUserFormatFunc(value, true).value_or(fmt::format("{}", value)); - } - [[nodiscard]] bool isPadding() const override { return this->m_padding; } void setPadding(bool padding) { this->m_padding = padding; } @@ -151,6 +136,15 @@ namespace pl::ptrn { } } + [[nodiscard]] core::Token::Literal getRawValue() const override { + return this->readValue(); + } + + protected: + std::string defaultToString() const override { + return fmt::format("{}", this->getValue().toUnsigned()); + } + private: u8 m_bitOffset; u8 m_bitSize; @@ -166,19 +160,13 @@ namespace pl::ptrn { return std::unique_ptr(new PatternBitfieldFieldSigned(*this)); } - [[nodiscard]] core::Token::Literal getValue() const override { - return transformValue(hlp::signExtend(this->getBitSize(), this->readValue())); - } - - std::string formatDisplayValue() override { - auto rawValue = this->readValue(); - auto value = hlp::signExtend(this->getBitSize(), i128(rawValue)); - return Pattern::callUserFormatFunc(value).value_or(fmt::format("{}", value)); + [[nodiscard]] core::Token::Literal getRawValue() const override { + return hlp::signExtend(this->getBitSize(), this->readValue()); } - [[nodiscard]] std::string toString() override { - auto result = fmt::format("{}", this->getValue().toSigned()); - return Pattern::callUserFormatFunc(this->getValue(), true).value_or(result); + protected: + std::string defaultToString() const override { + return fmt::format("{}", this->getValue().toSigned()); } }; @@ -190,27 +178,24 @@ namespace pl::ptrn { return std::unique_ptr(new PatternBitfieldFieldBoolean(*this)); } - [[nodiscard]] core::Token::Literal getValue() const override { - return transformValue(this->readValue()); - } - [[nodiscard]] std::string getFormattedName() const override { return "bool"; } - std::string formatDisplayValue() override { - auto value = this->getValue().toUnsigned(); - if (value == 0) - return "false"; - else if (value == 1) - return "true"; - else - return "true*"; + protected: + std::string defaultToString() const override { + return fmt::format("{}", this->getValue().toBoolean() ? "true" : "false"); } - [[nodiscard]] std::string toString() override { - auto value = this->getValue(); - return Pattern::callUserFormatFunc(value, true).value_or(fmt::format("{}", value.toBoolean() ? "true" : "false")); + std::string defaultToDisplayValue() const override { + const auto value = this->getValue().toUnsigned(); + if (value == 0) { + return "false"; + } + if (value == 1) { + return "true"; + } + return "true*"; } }; @@ -245,15 +230,9 @@ namespace pl::ptrn { return std::unique_ptr(new PatternBitfieldFieldEnum(*this)); } - std::string formatDisplayValue() override { - auto value = this->readValue(); - auto enumName = PatternEnum::getEnumName(this->getTypeName(), value, this->getEnumValues(), this->getBitSize()); - return Pattern::callUserFormatFunc(value).value_or(fmt::format("{}", enumName)); - } - - [[nodiscard]] std::string toString() override { - auto enumName = PatternEnum::getEnumName(this->getTypeName(), this->readValue(), this->getEnumValues(), this->getBitSize()); - return Pattern::callUserFormatFunc(this->getValue(), true).value_or(enumName); + protected: + std::string defaultToString() const override { + return PatternEnum::getEnumName(this->getTypeName(), this->getValue().toUnsigned(), this->getEnumValues(), this->getBitSize()); } private: @@ -430,33 +409,6 @@ namespace pl::ptrn { this->setBaseColor(this->m_entries.front()->getColor()); } - [[nodiscard]] std::string toString() override { - std::string result; - - result += "[ "; - - size_t entryCount = 0; - for (const auto &entry : this->m_entries) { - if (entryCount > 50) { - result += fmt::format("..., "); - break; - } - - result += fmt::format("{}, ", entry->toString()); - entryCount++; - } - - if (entryCount > 0) { - // Remove trailing ", " - result.pop_back(); - result.pop_back(); - } - - result += " ]"; - - return Pattern::callUserFormatFunc(this->reference(), true).value_or(result); - } - [[nodiscard]] bool operator==(const Pattern &other) const override { if (!compareCommonProperties(other)) return false; @@ -493,10 +445,6 @@ namespace pl::ptrn { v.visit(*this); } - std::string formatDisplayValue() override { - return Pattern::callUserFormatFunc(this->reference()).value_or("[ ... ]"); - } - void sort(const std::function &comparator) override { this->m_sortedEntries.clear(); for (auto &member : this->m_entries) @@ -531,6 +479,36 @@ namespace pl::ptrn { Pattern::clearFormatCache(); } + protected: + std::string defaultToString() const override { + std::string result; + + result += "[ "; + + size_t entryCount = 0; + for (const auto &entry : this->m_entries) { + if (entryCount > 50) { + result += fmt::format("..., "); + break; + } + + result += fmt::format("{}, ", entry->toString()); + entryCount++; + } + + if (entryCount > 0) { + // Remove trailing ", " + result.pop_back(); + result.pop_back(); + } + + result += " ]"; + return result; + } + + std::string defaultToDisplayValue() const override { + return "[ ... ]"; + } private: std::vector> m_entries; @@ -679,63 +657,6 @@ namespace pl::ptrn { v.visit(*this); } - [[nodiscard]] std::string toString() override { - std::string result = this->getFormattedName(); - - result += " { "; - - for (const auto &field : this->m_fields) { - if (field->getVariableName().starts_with("$")) - continue; - - result += fmt::format("{} = {}, ", field->getVariableName(), field->toString()); - } - - // Remove trailing ", " - result.pop_back(); - result.pop_back(); - - result += " }"; - - return Pattern::callUserFormatFunc(this->reference(), true).value_or(result); - } - - std::string formatDisplayValue() override { - std::vector bytes(this->getSize(), 0); - this->getEvaluator()->readData(this->getOffset(), bytes.data(), bytes.size(), this->getSection()); - - if (this->getEndian() == std::endian::little) - std::reverse(bytes.begin(), bytes.end()); - - std::string valueString; - - for (const auto &pattern : this->m_fields) { - if (auto *field = dynamic_cast(pattern.get()); field != nullptr) { - auto fieldValue = field->getValue().toUnsigned(); - - if (field->getBitSize() == 1) { - if (fieldValue > 0) - valueString += fmt::format("{} | ", field->getVariableName()); - } else { - valueString += fmt::format("{}({}) | ", field->getVariableName(), field->toString()); - } - } else if (auto *member = dynamic_cast(pattern.get()); member != nullptr) { - valueString += fmt::format("{} = {} | ", member->getVariableName(), member->toString()); - } else if (auto *bitfield = dynamic_cast(pattern.get()); bitfield != nullptr) { - valueString += fmt::format("{} = {} | ", bitfield->getVariableName(), bitfield->formatDisplayValue()); - } - } - - if (valueString.size() >= 3) { - valueString.resize(valueString.size() - 3); - } - - if (valueString.size() > 64) - return Pattern::callUserFormatFunc(this->reference()).value_or(fmt::format("{{ ... }}", valueString)); - else - return Pattern::callUserFormatFunc(this->reference()).value_or(fmt::format("{{ {} }}", valueString)); - } - void setEndian(std::endian endian) override { if (this->isLocal()) return; @@ -827,6 +748,64 @@ namespace pl::ptrn { Pattern::clearFormatCache(); } + protected: + std::string defaultToString() const override { + std::string result = this->getFormattedName(); + + result += " { "; + + for (const auto &field : this->m_fields) { + if (field->getVariableName().starts_with("$")) + continue; + + result += fmt::format("{} = {}, ", field->getVariableName(), field->toString()); + } + + // Remove trailing ", " + result.pop_back(); + result.pop_back(); + + result += " }"; + return result; + } + + std::string defaultToDisplayValue() const override { + std::vector bytes(this->getSize(), 0); + this->getEvaluator()->readData(this->getOffset(), bytes.data(), bytes.size(), this->getSection()); + + if (this->getEndian() == std::endian::little) + std::reverse(bytes.begin(), bytes.end()); + + std::string valueString; + + for (const auto &pattern : this->m_fields) { + if (auto *field = dynamic_cast(pattern.get()); field != nullptr) { + auto fieldValue = field->getValue().toUnsigned(); + + if (field->getBitSize() == 1) { + if (fieldValue > 0) + valueString += fmt::format("{} | ", field->getVariableName()); + } else { + valueString += fmt::format("{}({}) | ", field->getVariableName(), field->toString()); + } + } else if (auto *member = dynamic_cast(pattern.get()); member != nullptr) { + valueString += fmt::format("{} = {} | ", member->getVariableName(), member->toString()); + } else if (auto *bitfield = dynamic_cast(pattern.get()); bitfield != nullptr) { + auto value = bitfield->callUserFormatFunc().value_or(bitfield->defaultToDisplayValue()); + valueString += fmt::format("{} = {} | ", bitfield->getVariableName(), std::move(value)); + } + } + + if (valueString.size() >= 3) { + valueString.resize(valueString.size() - 3); + } + + if (valueString.size() > 64) + return fmt::format("{{ ... }}", valueString); + else + return fmt::format("{{ {} }}", valueString); + } + private: std::vector> m_fields; std::vector> m_sortedFields; diff --git a/lib/include/pl/patterns/pattern_boolean.hpp b/lib/include/pl/patterns/pattern_boolean.hpp index af9bf441..238443cc 100644 --- a/lib/include/pl/patterns/pattern_boolean.hpp +++ b/lib/include/pl/patterns/pattern_boolean.hpp @@ -13,13 +13,6 @@ namespace pl::ptrn { return std::unique_ptr(new PatternBoolean(*this)); } - [[nodiscard]] core::Token::Literal getValue() const override { - bool boolean = false; - this->getEvaluator()->readData(this->getOffset(), &boolean, 1, this->getSection()); - - return transformValue(boolean); - } - std::vector getBytesOf(const core::Token::Literal &value) const override { if (auto boolValue = std::get_if(&value); boolValue != nullptr) return wolv::util::toContainer>(wolv::util::toBytes(*boolValue)); @@ -31,28 +24,12 @@ namespace pl::ptrn { return "bool"; } - std::string formatDisplayValue() override { - auto value = this->getValue().toUnsigned(); - if (value == 0) - return "false"; - if (value == 1) - return "true"; - return "true*"; - } - [[nodiscard]] bool operator==(const Pattern &other) const override { return compareCommonProperties(other); } void accept(PatternVisitor &v) override { v.visit(*this); } - [[nodiscard]] std::string toString() override { - auto value = this->getValue(); - auto result = fmt::format("{}", value.toBoolean() ? "true" : "false"); - - return Pattern::callUserFormatFunc(value, true).value_or(result); - } - std::vector getRawBytes() override { std::vector result; result.resize(this->getSize()); @@ -63,6 +40,27 @@ namespace pl::ptrn { return result; } + + [[nodiscard]] core::Token::Literal getRawValue() const override { + bool boolean = false; + this->getEvaluator()->readData(this->getOffset(), &boolean, 1, this->getSection()); + + return boolean; + } + + protected: + std::string defaultToString() const override { + return fmt::format("{}", this->getValue().toBoolean() ? "true" : "false"); + } + + std::string defaultToDisplayValue() const override { + auto value = this->getValue().toUnsigned(); + if (value == 0) + return "false"; + if (value == 1) + return "true"; + return "true*"; + } }; -} \ No newline at end of file +} diff --git a/lib/include/pl/patterns/pattern_character.hpp b/lib/include/pl/patterns/pattern_character.hpp index 66578064..f5a9f017 100644 --- a/lib/include/pl/patterns/pattern_character.hpp +++ b/lib/include/pl/patterns/pattern_character.hpp @@ -13,13 +13,6 @@ namespace pl::ptrn { return std::make_unique(*this); } - [[nodiscard]] core::Token::Literal getValue() const override { - char character = '\x00'; - this->getEvaluator()->readData(this->getOffset(), &character, 1, this->getSection()); - - return transformValue(character); - } - std::vector getBytesOf(const core::Token::Literal &value) const override { if (auto charValue = std::get_if(&value); charValue != nullptr) return wolv::util::toContainer>(wolv::util::toBytes(*charValue)); @@ -31,24 +24,12 @@ namespace pl::ptrn { return "char"; } - std::string formatDisplayValue() override { - const u8 character = this->getValue().toCharacter(); - return Pattern::callUserFormatFunc(this->getValue()).value_or(fmt::format("'{0}'", hlp::encodeByteString({ character }))); - } - [[nodiscard]] bool operator==(const Pattern &other) const override { return compareCommonProperties(other); } void accept(PatternVisitor &v) override { v.visit(*this); } - [[nodiscard]] std::string toString() override { - auto value = this->getValue(); - auto result = fmt::format("{}", hlp::encodeByteString({ u8(value.toCharacter()) })); - - return Pattern::callUserFormatFunc(value, true).value_or(result); - } - std::vector getRawBytes() override { std::vector result; result.resize(this->getSize()); @@ -59,6 +40,22 @@ namespace pl::ptrn { return result; } + + [[nodiscard]] core::Token::Literal getRawValue() const override { + char character = '\x00'; + this->getEvaluator()->readData(this->getOffset(), &character, 1, this->getSection()); + + return character; + } + + protected: + std::string defaultToString() const override { + return fmt::format("{}", hlp::encodeByteString({ static_cast(this->getValue().toCharacter()) })); + } + + std::string defaultToDisplayValue() const override { + return fmt::format("'{0}'", this->defaultToString()); + } }; -} \ No newline at end of file +} diff --git a/lib/include/pl/patterns/pattern_enum.hpp b/lib/include/pl/patterns/pattern_enum.hpp index da873522..d4b00eea 100644 --- a/lib/include/pl/patterns/pattern_enum.hpp +++ b/lib/include/pl/patterns/pattern_enum.hpp @@ -21,13 +21,6 @@ namespace pl::ptrn { return std::unique_ptr(new PatternEnum(*this)); } - [[nodiscard]] core::Token::Literal getValue() const override { - u128 value = 0; - this->getEvaluator()->readData(this->getOffset(), &value, this->getSize(), this->getSection()); - - return transformValue(hlp::changeEndianess(value, this->getSize(), this->getEndian())); - } - [[nodiscard]] std::string getFormattedName() const override { return "enum " + Pattern::getTypeName(); } @@ -58,10 +51,6 @@ namespace pl::ptrn { v.visit(*this); } - std::string formatDisplayValue() override { - return fmt::format("{}", this->toString()); - } - static std::string getEnumName(const std::string &typeName, u128 value, const std::map &enumValues, u64 bitSize = 128) { auto truncate = [bitSize](const core::Token::Literal &literal) -> u128 { auto value = literal.toUnsigned(); @@ -97,11 +86,6 @@ namespace pl::ptrn { return result; } - [[nodiscard]] std::string toString() override { - u128 value = this->getValue().toUnsigned(); - return Pattern::callUserFormatFunc(this->reference(), true).value_or(getEnumName(this->getTypeName(), value, m_enumValues, this->getSize() * 8)); - } - std::vector getRawBytes() override { std::vector result; result.resize(this->getSize()); @@ -113,6 +97,19 @@ namespace pl::ptrn { return result; } + [[nodiscard]] core::Token::Literal getRawValue() const override { + u128 value = 0; + this->getEvaluator()->readData(this->getOffset(), &value, this->getSize(), this->getSection()); + + return hlp::changeEndianess(value, this->getSize(), this->getEndian()); + } + + protected: + std::string defaultToString() const override { + const u128 value = this->getValue().toUnsigned(); + return getEnumName(this->getTypeName(), value, m_enumValues, this->getSize() * 8); + } + private: std::map m_enumValues; }; diff --git a/lib/include/pl/patterns/pattern_error.hpp b/lib/include/pl/patterns/pattern_error.hpp index fc9e52be..91e8f6a1 100644 --- a/lib/include/pl/patterns/pattern_error.hpp +++ b/lib/include/pl/patterns/pattern_error.hpp @@ -27,20 +27,16 @@ namespace pl::ptrn { v.visit(*this); } - std::string formatDisplayValue() override { - return m_errorMessage; - } - - [[nodiscard]] std::string toString() override { - return m_errorMessage; - } - std::vector getRawBytes() override { return { }; } + protected: + std::string defaultToString() const override { + return m_errorMessage; + } private: std::string m_errorMessage; }; -} \ No newline at end of file +} diff --git a/lib/include/pl/patterns/pattern_float.hpp b/lib/include/pl/patterns/pattern_float.hpp index 96dbe4a9..1c42c199 100644 --- a/lib/include/pl/patterns/pattern_float.hpp +++ b/lib/include/pl/patterns/pattern_float.hpp @@ -13,28 +13,6 @@ namespace pl::ptrn { return std::unique_ptr(new PatternFloat(*this)); } - [[nodiscard]] core::Token::Literal getValue() const override { - if (this->getSize() == 4) { - u32 data = 0; - this->getEvaluator()->readData(this->getOffset(), &data, 4, this->getSection()); - data = hlp::changeEndianess(data, 4, this->getEndian()); - - float result = 0; - std::memcpy(&result, &data, sizeof(float)); - return transformValue(double(result)); - } else if (this->getSize() == 8) { - u64 data = 0; - this->getEvaluator()->readData(this->getOffset(), &data, 8, this->getSection()); - data = hlp::changeEndianess(data, 8, this->getEndian()); - - double result = 0; - std::memcpy(&result, &data, sizeof(double)); - return transformValue(result); - } else { - return std::numeric_limits::quiet_NaN(); - } - } - std::vector getBytesOf(const core::Token::Literal &value) const override { auto doubleValue = value.toFloatingPoint(); std::vector result; @@ -64,35 +42,6 @@ namespace pl::ptrn { v.visit(*this); } - std::string formatDisplayValue() override { - auto value = this->getValue().toFloatingPoint(); - if (this->getSize() == 4) { - auto f32 = static_cast(value); - u32 integerResult = 0; - std::memcpy(&integerResult, &f32, sizeof(float)); - return Pattern::callUserFormatFunc(f32).value_or(fmt::format("{:g}", f32)); - } else if (this->getSize() == 8) { - auto f64 = static_cast(value); - u64 integerResult = 0; - std::memcpy(&integerResult, &f64, sizeof(double)); - return Pattern::callUserFormatFunc(f64).value_or(fmt::format("{:g}", f64)); - } else { - return "Floating Point Data"; - } - } - - [[nodiscard]] std::string toString() override { - auto value = this->getValue(); - - std::string result; - if (this->getSize() == 4) - result = fmt::format("{}", static_cast(value.toFloatingPoint())); - else - result = fmt::format("{}", static_cast(value.toFloatingPoint())); - - return Pattern::callUserFormatFunc(value, true).value_or(result); - } - std::vector getRawBytes() override { std::vector result; result.resize(this->getSize()); @@ -103,6 +52,43 @@ namespace pl::ptrn { return result; } + + [[nodiscard]] core::Token::Literal getRawValue() const override { + if (this->getSize() == 4) { + u32 data = 0; + this->getEvaluator()->readData(this->getOffset(), &data, 4, this->getSection()); + data = hlp::changeEndianess(data, 4, this->getEndian()); + + return static_cast(std::bit_cast(data)); + } + if (this->getSize() == 8) { + u64 data = 0; + this->getEvaluator()->readData(this->getOffset(), &data, 8, this->getSection()); + data = hlp::changeEndianess(data, 8, this->getEndian()); + + return std::bit_cast(data); + } + return std::numeric_limits::quiet_NaN(); + } + + protected: + std::string defaultToString() const override { + if (this->getSize() == 4) { + return fmt::format("{}", static_cast(this->getValue().toFloatingPoint())); + } else { + return fmt::format("{}", static_cast(this->getValue().toFloatingPoint())); + } + } + + std::string defaultToDisplayValue() const override { + if (this->getSize() == 4) { + return fmt::format("{:g}", static_cast(this->getValue().toFloatingPoint())); + } + if (this->getSize() == 8) { + return fmt::format("{:g}", static_cast(this->getValue().toFloatingPoint())); + } + return "Floating Point Data"; + } }; -} \ No newline at end of file +} diff --git a/lib/include/pl/patterns/pattern_padding.hpp b/lib/include/pl/patterns/pattern_padding.hpp index d3a95128..756098c7 100644 --- a/lib/include/pl/patterns/pattern_padding.hpp +++ b/lib/include/pl/patterns/pattern_padding.hpp @@ -26,24 +26,20 @@ namespace pl::ptrn { v.visit(*this); } - std::string formatDisplayValue() override { - return ""; + std::vector getRawBytes() override { + return { }; } - - [[nodiscard]] std::string toString() override { - auto result = [this]{ - if (this->getSize() == 0) - return std::string("null"); - else - return fmt::format("padding[{}]", this->getSize()); - }(); - - return Pattern::callUserFormatFunc(this->getValue(), true).value_or(result); + protected: + std::string defaultToString() const override { + if (this->getSize() == 0) + return "null"; + else + return fmt::format("padding[{}]", this->getSize()); } - std::vector getRawBytes() override { - return { }; + std::string defaultToDisplayValue() const override { + return ""; } }; -} \ No newline at end of file +} diff --git a/lib/include/pl/patterns/pattern_pointer.hpp b/lib/include/pl/patterns/pattern_pointer.hpp index 58f48b72..784a655f 100644 --- a/lib/include/pl/patterns/pattern_pointer.hpp +++ b/lib/include/pl/patterns/pattern_pointer.hpp @@ -24,10 +24,6 @@ namespace pl::ptrn { return std::unique_ptr(new PatternPointer(*this)); } - [[nodiscard]] core::Token::Literal getValue() const override { - return transformValue(this->m_pointerType->getValue()); - } - [[nodiscard]] std::string getFormattedName() const override { std::string output; if (this->getTypeName().empty()) { @@ -148,17 +144,6 @@ namespace pl::ptrn { v.visit(*this); } - std::string formatDisplayValue() override { - auto data = this->getValue().toSigned(); - return Pattern::callUserFormatFunc(this->getValue()).value_or(fmt::format("*(0x{0:X})", data)); - } - - [[nodiscard]] std::string toString() override { - auto result = this->m_pointedAt->toString(); - - return Pattern::callUserFormatFunc(this->reference(), true).value_or(result); - } - std::vector getRawBytes() override { std::vector result; result.resize(this->getSize()); @@ -176,6 +161,19 @@ namespace pl::ptrn { Pattern::clearFormatCache(); } + [[nodiscard]] core::Token::Literal getRawValue() const override { + return this->m_pointerType->getValue(); + } + + protected: + std::string defaultToString() const override { + return this->m_pointedAt->toString(); + } + + std::string defaultToDisplayValue() const override { + return fmt::format("*(0x{0:X})", this->getValue().toSigned()); + } + private: std::shared_ptr m_pointedAt; std::shared_ptr m_pointerType; diff --git a/lib/include/pl/patterns/pattern_signed.hpp b/lib/include/pl/patterns/pattern_signed.hpp index 94ad4b59..9defc1ae 100644 --- a/lib/include/pl/patterns/pattern_signed.hpp +++ b/lib/include/pl/patterns/pattern_signed.hpp @@ -3,7 +3,6 @@ #include namespace pl::ptrn { - class PatternSigned : public Pattern { public: PatternSigned(core::Evaluator *evaluator, u64 offset, size_t size, u32 line) @@ -13,14 +12,6 @@ namespace pl::ptrn { return std::unique_ptr(new PatternSigned(*this)); } - [[nodiscard]] core::Token::Literal getValue() const override { - i128 data = 0; - this->getEvaluator()->readData(this->getOffset(), &data, this->getSize(), this->getSection()); - data = hlp::changeEndianess(data, this->getSize(), this->getEndian()); - - return transformValue(hlp::signExtend(this->getSize() * 8, data)); - } - [[nodiscard]] std::string getFormattedName() const override { return this->getTypeName(); } @@ -31,19 +22,6 @@ namespace pl::ptrn { v.visit(*this); } - std::string formatDisplayValue() override { - auto data = this->getValue().toSigned(); - - return Pattern::callUserFormatFunc(this->getValue()).value_or(fmt::format("{:d}", data)); - } - - [[nodiscard]] std::string toString() override { - auto value = this->getValue(); - auto result = fmt::format("{:d}", value.toSigned()); - - return Pattern::callUserFormatFunc(value, true).value_or(result); - } - std::vector getRawBytes() override { std::vector result; result.resize(this->getSize()); @@ -54,6 +32,19 @@ namespace pl::ptrn { return result; } + + [[nodiscard]] core::Token::Literal getRawValue() const override { + i128 data = 0; + this->getEvaluator()->readData(this->getOffset(), &data, this->getSize(), this->getSection()); + data = hlp::changeEndianess(data, this->getSize(), this->getEndian()); + + return hlp::signExtend(this->getSize() * 8, data); + } + + protected: + std::string defaultToString() const override { + return fmt::format("{:d}", this->getValue().toSigned()); + } }; -} \ No newline at end of file +} diff --git a/lib/include/pl/patterns/pattern_string.hpp b/lib/include/pl/patterns/pattern_string.hpp index e7e69b40..9665d06f 100644 --- a/lib/include/pl/patterns/pattern_string.hpp +++ b/lib/include/pl/patterns/pattern_string.hpp @@ -6,7 +6,6 @@ #include namespace pl::ptrn { - class PatternString : public Pattern, public IIndexable { public: @@ -17,10 +16,6 @@ namespace pl::ptrn { return std::unique_ptr(new PatternString(*this)); } - [[nodiscard]] core::Token::Literal getValue() const override { - return transformValue(this->getValue(this->getSize())); - } - [[nodiscard]] std::vector> getEntries() override { return { }; } @@ -115,20 +110,52 @@ namespace pl::ptrn { return "String"; } - [[nodiscard]] std::string toString() override { - auto value = this->getValue(); - auto result = value.toString(false); - - return Pattern::callUserFormatFunc(value, true).value_or(result); - } - [[nodiscard]] bool operator==(const Pattern &other) const override { return compareCommonProperties(other); } void accept(PatternVisitor &v) override { v.visit(*this); } - std::string formatDisplayValue() override { + std::shared_ptr getEntry(size_t index) const override { + auto result = std::make_shared(this->getEvaluator(), this->getOffset() + index, getLine()); + result->setVariableName(fmt::format("{}[{}]", this->getVariableName(), index)); + result->setSection(this->getSection()); + + return result; + } + + size_t getEntryCount() const override { + return this->getSize(); + } + + void forEachEntryImpl(const std::vector> &patterns, u64 start, u64 end, const std::function&)> &callback) override { + std::ignore = patterns; + + for (auto i = start; i < end; i++) + callback(i, this->getEntry(i)); + } + + std::vector getRawBytes() override { + std::vector result; + + this->forEachEntry(0, this->getEntryCount(), [&](u64, const auto &entry) { + auto bytes = entry->getBytes(); + std::copy(bytes.begin(), bytes.end(), std::back_inserter(result)); + }); + + return result; + } + + [[nodiscard]] core::Token::Literal getRawValue() const override { + return this->getValue(this->getSize()); + } + + protected: + std::string defaultToString() const override { + return Pattern::getValue().toString(false); + } + + std::string defaultToDisplayValue() const override { auto *evaluator = this->getEvaluator(); const auto fullSize = this->getSize(); @@ -145,9 +172,6 @@ namespace pl::ptrn { std::string buffer(size, 0x00); evaluator->readData(this->getOffset(), buffer.data(), size, this->getSection()); - if (auto formatted = Pattern::callUserFormatFunc(buffer); formatted.has_value()) - return *formatted; - const auto &codec = evaluator->getStringEncodeDecode(); // No codec configured keeps the old raw-byte display, unescaped by any @@ -179,36 +203,6 @@ namespace pl::ptrn { return fmt::format("\"{0}\" {1}", decoded.text, truncated ? "(truncated)" : ""); } - std::shared_ptr getEntry(size_t index) const override { - auto result = std::make_shared(this->getEvaluator(), this->getOffset() + index, getLine()); - result->setVariableName(fmt::format("{}[{}]", this->getVariableName(), index)); - result->setSection(this->getSection()); - - return result; - } - - size_t getEntryCount() const override { - return this->getSize(); - } - - void forEachEntryImpl(const std::vector> &patterns, u64 start, u64 end, const std::function&)> &callback) override { - std::ignore = patterns; - - for (auto i = start; i < end; i++) - callback(i, this->getEntry(i)); - } - - std::vector getRawBytes() override { - std::vector result; - - this->forEachEntry(0, this->getEntryCount(), [&](u64, const auto &entry) { - auto bytes = entry->getBytes(); - std::copy(bytes.begin(), bytes.end(), std::back_inserter(result)); - }); - - return result; - } - }; -} \ No newline at end of file +} diff --git a/lib/include/pl/patterns/pattern_struct.hpp b/lib/include/pl/patterns/pattern_struct.hpp index ec7be391..09aec7dd 100644 --- a/lib/include/pl/patterns/pattern_struct.hpp +++ b/lib/include/pl/patterns/pattern_struct.hpp @@ -151,28 +151,6 @@ namespace pl::ptrn { return "struct " + Pattern::getTypeName(); } - [[nodiscard]] std::string toString() override { - std::string result = this->getFormattedName(); - result += " { "; - - for (const auto &member : this->m_members) { - if (member->getVariableName().starts_with("$")) - continue; - - result += fmt::format("{} = {}, ", member->getVariableName(), member->toString()); - } - - if (!this->m_members.empty()) { - // Remove trailing ", " - result.pop_back(); - result.pop_back(); - } - - result += " }"; - - return Pattern::callUserFormatFunc(this->reference(), true).value_or(result); - } - void sort(const std::function &comparator) override { this->m_sortedMembers.clear(); for (auto &member : this->m_members) @@ -217,10 +195,6 @@ namespace pl::ptrn { v.visit(*this); } - std::string formatDisplayValue() override { - return Pattern::callUserFormatFunc(this->reference()).value_or("{ ... }"); - } - std::vector getRawBytes() override { std::vector result; @@ -244,6 +218,31 @@ namespace pl::ptrn { Pattern::clearFormatCache(); } + protected: + std::string defaultToString() const override { + std::string result = this->getFormattedName(); + result += " { "; + + for (const auto &member : this->m_members) { + if (member->getVariableName().starts_with("$")) + continue; + + result += fmt::format("{} = {}, ", member->getVariableName(), member->toString()); + } + + if (!this->m_members.empty()) { + // Remove trailing ", " + result.pop_back(); + result.pop_back(); + } + + result += " }"; + return result; + } + + std::string defaultToDisplayValue() const override { + return "{ ... }"; + } private: std::vector> m_members; diff --git a/lib/include/pl/patterns/pattern_union.hpp b/lib/include/pl/patterns/pattern_union.hpp index 4b41bbf4..1877274e 100644 --- a/lib/include/pl/patterns/pattern_union.hpp +++ b/lib/include/pl/patterns/pattern_union.hpp @@ -143,28 +143,6 @@ namespace pl::ptrn { return "union " + Pattern::getTypeName(); } - [[nodiscard]] std::string toString() override { - std::string result = this->getFormattedName(); - result += " { "; - - for (const auto &member : this->m_members) { - if (member->getVariableName().starts_with("$")) - continue; - - result += fmt::format("{} = {}, ", member->getVariableName(), member->toString()); - } - - if (!this->m_members.empty()) { - // Remove trailing ", " - result.pop_back(); - result.pop_back(); - } - - result += " }"; - - return Pattern::callUserFormatFunc(this->reference(), true).value_or(result); - } - void sort(const std::function &comparator) override { this->m_sortedMembers.clear(); for (auto &member : this->m_members) @@ -209,10 +187,6 @@ namespace pl::ptrn { v.visit(*this); } - std::string formatDisplayValue() override { - return Pattern::callUserFormatFunc(this->reference()).value_or("{ ... }"); - } - std::vector getRawBytes() override { std::vector result; @@ -229,6 +203,31 @@ namespace pl::ptrn { Pattern::clearFormatCache(); } + protected: + std::string defaultToString() const override { + std::string result = this->getFormattedName(); + result += " { "; + + for (const auto &member : this->m_members) { + if (member->getVariableName().starts_with("$")) + continue; + + result += fmt::format("{} = {}, ", member->getVariableName(), member->toString()); + } + + if (!this->m_members.empty()) { + // Remove trailing ", " + result.pop_back(); + result.pop_back(); + } + + result += " }"; + return result; + } + + std::string defaultToDisplayValue() const override { + return "{ ... }"; + } private: std::vector> m_members; diff --git a/lib/include/pl/patterns/pattern_unsigned.hpp b/lib/include/pl/patterns/pattern_unsigned.hpp index 6cb650de..acf5180f 100644 --- a/lib/include/pl/patterns/pattern_unsigned.hpp +++ b/lib/include/pl/patterns/pattern_unsigned.hpp @@ -3,7 +3,6 @@ #include namespace pl::ptrn { - class PatternUnsigned : public Pattern { public: PatternUnsigned(core::Evaluator *evaluator, u64 offset, size_t size, u32 line) @@ -13,12 +12,6 @@ namespace pl::ptrn { return std::unique_ptr(new PatternUnsigned(*this)); } - [[nodiscard]] core::Token::Literal getValue() const override { - u128 data = 0; - this->getEvaluator()->readData(this->getOffset(), &data, this->getSize(), this->getSection()); - return transformValue(hlp::changeEndianess(data, this->getSize(), this->getEndian())); - } - [[nodiscard]] std::string getFormattedName() const override { return this->getTypeName(); } @@ -29,18 +22,6 @@ namespace pl::ptrn { v.visit(*this); } - std::string formatDisplayValue() override { - auto data = this->getValue().toUnsigned(); - return Pattern::callUserFormatFunc(this->getValue()).value_or(fmt::format("{:d}", data)); - } - - [[nodiscard]] std::string toString() override { - auto value = this->getValue(); - auto result = fmt::format("{:d}", value.toUnsigned()); - - return Pattern::callUserFormatFunc(value, true).value_or(result); - } - std::vector getRawBytes() override { std::vector result; result.resize(this->getSize()); @@ -51,6 +32,16 @@ namespace pl::ptrn { return result; } - }; -} \ No newline at end of file + [[nodiscard]] core::Token::Literal getRawValue() const override { + u128 data = 0; + this->getEvaluator()->readData(this->getOffset(), &data, this->getSize(), this->getSection()); + return hlp::changeEndianess(data, this->getSize(), this->getEndian()); + } + + protected: + std::string defaultToString() const override { + return fmt::format("{:d}", this->getValue().toUnsigned()); + } + }; +} diff --git a/lib/include/pl/patterns/pattern_wide_character.hpp b/lib/include/pl/patterns/pattern_wide_character.hpp index 1bc28b7c..43c06b95 100644 --- a/lib/include/pl/patterns/pattern_wide_character.hpp +++ b/lib/include/pl/patterns/pattern_wide_character.hpp @@ -5,7 +5,6 @@ #include namespace pl::ptrn { - class PatternWideCharacter : public Pattern { public: explicit PatternWideCharacter(core::Evaluator *evaluator, u64 offset, u32 line) @@ -15,36 +14,16 @@ namespace pl::ptrn { return std::unique_ptr(new PatternWideCharacter(*this)); } - [[nodiscard]] core::Token::Literal getValue() const override { - char16_t character = u'\u0000'; - this->getEvaluator()->readData(this->getOffset(), &character, 2, this->getSection()); - return transformValue(u128(hlp::changeEndianess(character, this->getEndian()))); - } - [[nodiscard]] std::string getFormattedName() const override { return "char16"; } - [[nodiscard]] std::string toString() override { - auto value = this->getValue(); - char16_t character = char16_t(value.toUnsigned()); - character = hlp::changeEndianess(character, this->getEndian()); - - auto result = wolv::util::utf16ToUtf8(std::u16string(&character, 1)).value_or("???"); - - return Pattern::callUserFormatFunc(value, true).value_or(result); - } - [[nodiscard]] bool operator==(const Pattern &other) const override { return compareCommonProperties(other); } void accept(PatternVisitor &v) override { v.visit(*this); } - std::string formatDisplayValue() override { - return Pattern::callUserFormatFunc(this->getValue()).value_or(fmt::format("'{0}'", this->toString())); - } - std::vector getRawBytes() override { std::vector result; result.resize(this->getSize()); @@ -55,6 +34,23 @@ namespace pl::ptrn { return result; } - }; + [[nodiscard]] core::Token::Literal getRawValue() const override { + char16_t character = u'\u0000'; + this->getEvaluator()->readData(this->getOffset(), &character, 2, this->getSection()); + return static_cast(hlp::changeEndianess(character, this->getEndian())); + } + + protected: + std::string defaultToString() const override { + char16_t character = static_cast(this->getValue().toUnsigned()); + character = hlp::changeEndianess(character, this->getEndian()); + + return wolv::util::utf16ToUtf8(std::u16string(&character, 1)).value_or("???"); + } + + std::string defaultToDisplayValue() const override { + return fmt::format("'{0}'", this->defaultToString()); + } + }; } diff --git a/lib/include/pl/patterns/pattern_wide_string.hpp b/lib/include/pl/patterns/pattern_wide_string.hpp index 6b2abf6b..a0f02700 100644 --- a/lib/include/pl/patterns/pattern_wide_string.hpp +++ b/lib/include/pl/patterns/pattern_wide_string.hpp @@ -16,10 +16,6 @@ namespace pl::ptrn { return std::unique_ptr(new PatternWideString(*this)); } - [[nodiscard]] core::Token::Literal getValue() const override { - return transformValue(this->getValue(this->getSize())); - } - std::string getValue(size_t size) const { std::u16string buffer(this->getSize() / sizeof(char16_t), 0x00); this->getEvaluator()->readData(this->getOffset(), buffer.data(), size, this->getSection()); @@ -38,39 +34,12 @@ namespace pl::ptrn { return "String16"; } - [[nodiscard]] std::string toString() override { - std::u16string buffer(this->getSize() / sizeof(char16_t), 0x00); - this->getEvaluator()->readData(this->getOffset(), buffer.data(), this->getSize(), this->getSection()); - - for (auto &c : buffer) - c = hlp::changeEndianess(c, 2, this->getEndian()); - - std::erase_if(buffer, [](auto c) { - return c == 0x00; - }); - - auto result = wolv::util::utf16ToUtf8(buffer).value_or("???"); - - return Pattern::callUserFormatFunc(this->getValue(), true).value_or(result); - } - [[nodiscard]] bool operator==(const Pattern &other) const override { return compareCommonProperties(other); } void accept(PatternVisitor &v) override { v.visit(*this); } - std::string formatDisplayValue() override { - auto size = std::min(this->getSize(), 0x100); - - if (size == 0) - return "\"\""; - - std::string utf8String = this->getValue(size); - - return Pattern::callUserFormatFunc(utf8String).value_or(fmt::format("\"{0}\" {1}", utf8String, size > this->getSize() ? "(truncated)" : "")); - } - [[nodiscard]] std::vector> getEntries() override { return { }; } @@ -111,6 +80,33 @@ namespace pl::ptrn { return result; } + + [[nodiscard]] core::Token::Literal getRawValue() const override { + return this->getValue(this->getSize()); + } + + protected: + std::string defaultToString() const override { + std::u16string buffer(this->getSize() / sizeof(char16_t), 0x00); + this->getEvaluator()->readData(this->getOffset(), buffer.data(), this->getSize(), this->getSection()); + + for (auto &c : buffer) + c = hlp::changeEndianess(c, 2, this->getEndian()); + + std::erase_if(buffer, [](auto c) { + return c == 0x00; + }); + return wolv::util::utf16ToUtf8(buffer).value_or("???"); + } + + std::string defaultToDisplayValue() const override { + auto size = std::min(this->getSize(), 0x100); + + if (size == 0) + return "\"\""; + + return fmt::format("\"{0}\" {1}", this->getValue(size), size > this->getSize() ? "(truncated)" : ""); + } }; } diff --git a/tests/include/test_patterns/test_pattern_attributes.hpp b/tests/include/test_patterns/test_pattern_attributes.hpp index 6f6ddba8..1e2824b8 100644 --- a/tests/include/test_patterns/test_pattern_attributes.hpp +++ b/tests/include/test_patterns/test_pattern_attributes.hpp @@ -12,6 +12,15 @@ namespace pl::test { [[nodiscard]] std::string getSourceCode() const override { return R"test( + struct FirstFormatOnlyTest { + s32 x [[format("format_field1")]]; + } [[format("format_only_test")]]; + + struct FormatOnlyTest { + s32 x [[format("format_field1")]]; + FirstFormatOnlyTest y [[format("format_field2")]]; + } [[format("format_only_test")]]; + struct FormatTransformTest { u32 x, y, z; } [[format("format_test"), transform("transform_test")]]; @@ -33,14 +42,28 @@ namespace pl::test { u32 y [[no_unique_address]]; }; + fn format_only_test(auto value) { + std::assert(value.x == 1196314761, "Accessing field in format in FormatOnlyTest"); + return "Hello"; + }; + fn format_test(FormatTransformTest value) { + std::assert(value.x == 1196314761, "Accessing field in format in FormatTransformTest"); return "Hello World"; }; fn transform_test(FormatTransformTest value) { + std::assert(value.x == 1196314761, "Accessing field in transform"); return 1337; }; + fn format_field1(s32 value) { + return builtin::std::format("Value is {}", value); + }; + fn format_field2(FirstFormatOnlyTest value) { + return builtin::std::format("Pattern value is {}", value.x); + }; + struct FixedSizeTest1 { u8 x; } [[fixed_size(4)]]; @@ -55,6 +78,7 @@ namespace pl::test { std::assert($ == pos + 4, "Fixed size pattern attribute padding not working"); }; + FormatOnlyTest formatOnlyTest @ 0x00; FormatTransformTest formatTransformTest @ 0x00; SealedTest sealedTest @ 0x10; HiddenTest hiddenTest @ 0x20; @@ -63,7 +87,13 @@ namespace pl::test { FixedSizeTest1 fixedSizeTest1 @ 0x50; FixedSizeTest2 fixedSizeTest2 @ 0x60; - std::assert(formatTransformTest == 1337, "Transform attribute not working"); + // std::format does not respect [[format]] for non-patterns values + std::assert(builtin::std::format("{}", formatOnlyTest.x) == "1196314761", "Format attribute should not apply to non-pattern field"); + std::assert(builtin::std::format("{}", formatOnlyTest.y) == "Pattern value is 169478669", "Format attribute on field not working on pattern value"); + std::assert(builtin::std::format("{}", formatOnlyTest) == "Hello", "Format attribute not working"); + + std::assert(formatTransformTest == 1337, "Transform attribute not working 1"); + std::assert(builtin::std::format("{}", formatTransformTest) == "1337", "Transform attribute not working 2"); std::assert(sizeof(noUniqueAddressTest) == sizeof(u32), "No Unique Address attribute not working"); std::assert(sizeof(fixedSizeTest1) == 4, "Fixed size attribute not working"); )test"; @@ -73,9 +103,33 @@ namespace pl::test { for (const auto &pattern : patterns) { auto varName = pattern->getVariableName(); - if (varName == "formatTransformTest") { + if (varName == "formatOnlyTest") { + if (pattern->getFormattedValue() != "Hello") + return false; + if (pattern->toString() != "Hello") + return false; + + if (auto *iterable = dynamic_cast(pattern.get()); iterable != nullptr) { + for (const auto &entry : iterable->getEntries()) { + const auto entryName = entry->getVariableName(); + if (entryName == "x") { + if (entry->getFormattedValue() != "Value is 1196314761") + return false; + if (entry->toString() != "Value is 1196314761") + return false; + } else if (entryName == "y") { + if (entry->getFormattedValue() != "Pattern value is 169478669") + return false; + if (entry->toString() != "Pattern value is 169478669") + return false; + } + } + } + } else if (varName == "formatTransformTest") { if (pattern->getFormattedValue() != "Hello World") return false; + if (pattern->toString() != "Hello World") + return false; } else if (varName == "sealedTest") { if (!pattern->isSealed()) return false; @@ -93,4 +147,4 @@ namespace pl::test { }; -} \ No newline at end of file +}