mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
KindFlags refactor, indicator helpers, auto-padding, sizeof format fix
- Add KindFlags bitmask enum (KF_HexPreview, KF_Container, KF_String, KF_Vector) - Add helper functions: isHexPreview(), flagsFor(), allTypeNamesForUI() - Add editor helpers: clearIndicatorLine(), fillIndicatorCols(), resolvedSpanFor() - Use SCI_FINDCOLUMN for UTF-8 safe column-to-position conversion - Auto-emit hex padding nodes when changing type to smaller size - Fix struct footer format: sizeof(Name)=0x... (no spaces) - Add tests for sizeof recalculation after node deletion - Add debug output to investigate sizeof refresh issue - Replace icons.qrc with resources.qrc, add embedded fonts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -641,9 +641,9 @@ private slots:
|
||||
int lastLine = result.meta.size() - 1;
|
||||
QCOMPARE(result.meta[lastLine].lineKind, LineKind::Footer);
|
||||
|
||||
// Footer text should contain sizeof=0xC (4+8=12=0xC)
|
||||
// Footer text should contain sizeof(Sized)=0xC (4+8=12=0xC)
|
||||
QString footerText = result.text.split('\n').last();
|
||||
QVERIFY(footerText.contains("sizeof=0xC"));
|
||||
QVERIFY(footerText.contains("sizeof(Sized)=0xC"));
|
||||
}
|
||||
|
||||
void testLineMetaHasNodeId() {
|
||||
@@ -668,6 +668,116 @@ private slots:
|
||||
QCOMPARE(result.meta[i].nodeId, tree.nodes[ni].id);
|
||||
}
|
||||
}
|
||||
|
||||
void testSizeofUpdatesAfterDelete() {
|
||||
// Test that sizeof recalculates after deleting a node
|
||||
NodeTree tree;
|
||||
tree.baseAddress = 0;
|
||||
|
||||
Node root;
|
||||
root.kind = NodeKind::Struct;
|
||||
root.name = "Test";
|
||||
root.parentId = 0;
|
||||
root.offset = 0;
|
||||
int ri = tree.addNode(root);
|
||||
uint64_t rootId = tree.nodes[ri].id;
|
||||
|
||||
Node f1;
|
||||
f1.kind = NodeKind::UInt32;
|
||||
f1.name = "a";
|
||||
f1.parentId = rootId;
|
||||
f1.offset = 0;
|
||||
tree.addNode(f1);
|
||||
|
||||
Node f2;
|
||||
f2.kind = NodeKind::UInt64;
|
||||
f2.name = "b";
|
||||
f2.parentId = rootId;
|
||||
f2.offset = 4;
|
||||
int f2i = tree.addNode(f2);
|
||||
uint64_t f2Id = tree.nodes[f2i].id;
|
||||
|
||||
NullProvider prov;
|
||||
|
||||
// First compose: sizeof should be 0xC (4+8=12)
|
||||
ComposeResult result1 = compose(tree, prov);
|
||||
QString footer1 = result1.text.split('\n').last();
|
||||
QVERIFY2(footer1.contains("sizeof(Test)=0xC"),
|
||||
qPrintable("Before delete: " + footer1));
|
||||
|
||||
// Delete the second field
|
||||
int idx = tree.indexOfId(f2Id);
|
||||
QVERIFY(idx >= 0);
|
||||
tree.nodes.remove(idx);
|
||||
tree.invalidateIdCache();
|
||||
|
||||
// Second compose: sizeof should be 0x4 (only UInt32 remains)
|
||||
ComposeResult result2 = compose(tree, prov);
|
||||
QString footer2 = result2.text.split('\n').last();
|
||||
QVERIFY2(footer2.contains("sizeof(Test)=0x4"),
|
||||
qPrintable("After delete: " + footer2));
|
||||
}
|
||||
|
||||
void testNestedStructSizeofUpdates() {
|
||||
// Test nested struct sizeof updates when child is deleted
|
||||
NodeTree tree;
|
||||
tree.baseAddress = 0;
|
||||
|
||||
// Root struct
|
||||
Node root;
|
||||
root.kind = NodeKind::Struct;
|
||||
root.name = "Root";
|
||||
root.parentId = 0;
|
||||
root.offset = 0;
|
||||
int ri = tree.addNode(root);
|
||||
uint64_t rootId = tree.nodes[ri].id;
|
||||
|
||||
// Nested struct (like IMAGE_FILE_HEADER)
|
||||
Node nested;
|
||||
nested.kind = NodeKind::Struct;
|
||||
nested.name = "Nested";
|
||||
nested.parentId = rootId;
|
||||
nested.offset = 0;
|
||||
int ni = tree.addNode(nested);
|
||||
uint64_t nestedId = tree.nodes[ni].id;
|
||||
|
||||
// Field in nested struct
|
||||
Node f1;
|
||||
f1.kind = NodeKind::UInt32;
|
||||
f1.name = "a";
|
||||
f1.parentId = nestedId;
|
||||
f1.offset = 0;
|
||||
tree.addNode(f1);
|
||||
|
||||
Node f2;
|
||||
f2.kind = NodeKind::UInt32;
|
||||
f2.name = "b";
|
||||
f2.parentId = nestedId;
|
||||
f2.offset = 4;
|
||||
int f2i = tree.addNode(f2);
|
||||
uint64_t f2Id = tree.nodes[f2i].id;
|
||||
|
||||
NullProvider prov;
|
||||
|
||||
// First compose
|
||||
ComposeResult result1 = compose(tree, prov);
|
||||
// Find nested struct footer
|
||||
QString text1 = result1.text;
|
||||
QVERIFY2(text1.contains("sizeof(Nested)=0x8"),
|
||||
qPrintable("Before delete nested sizeof: " + text1));
|
||||
|
||||
// Delete field from nested struct
|
||||
int idx = tree.indexOfId(f2Id);
|
||||
QVERIFY(idx >= 0);
|
||||
tree.nodes.remove(idx);
|
||||
tree.invalidateIdCache();
|
||||
|
||||
// Second compose - nested sizeof should update
|
||||
ComposeResult result2 = compose(tree, prov);
|
||||
QString text2 = result2.text;
|
||||
QVERIFY2(text2.contains("sizeof(Nested)=0x4"),
|
||||
qPrintable("After delete nested sizeof: " + text2));
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_MAIN(TestCompose)
|
||||
|
||||
@@ -279,27 +279,28 @@ private slots:
|
||||
QVERIFY(ok);
|
||||
QCOMPARE((uint8_t)b[0], (uint8_t)0x4D);
|
||||
|
||||
// Hex32 with space-separated bytes
|
||||
// Hex32 with space-separated bytes (raw byte order, no endian conversion)
|
||||
b = fmt::parseValue(NodeKind::Hex32, "DE AD BE EF", &ok);
|
||||
QVERIFY(ok);
|
||||
QCOMPARE(b.size(), 4);
|
||||
uint32_t v32;
|
||||
memcpy(&v32, b.data(), 4);
|
||||
QCOMPARE(v32, (uint32_t)0xDEADBEEF);
|
||||
QCOMPARE((uint8_t)b[0], (uint8_t)0xDE);
|
||||
QCOMPARE((uint8_t)b[1], (uint8_t)0xAD);
|
||||
QCOMPARE((uint8_t)b[2], (uint8_t)0xBE);
|
||||
QCOMPARE((uint8_t)b[3], (uint8_t)0xEF);
|
||||
|
||||
// Hex64 with space-separated bytes
|
||||
b = fmt::parseValue(NodeKind::Hex64, "4D 5A 90 00 00 00 00 00", &ok);
|
||||
QVERIFY(ok);
|
||||
QCOMPARE(b.size(), 8);
|
||||
uint64_t v64;
|
||||
memcpy(&v64, b.data(), 8);
|
||||
QCOMPARE(v64, (uint64_t)0x4D5A900000000000ULL);
|
||||
QCOMPARE((uint8_t)b[0], (uint8_t)0x4D);
|
||||
QCOMPARE((uint8_t)b[1], (uint8_t)0x5A);
|
||||
QCOMPARE((uint8_t)b[7], (uint8_t)0x00);
|
||||
|
||||
// Hex64 continuous (should still work)
|
||||
b = fmt::parseValue(NodeKind::Hex64, "4D5A900000000000", &ok);
|
||||
QVERIFY(ok);
|
||||
memcpy(&v64, b.data(), 8);
|
||||
QCOMPARE(v64, (uint64_t)0x4D5A900000000000ULL);
|
||||
QCOMPARE((uint8_t)b[0], (uint8_t)0x4D);
|
||||
QCOMPARE((uint8_t)b[1], (uint8_t)0x5A);
|
||||
|
||||
// Hex64 with 0x prefix and spaces
|
||||
b = fmt::parseValue(NodeKind::Hex64, "0x4D 5A 90 00 00 00 00 00", &ok);
|
||||
|
||||
@@ -62,7 +62,7 @@ private slots:
|
||||
n.name = "Test";
|
||||
QString s = fmt::fmtStructFooter(n, 0);
|
||||
QVERIFY(s.contains("};"));
|
||||
QVERIFY(s.contains("Test"));
|
||||
// When no size, footer is just "};" without name
|
||||
}
|
||||
|
||||
void testIndent() {
|
||||
@@ -93,12 +93,14 @@ private slots:
|
||||
|
||||
void testParseValueHex32() {
|
||||
bool ok;
|
||||
// Hex parsing produces raw bytes (no endian conversion)
|
||||
QByteArray b = fmt::parseValue(NodeKind::Hex32, "DEADBEEF", &ok);
|
||||
QVERIFY(ok);
|
||||
QCOMPARE(b.size(), 4);
|
||||
uint32_t v;
|
||||
memcpy(&v, b.data(), 4);
|
||||
QCOMPARE(v, (uint32_t)0xDEADBEEF);
|
||||
QCOMPARE((uint8_t)b[0], (uint8_t)0xDE);
|
||||
QCOMPARE((uint8_t)b[1], (uint8_t)0xAD);
|
||||
QCOMPARE((uint8_t)b[2], (uint8_t)0xBE);
|
||||
QCOMPARE((uint8_t)b[3], (uint8_t)0xEF);
|
||||
}
|
||||
|
||||
void testParseValueBool() {
|
||||
@@ -119,12 +121,13 @@ private slots:
|
||||
|
||||
void testParseValueHex0xPrefix() {
|
||||
bool ok;
|
||||
// Hex32 with 0x prefix should work
|
||||
// Hex32 with 0x prefix should work (raw bytes, no endian conversion)
|
||||
QByteArray b = fmt::parseValue(NodeKind::Hex32, "0xDEADBEEF", &ok);
|
||||
QVERIFY(ok);
|
||||
uint32_t v;
|
||||
memcpy(&v, b.data(), 4);
|
||||
QCOMPARE(v, (uint32_t)0xDEADBEEF);
|
||||
QCOMPARE((uint8_t)b[0], (uint8_t)0xDE);
|
||||
QCOMPARE((uint8_t)b[1], (uint8_t)0xAD);
|
||||
QCOMPARE((uint8_t)b[2], (uint8_t)0xBE);
|
||||
QCOMPARE((uint8_t)b[3], (uint8_t)0xEF);
|
||||
|
||||
// Pointer64 with 0x prefix
|
||||
b = fmt::parseValue(NodeKind::Pointer64, "0x0000000000400000", &ok);
|
||||
@@ -229,8 +232,7 @@ private slots:
|
||||
// With size
|
||||
QString s1 = fmt::fmtStructFooter(n, 0, 0x14);
|
||||
QVERIFY(s1.contains("};"));
|
||||
QVERIFY(s1.contains("Test"));
|
||||
QVERIFY(s1.contains("sizeof=0x14"));
|
||||
QVERIFY(s1.contains("sizeof(Test)=0x14"));
|
||||
|
||||
// Size 0 → no sizeof
|
||||
QString s2 = fmt::fmtStructFooter(n, 0, 0);
|
||||
|
||||
Reference in New Issue
Block a user