From b5e18e6b22c436407e2f07e838cb12fc4d70c4b2 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 20 Mar 2022 16:01:29 +0100 Subject: [PATCH] Calculate checksums for structured data def --- .../CommonStructuredDataDef.cpp | 11 ++- .../CommonStructuredDataDef.h | 3 +- .../CommonStructuredDataEnum.cpp | 23 +++++ .../CommonStructuredDataEnum.h | 1 + .../CommonStructuredDataStruct.cpp | 83 +++++++++++++++++++ .../CommonStructuredDataStruct.h | 4 + .../AssetDumperStructuredDataDefSet.cpp | 6 +- 7 files changed, 126 insertions(+), 5 deletions(-) diff --git a/src/ObjCommon/StructuredDataDef/CommonStructuredDataDef.cpp b/src/ObjCommon/StructuredDataDef/CommonStructuredDataDef.cpp index f7ba4c89..5aad0732 100644 --- a/src/ObjCommon/StructuredDataDef/CommonStructuredDataDef.cpp +++ b/src/ObjCommon/StructuredDataDef/CommonStructuredDataDef.cpp @@ -12,8 +12,13 @@ CommonStructuredDataDef::CommonStructuredDataDef(const int version) { } -size_t CommonStructuredDataDef::CalculateChecksum() const +uint32_t CommonStructuredDataDef::CalculateChecksum() const { - // TODO: Implement - return 0u; + auto checksum = 0u; + for (const auto& _enum : m_enums) + checksum = _enum->CalculateChecksum(checksum); + for (const auto& _struct : m_structs) + checksum = _struct->CalculateChecksum(*this, checksum); + + return checksum; } diff --git a/src/ObjCommon/StructuredDataDef/CommonStructuredDataDef.h b/src/ObjCommon/StructuredDataDef/CommonStructuredDataDef.h index 2f762a79..ff16ef80 100644 --- a/src/ObjCommon/StructuredDataDef/CommonStructuredDataDef.h +++ b/src/ObjCommon/StructuredDataDef/CommonStructuredDataDef.h @@ -3,6 +3,7 @@ #include #include +#include "Utils/ClassUtils.h" #include "CommonStructuredDataEnum.h" #include "CommonStructuredDataStruct.h" @@ -22,5 +23,5 @@ public: CommonStructuredDataDef(); explicit CommonStructuredDataDef(int version); - size_t CalculateChecksum() const; + _NODISCARD uint32_t CalculateChecksum() const; }; diff --git a/src/ObjCommon/StructuredDataDef/CommonStructuredDataEnum.cpp b/src/ObjCommon/StructuredDataDef/CommonStructuredDataEnum.cpp index f0f29161..15c79971 100644 --- a/src/ObjCommon/StructuredDataDef/CommonStructuredDataEnum.cpp +++ b/src/ObjCommon/StructuredDataDef/CommonStructuredDataEnum.cpp @@ -1,6 +1,9 @@ #include "CommonStructuredDataEnum.h" #include +#include + +#include "Utils/Endianness.h" CommonStructuredDataEnumEntry::CommonStructuredDataEnumEntry() : m_value(0u) @@ -35,6 +38,26 @@ size_t CommonStructuredDataEnum::ElementCount() const return m_reserved_entry_count > 0 ? static_cast(m_reserved_entry_count) : m_entries.size(); } +uint32_t CommonStructuredDataEnum::CalculateChecksum(const uint32_t initialValue) const +{ + auto checksum = initialValue; + + checksum = crc32(checksum, reinterpret_cast(m_name.c_str()), m_name.size() + 1); + + const auto littleEndianElementCount = endianness::ToLittleEndian(ElementCount()); + checksum = crc32(checksum, reinterpret_cast(&littleEndianElementCount), sizeof(littleEndianElementCount)); + + for(const auto& entry : m_entries) + { + checksum = crc32(checksum, reinterpret_cast(entry.m_name.c_str()), entry.m_name.size() + 1); + + const auto littleEndianValue = endianness::ToLittleEndian(entry.m_value); + checksum = crc32(checksum, reinterpret_cast(&littleEndianValue), sizeof(littleEndianValue)); + } + + return checksum; +} + void CommonStructuredDataEnum::SortEntries() { std::sort(m_entries.begin(), m_entries.end(), [](const CommonStructuredDataEnumEntry& e1, const CommonStructuredDataEnumEntry& e2) diff --git a/src/ObjCommon/StructuredDataDef/CommonStructuredDataEnum.h b/src/ObjCommon/StructuredDataDef/CommonStructuredDataEnum.h index 93200ce5..09fd65a4 100644 --- a/src/ObjCommon/StructuredDataDef/CommonStructuredDataEnum.h +++ b/src/ObjCommon/StructuredDataDef/CommonStructuredDataEnum.h @@ -25,6 +25,7 @@ struct CommonStructuredDataEnum CommonStructuredDataEnum(std::string name, int reservedEntryCount); _NODISCARD size_t ElementCount() const; + _NODISCARD uint32_t CalculateChecksum(uint32_t initialValue) const; void SortEntries(); }; diff --git a/src/ObjCommon/StructuredDataDef/CommonStructuredDataStruct.cpp b/src/ObjCommon/StructuredDataDef/CommonStructuredDataStruct.cpp index d61d9b1c..1bfd46b8 100644 --- a/src/ObjCommon/StructuredDataDef/CommonStructuredDataStruct.cpp +++ b/src/ObjCommon/StructuredDataDef/CommonStructuredDataStruct.cpp @@ -1,6 +1,10 @@ #include "CommonStructuredDataStruct.h" #include +#include + +#include "CommonStructuredDataDef.h" +#include "Utils/Endianness.h" CommonStructuredDataStructEntry::CommonStructuredDataStructEntry() : m_offset_in_bits(0u) @@ -33,6 +37,85 @@ CommonStructuredDataStruct::CommonStructuredDataStruct(std::string name) { } +uint32_t CommonStructuredDataStruct::CalculateChecksum(const CommonStructuredDataDef& def, const uint32_t initialValue) const +{ + auto checksum = initialValue; + + checksum = crc32(checksum, reinterpret_cast(m_name.c_str()), m_name.size() + 1); + for (const auto& property : m_properties) + { + checksum = crc32(checksum, reinterpret_cast(property.m_name.c_str()), property.m_name.size() + 1); + + const auto littleEndianOffset = endianness::ToLittleEndian(property.m_offset_in_bits); + checksum = crc32(checksum, reinterpret_cast(&littleEndianOffset), sizeof(littleEndianOffset)); + + auto currentType = property.m_type; + while (currentType.m_category != CommonStructuredDataTypeCategory::UNKNOWN) + { + const auto categoryByte = static_cast(currentType.m_category); + checksum = crc32(checksum, &categoryByte, sizeof(categoryByte)); + + switch (currentType.m_category) + { + case CommonStructuredDataTypeCategory::STRING: + { + const auto littleEndianStringLength = endianness::ToLittleEndian(currentType.m_info.string_length); + checksum = crc32(checksum, reinterpret_cast(&littleEndianStringLength), sizeof(littleEndianStringLength)); + currentType = CommonStructuredDataType(CommonStructuredDataTypeCategory::UNKNOWN); + } + break; + case CommonStructuredDataTypeCategory::ENUM: + if (currentType.m_info.type_index < def.m_enums.size()) + { + const auto& _enum = *def.m_enums[currentType.m_info.type_index]; + checksum = crc32(checksum, reinterpret_cast(_enum.m_name.c_str()), _enum.m_name.size() + 1); + currentType = CommonStructuredDataType(CommonStructuredDataTypeCategory::UNKNOWN); + } + break; + case CommonStructuredDataTypeCategory::STRUCT: + if (currentType.m_info.type_index < def.m_structs.size()) + { + const auto& _struct = *def.m_structs[currentType.m_info.type_index]; + checksum = crc32(checksum, reinterpret_cast(_struct.m_name.c_str()), _struct.m_name.size() + 1); + currentType = CommonStructuredDataType(CommonStructuredDataTypeCategory::UNKNOWN); + } + break; + case CommonStructuredDataTypeCategory::INDEXED_ARRAY: + if (currentType.m_info.type_index < def.m_indexed_arrays.size()) + { + const auto& indexedArray = def.m_indexed_arrays[currentType.m_info.type_index]; + const auto littleEndianElementCount = endianness::ToLittleEndian(indexedArray.m_element_count); + checksum = crc32(checksum, reinterpret_cast(&littleEndianElementCount), sizeof(littleEndianElementCount)); + currentType = indexedArray.m_array_type; + } + else + currentType = CommonStructuredDataType(CommonStructuredDataTypeCategory::UNKNOWN); + break; + case CommonStructuredDataTypeCategory::ENUM_ARRAY: + if (currentType.m_info.type_index < def.m_enumed_arrays.size()) + { + const auto& enumedArray = def.m_enumed_arrays[currentType.m_info.type_index]; + + if(enumedArray.m_enum_index < def.m_enums.size()) + { + const auto& _enum = *def.m_enums[enumedArray.m_enum_index]; + checksum = crc32(checksum, reinterpret_cast(_enum.m_name.c_str()), _enum.m_name.size() + 1); + } + currentType = enumedArray.m_array_type; + } + else + currentType = CommonStructuredDataType(CommonStructuredDataTypeCategory::UNKNOWN); + break; + default: + currentType = CommonStructuredDataType(CommonStructuredDataTypeCategory::UNKNOWN); + break; + } + } + } + + return checksum; +} + void CommonStructuredDataStruct::SortProperties() { std::sort(m_properties.begin(), m_properties.end(), [](const CommonStructuredDataStructEntry& e1, const CommonStructuredDataStructEntry& e2) diff --git a/src/ObjCommon/StructuredDataDef/CommonStructuredDataStruct.h b/src/ObjCommon/StructuredDataDef/CommonStructuredDataStruct.h index bbfc1c80..a9ae33f3 100644 --- a/src/ObjCommon/StructuredDataDef/CommonStructuredDataStruct.h +++ b/src/ObjCommon/StructuredDataDef/CommonStructuredDataStruct.h @@ -3,6 +3,7 @@ #include #include +#include "Utils/ClassUtils.h" #include "CommonStructuredDataTypes.h" struct CommonStructuredDataStructEntry @@ -16,6 +17,7 @@ struct CommonStructuredDataStructEntry CommonStructuredDataStructEntry(std::string name, CommonStructuredDataType type, size_t offsetInBits); }; +class CommonStructuredDataDef; struct CommonStructuredDataStruct { std::string m_name; @@ -26,5 +28,7 @@ struct CommonStructuredDataStruct CommonStructuredDataStruct(); explicit CommonStructuredDataStruct(std::string name); + _NODISCARD uint32_t CalculateChecksum(const CommonStructuredDataDef& def, uint32_t initialValue) const; + void SortProperties(); }; diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.cpp index 1c068388..944ee225 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.cpp +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.cpp @@ -401,7 +401,11 @@ CommonStructuredDataType AssetDumperStructuredDataDefSet::ConvertType(const Comm void AssetDumperStructuredDataDefSet::ConvertEnum(CommonStructuredDataEnum* out, const StructuredDataEnum* in, const size_t enumIndex) { out->m_name = "ENUM_" + std::to_string(enumIndex); - out->m_reserved_entry_count = std::max(in->reservedEntryCount, 0); + + if (in->reservedEntryCount > 0 && in->reservedEntryCount != in->entryCount) + out->m_reserved_entry_count = std::max(in->reservedEntryCount, 0); + else + out->m_reserved_entry_count = -1; out->m_entries.resize(static_cast(std::max(in->entryCount, 0))); for(auto i = 0u; i < out->m_entries.size(); i++)