diff --git a/lib/libimhex/source/pattern_language/evaluator.cpp b/lib/libimhex/source/pattern_language/evaluator.cpp index f66a2d2f7..79034ad83 100644 --- a/lib/libimhex/source/pattern_language/evaluator.cpp +++ b/lib/libimhex/source/pattern_language/evaluator.cpp @@ -37,12 +37,13 @@ namespace hex::pl { auto startOffset = this->dataOffset(); std::unique_ptr pattern; - this->dataOffset() = startOffset; bool referenceType = false; auto typePattern = type->createPatterns(this); + this->dataOffset() = startOffset; + if (typePattern.empty()) { // Handle auto variables if (!value.has_value()) diff --git a/tests/pattern_language/CMakeLists.txt b/tests/pattern_language/CMakeLists.txt index be58ffe8d..0742b703e 100644 --- a/tests/pattern_language/CMakeLists.txt +++ b/tests/pattern_language/CMakeLists.txt @@ -19,6 +19,8 @@ set(AVAILABLE_TESTS Namespaces ExtraSemicolon Pointers + Arrays + NestedStructs ) @@ -42,4 +44,4 @@ add_custom_command(TARGET pattern_language_tests foreach (test IN LISTS AVAILABLE_TESTS) add_test(NAME "PatternLanguage/${test}" COMMAND pattern_language_tests "${test}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) endforeach () -add_dependencies(unit_tests ${PROJECT_NAME}) \ No newline at end of file +add_dependencies(unit_tests ${PROJECT_NAME}) diff --git a/tests/pattern_language/include/test_patterns/test_pattern_arrays.hpp b/tests/pattern_language/include/test_patterns/test_pattern_arrays.hpp new file mode 100644 index 000000000..150b1088e --- /dev/null +++ b/tests/pattern_language/include/test_patterns/test_pattern_arrays.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include "test_pattern.hpp" + +#include +#include +#include + +#include + +namespace hex::test { + + class TestPatternArrays : public TestPattern { + public: + TestPatternArrays() : TestPattern("Arrays") { + auto first = create("u8", "first", 0x0, sizeof(u8[4])); + first->setEntries(create("u8", "", 0x0, sizeof(u8)), 4); + + auto second = create("u8", "second", 0x4, sizeof(u8[4])); + second->setEntries(create("u8", "", 0x4, sizeof(u8)), 4); + + auto testStruct = create("Signature", "sign", 0x0, sizeof(u8[8])); + std::vector> structMembers; + { + structMembers.push_back(std::move(first)); + structMembers.push_back(std::move(second)); + } + testStruct->setMembers(std::move(structMembers)); + + addPattern(std::move(testStruct)); + } + ~TestPatternArrays() override = default; + + [[nodiscard]] std::string getSourceCode() const override { + return R"( + fn end_of_signature() { + return $ >= 8; + }; + + struct Signature { + u8 first[4]; + u8 second[while(!end_of_signature())]; + }; + + Signature sign @ 0x0; + + std::assert(sign.first[0] == 0x89, "Invalid 1st byte of signature"); + std::assert(sign.first[1] == 0x50, "Invalid 2nd byte of signature"); + std::assert(sign.first[2] == 0x4E, "Invalid 3rd byte of signature"); + std::assert(sign.first[3] == 0x47, "Invalid 4th byte of signature"); + std::assert(sizeof(sign.second) == 4, "Invalid size of signature"); + std::assert(sign.second[0] == 0x0D, "Invalid 5th byte of signature"); + std::assert(sign.second[1] == 0x0A, "Invalid 6th byte of signature"); + std::assert(sign.second[2] == 0x1A, "Invalid 7th byte of signature"); + std::assert(sign.second[3] == 0x0A, "Invalid 8th byte of signature"); + )"; + } + }; + +} \ No newline at end of file diff --git a/tests/pattern_language/include/test_patterns/test_pattern_nested_structs.hpp b/tests/pattern_language/include/test_patterns/test_pattern_nested_structs.hpp new file mode 100644 index 000000000..cb034281f --- /dev/null +++ b/tests/pattern_language/include/test_patterns/test_pattern_nested_structs.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include "test_pattern.hpp" + +#include +#include +#include + +#include + +namespace hex::test { + + class TestPatternNestedStructs : public TestPattern { + public: + TestPatternNestedStructs() : TestPattern("NestedStructs") { + const size_t HEADER_START = 0x0; + const size_t HEADER_SIZE = sizeof(u8); + const size_t BODY_START = HEADER_SIZE; + const size_t BODY_SIZE = 0x89 - 1; + + auto data = create("Data", "data", HEADER_START, HEADER_SIZE + BODY_SIZE); + { + auto hdr = create("Header", "hdr", HEADER_START, HEADER_SIZE); + { + std::vector> hdrMembers { + std::shared_ptr(create("u8", "len", HEADER_START, sizeof(u8))) + }; + hdr->setMembers(std::move(hdrMembers)); + } + + auto body = create("Body", "body", BODY_START, BODY_SIZE); + { + auto bodyArray = create("u8", "arr", BODY_START, BODY_SIZE); + bodyArray->setEntries(create("u8", "", BODY_START, sizeof(u8)), BODY_SIZE); + std::vector> bodyMembers { + std::shared_ptr(std::move(bodyArray)) + }; + body->setMembers(std::move(bodyMembers)); + } + + std::vector> dataMembers { + std::shared_ptr(std::move(hdr)), + std::shared_ptr(std::move(body)) + }; + data->setMembers(std::move(dataMembers)); + } + + addPattern(std::move(data)); + } + ~TestPatternNestedStructs() override = default; + + [[nodiscard]] std::string getSourceCode() const override { + return R"( + fn end_of_body() { + u32 start = addressof(parent.parent.hdr); + u32 len = parent.parent.hdr.len; + u32 end = start + len; + + return $ >= end; + }; + + struct Header { + u8 len; + }; + + struct Body { + u8 arr[while(!end_of_body())]; + }; + + struct Data { + Header hdr; + Body body; + }; + + Data data @ 0x0; + + std::assert(data.hdr.len == 0x89, "Invalid length"); + std::assert(sizeof(data.body.arr) == 0x89 - 1, "Invalid size of body"); + )"; + } + }; + +} \ No newline at end of file diff --git a/tests/pattern_language/source/tests.cpp b/tests/pattern_language/source/tests.cpp index a3dc1d58b..87ae14d1f 100644 --- a/tests/pattern_language/source/tests.cpp +++ b/tests/pattern_language/source/tests.cpp @@ -14,6 +14,8 @@ #include "test_patterns/test_pattern_namespaces.hpp" #include "test_patterns/test_pattern_extra_semicolon.hpp" #include "test_patterns/test_pattern_pointers.hpp" +#include "test_patterns/test_pattern_arrays.hpp" +#include "test_patterns/test_pattern_nested_structs.hpp" std::array Tests = { TEST(Placement), @@ -29,5 +31,7 @@ std::array Tests = { TEST(RValues), TEST(Namespaces), TEST(ExtraSemicolon), - TEST(Pointers) + TEST(Pointers), + TEST(Arrays), + TEST(NestedStructs), }; \ No newline at end of file