From 73564cf0f0b90901f266d6b487938c9b251ca2d6 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 5 Feb 2022 19:48:08 +0100 Subject: [PATCH] Dump StructuredDataDef paddings --- .../StructuredDataDefDumper.cpp | 52 +++++++-- .../StructuredDataDefDumper.h | 12 ++- .../AssetDumperStructuredDataDefSet.cpp | 100 +++++++++++++++--- .../AssetDumperStructuredDataDefSet.h | 2 + 4 files changed, 139 insertions(+), 27 deletions(-) diff --git a/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.cpp b/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.cpp index f618f3b6..0c322c52 100644 --- a/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.cpp +++ b/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.cpp @@ -4,9 +4,11 @@ #include #include -StructuredDataDefDumper::StructEntry::StructEntry(std::string stringValue, const size_t offset) +StructuredDataDefDumper::StructEntry::StructEntry(std::string stringValue, const size_t offset, const size_t sizeInBits, const size_t alignment) : m_string_value(std::move(stringValue)), - m_offset(offset) + m_offset(offset), + m_size_in_bits(sizeInBits), + m_alignment(alignment) { } @@ -16,7 +18,9 @@ StructuredDataDefDumper::StructuredDataDefDumper(std::ostream& stream) m_flags{}, m_enum_entry_count(0u), m_struct_property_count(0u), - m_current_property_offset(0u) + m_current_property_offset(0u), + m_current_property_size_in_bits(0u), + m_current_property_alignment(0u) { } @@ -75,7 +79,7 @@ void StructuredDataDefDumper::BeginEnum(const std::string& enumName, const size_ m_stream << "enum(" << enumReservedEntryCount << ") "; else m_stream << "enum "; - m_stream << enumName; + m_stream << enumName; m_stream << "\n"; @@ -130,7 +134,7 @@ void StructuredDataDefDumper::WriteEnumEntry(const std::string& entryName, const m_enum_entries[entryValue] = entryName; } -void StructuredDataDefDumper::BeginStruct(const std::string& structName, const size_t structPropertyCount) +void StructuredDataDefDumper::BeginStruct(const std::string& structName, const size_t structPropertyCount, const size_t structSizeInBits, const size_t structInitialOffset) { assert(m_flags.m_in_version); assert(m_block == Block::BLOCK_NONE); @@ -139,6 +143,8 @@ void StructuredDataDefDumper::BeginStruct(const std::string& structName, const s return; m_struct_property_count = structPropertyCount; + m_struct_size_in_bits = structSizeInBits; + m_struct_initial_offset = structInitialOffset; m_struct_properties.reserve(structPropertyCount); if (m_flags.m_empty_line_before_block) @@ -166,10 +172,34 @@ void StructuredDataDefDumper::EndStruct() return e1.m_offset < e2.m_offset; }); + auto expectedOffset = m_struct_initial_offset; for (auto& structProperty : m_struct_properties) { + if (structProperty.m_alignment > 0) + expectedOffset = (expectedOffset + structProperty.m_alignment - 1) / structProperty.m_alignment * structProperty.m_alignment; + + if(expectedOffset != structProperty.m_offset) + { + assert(structProperty.m_offset > expectedOffset); + assert((structProperty.m_offset - expectedOffset) % 8 == 0); + Indent(); + m_stream << "pad(" << (structProperty.m_offset - expectedOffset) << ");\n"; + expectedOffset = structProperty.m_offset; + } + Indent(); m_stream << structProperty.m_string_value << ";\n"; + + expectedOffset += structProperty.m_size_in_bits; + } + + expectedOffset = (expectedOffset + 7) / 8 * 8; + if (m_struct_size_in_bits > 0 && expectedOffset != m_struct_size_in_bits) + { + assert(m_struct_size_in_bits > expectedOffset); + assert((m_struct_size_in_bits - expectedOffset) % 8 == 0); + Indent(); + m_stream << "pad(" << (m_struct_size_in_bits - expectedOffset) / 8 << ");\n"; } DecIndent(); @@ -179,9 +209,11 @@ void StructuredDataDefDumper::EndStruct() m_flags.m_empty_line_before_block = true; m_struct_properties.clear(); m_struct_property_count = 0u; + m_struct_initial_offset = 0u; + m_struct_size_in_bits = 0u; } -void StructuredDataDefDumper::BeginProperty(const std::string& propertyName, const size_t propertyOffset) +void StructuredDataDefDumper::BeginProperty(const std::string& propertyName, const size_t propertyOffset, const size_t propertySizeInBits, const size_t alignment) { assert(m_flags.m_in_version); assert(m_block == Block::BLOCK_STRUCT); @@ -191,6 +223,8 @@ void StructuredDataDefDumper::BeginProperty(const std::string& propertyName, con m_current_property_name = propertyName; m_current_property_offset = propertyOffset; + m_current_property_size_in_bits = propertySizeInBits; + m_current_property_alignment = alignment; m_block = Block::BLOCK_PROPERTY; } @@ -221,12 +255,12 @@ void StructuredDataDefDumper::EndProperty() } ss << " /* Offset: " << m_current_property_offset / 8; - + if (m_current_property_offset % 8 > 0) ss << " + " << m_current_property_offset % 8 << "bit"; - + ss << " */ "; - m_struct_properties.emplace_back(ss.str(), m_current_property_offset); + m_struct_properties.emplace_back(ss.str(), m_current_property_offset, m_current_property_size_in_bits, m_current_property_alignment); m_block = Block::BLOCK_STRUCT; m_current_property_array_specifiers.clear(); diff --git a/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.h b/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.h index 4ff9134a..fcea85a6 100644 --- a/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.h +++ b/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.h @@ -10,8 +10,10 @@ class StructuredDataDefDumper : AbstractTextDumper { std::string m_string_value; size_t m_offset; + size_t m_size_in_bits; + size_t m_alignment; - StructEntry(std::string stringValue, size_t offset); + StructEntry(std::string stringValue, size_t offset, size_t sizeInBits, size_t alignment); }; enum class Block @@ -34,8 +36,12 @@ class StructuredDataDefDumper : AbstractTextDumper std::vector m_struct_properties; size_t m_struct_property_count; + size_t m_struct_initial_offset; + size_t m_struct_size_in_bits; std::string m_current_property_name; size_t m_current_property_offset; + size_t m_current_property_size_in_bits; + size_t m_current_property_alignment; std::string m_current_property_type_name; std::vector m_current_property_array_specifiers; @@ -51,9 +57,9 @@ public: void EndEnum(); void WriteEnumEntry(const std::string& entryName, size_t entryValue); - void BeginStruct(const std::string& structName, size_t structPropertyCount); + void BeginStruct(const std::string& structName, size_t structPropertyCount, size_t structSizeInBits, size_t structInitialOffset); void EndStruct(); - void BeginProperty(const std::string& propertyName, size_t propertyOffset); + void BeginProperty(const std::string& propertyName, size_t propertyOffset, size_t propertySizeInBits, size_t alignment); void AddPropertyArraySpecifier(const std::string& specifierName); void SetPropertyTypeName(const std::string& typeName); void EndProperty(); diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.cpp index d07af99e..53711ece 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.cpp +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.cpp @@ -11,9 +11,9 @@ using namespace std::string_literals; bool AssetDumperStructuredDataDefSet::GetNextHeadValue(const StructuredDataDef* def, const bool isFirstStruct, const std::vector& structsIncludedInOrder, size_t& nextHeadValue) { - if(isFirstStruct - && def->rootType.type == DATA_STRUCT - && def->rootType.u.structIndex >= 0 + if (isFirstStruct + && def->rootType.type == DATA_STRUCT + && def->rootType.u.structIndex >= 0 && def->rootType.u.structIndex < def->structCount) { nextHeadValue = def->rootType.u.structIndex; @@ -32,7 +32,7 @@ bool AssetDumperStructuredDataDefSet::GetNextHeadValue(const StructuredDataDef* StructuredDataType AssetDumperStructuredDataDefSet::GetBaseType(const StructuredDataDef* def, StructuredDataType type) { - while(true) + while (true) { if (type.type == DATA_INDEXED_ARRAY) { @@ -69,7 +69,7 @@ std::vector AssetDumperStructuredDataDefSet::CalculateStructDumpingOrder result.reserve(def->structCount); std::vector structIncludedInOrder(def->structCount); - while(resultStructTail < structCount) + while (resultStructTail < structCount) { size_t nextHeadValue; if (!GetNextHeadValue(def, resultStructHead == 0, structIncludedInOrder, nextHeadValue)) @@ -78,18 +78,18 @@ std::vector AssetDumperStructuredDataDefSet::CalculateStructDumpingOrder structIncludedInOrder[nextHeadValue] = true; ++resultStructHead; - while(resultStructHead > resultStructTail) + while (resultStructHead > resultStructTail) { const auto& currentStruct = def->structs[result[resultStructTail++]]; - if(currentStruct.properties == nullptr) + if (currentStruct.properties == nullptr) continue; - for(auto i = 0; i < currentStruct.propertyCount; i++) + for (auto i = 0; i < currentStruct.propertyCount; i++) { const auto baseType = GetBaseType(def, currentStruct.properties[i].type); - if(baseType.type == DATA_STRUCT - && baseType.u.structIndex >= 0 + if (baseType.type == DATA_STRUCT + && baseType.u.structIndex >= 0 && static_cast(baseType.u.structIndex) < structCount && structIncludedInOrder[static_cast(baseType.u.structIndex)] == false) { @@ -116,7 +116,7 @@ void AssetDumperStructuredDataDefSet::DumpEnum(StructuredDataDefDumper& dumper, dumper.BeginEnum(ss.str(), static_cast(_enum->entryCount), static_cast(_enum->reservedEntryCount)); - if(_enum->entries && _enum->entryCount > 0) + if (_enum->entries && _enum->entryCount > 0) { for (auto i = 0; i < _enum->entryCount; i++) { @@ -133,9 +133,72 @@ void AssetDumperStructuredDataDefSet::DumpEnum(StructuredDataDefDumper& dumper, dumper.EndEnum(); } +size_t AssetDumperStructuredDataDefSet::GetPropertySizeInBits(const StructuredDataStructProperty& property, const StructuredDataDef* def) +{ + switch (property.type.type) + { + case DATA_FLOAT: + case DATA_INT: + return 32; + case DATA_BYTE: + return 8; + case DATA_BOOL: + return 1; + case DATA_SHORT: + case DATA_ENUM: + return 16; + case DATA_STRING: + return property.type.u.stringDataLength * 8; + case DATA_STRUCT: + if (property.type.u.structIndex < 0 || property.type.u.structIndex >= def->structCount || def->structs == nullptr) + { + assert(false); + return 0; + } + return static_cast(def->structs[property.type.u.structIndex].size) * 8; + case DATA_INDEXED_ARRAY: + { + if (property.type.u.indexedArrayIndex < 0 || property.type.u.indexedArrayIndex >= def->indexedArrayCount || def->indexedArrays == nullptr) + { + assert(false); + return 0; + } + const auto& indexedArray = def->indexedArrays[property.type.u.indexedArrayIndex]; + const auto elementSize = indexedArray.elementType.type == DATA_BOOL ? 1 : indexedArray.elementSize * 8; + return elementSize * static_cast(def->indexedArrays[property.type.u.indexedArrayIndex].arraySize); + } + case DATA_ENUM_ARRAY: + { + if (property.type.u.enumedArrayIndex < 0 || property.type.u.enumedArrayIndex >= def->enumedArrayCount || def->enumedArrays == nullptr) + { + assert(false); + return 0; + } + + const auto& enumedArray = def->enumedArrays[property.type.u.enumedArrayIndex]; + if (enumedArray.enumIndex < 0 || enumedArray.enumIndex >= def->enumCount || def->enums == nullptr) + { + assert(false); + return 0; + } + + const auto elementSize = enumedArray.elementType.type == DATA_BOOL ? 1 : enumedArray.elementSize * 8; + return elementSize * static_cast(def->enums[enumedArray.enumIndex].reservedEntryCount); + } + default: + assert(false); + return 0; + } +} + +size_t AssetDumperStructuredDataDefSet::GetPropertyAlign(const StructuredDataStructProperty& property) +{ + return property.type.type == DATA_BOOL ? 0 : 8; +} + void AssetDumperStructuredDataDefSet::DumpProperty(StructuredDataDefDumper& dumper, const StructuredDataStructProperty& property, const StructuredDataDef* def, const int rootStructIndex) { - dumper.BeginProperty(property.name, property.type.type == DATA_BOOL ? property.offset : property.offset * 8); + dumper.BeginProperty(property.name, property.type.type == DATA_BOOL ? property.offset : property.offset * 8, GetPropertySizeInBits(property, def), GetPropertyAlign(property)); auto currentType = property.type; auto stopTypeIteration = false; @@ -242,25 +305,32 @@ void AssetDumperStructuredDataDefSet::DumpProperty(StructuredDataDefDumper& dump dumper.EndProperty(); } -void AssetDumperStructuredDataDefSet::DumpStruct(StructuredDataDefDumper& dumper, const size_t structIndex, const StructuredDataStruct* _struct, const StructuredDataDef* def, const int rootStructIndex) +void AssetDumperStructuredDataDefSet::DumpStruct(StructuredDataDefDumper& dumper, const size_t structIndex, const StructuredDataStruct* _struct, const StructuredDataDef* def, + const int rootStructIndex) { std::string structName; + size_t actualStructSize; + size_t initialOffset; if (static_cast(structIndex) == rootStructIndex) { structName = "root"; + actualStructSize = def->size; + initialOffset = 64; } else { std::ostringstream ss; ss << "STRUCT_" << structIndex; structName = ss.str(); + actualStructSize = static_cast(_struct->size); + initialOffset = 0; } dumper.WriteLineComment("BitOffset: "s + std::to_string(_struct->bitOffset)); dumper.WriteLineComment("Size: "s + std::to_string(_struct->size)); - dumper.BeginStruct(structName, static_cast(_struct->propertyCount)); + dumper.BeginStruct(structName, static_cast(_struct->propertyCount), actualStructSize * 8, initialOffset); - if(_struct->properties && _struct->propertyCount > 0) + if (_struct->properties && _struct->propertyCount > 0) { for (auto i = 0; i < _struct->propertyCount; i++) { diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.h b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.h index 362747e7..6b586f96 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.h +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.h @@ -15,6 +15,8 @@ namespace IW4 static StructuredDataType GetBaseType(const StructuredDataDef* def, StructuredDataType type); static std::vector CalculateStructDumpingOrder(const StructuredDataDef* def); static void DumpEnum(StructuredDataDefDumper& dumper, int enumIndex, const StructuredDataEnum* _enum); + static size_t GetPropertySizeInBits(const StructuredDataStructProperty& property, const StructuredDataDef* def); + static size_t GetPropertyAlign(const StructuredDataStructProperty& property); static void DumpProperty(StructuredDataDefDumper& dumper, const StructuredDataStructProperty& property, const StructuredDataDef* def, int rootStructIndex); static void DumpStruct(StructuredDataDefDumper& dumper, size_t structIndex, const StructuredDataStruct* _struct, const StructuredDataDef* def, int rootStructIndex);