mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-21 08:35:43 +00:00
Dump structured data def structs in correct order and sort entries by offset
This commit is contained in:
parent
944586fcde
commit
51003e5f6d
@ -1,12 +1,22 @@
|
|||||||
#include "StructuredDataDefDumper.h"
|
#include "StructuredDataDefDumper.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
StructuredDataDefDumper::StructEntry::StructEntry(std::string stringValue, const size_t offset)
|
||||||
|
: m_string_value(std::move(stringValue)),
|
||||||
|
m_offset(offset)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
StructuredDataDefDumper::StructuredDataDefDumper(std::ostream& stream)
|
StructuredDataDefDumper::StructuredDataDefDumper(std::ostream& stream)
|
||||||
: AbstractTextDumper(stream),
|
: AbstractTextDumper(stream),
|
||||||
m_block(Block::BLOCK_NONE),
|
m_block(Block::BLOCK_NONE),
|
||||||
m_flags{},
|
m_flags{},
|
||||||
m_enum_size(0u)
|
m_enum_entry_count(0u),
|
||||||
|
m_struct_property_count(0u),
|
||||||
|
m_current_property_offset(0u)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +74,7 @@ void StructuredDataDefDumper::BeginEnum(const std::string& enumName, const size_
|
|||||||
m_block = Block::BLOCK_ENUM;
|
m_block = Block::BLOCK_ENUM;
|
||||||
|
|
||||||
m_enum_entries.resize(enumEntryCount);
|
m_enum_entries.resize(enumEntryCount);
|
||||||
m_enum_size = enumEntryCount;
|
m_enum_entry_count = enumEntryCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StructuredDataDefDumper::EndEnum()
|
void StructuredDataDefDumper::EndEnum()
|
||||||
@ -100,15 +110,15 @@ void StructuredDataDefDumper::EndEnum()
|
|||||||
void StructuredDataDefDumper::WriteEnumEntry(const std::string& entryName, const size_t entryValue)
|
void StructuredDataDefDumper::WriteEnumEntry(const std::string& entryName, const size_t entryValue)
|
||||||
{
|
{
|
||||||
assert(m_block == Block::BLOCK_ENUM);
|
assert(m_block == Block::BLOCK_ENUM);
|
||||||
assert(entryValue < m_enum_size);
|
assert(entryValue < m_enum_entry_count);
|
||||||
|
|
||||||
if (m_block != Block::BLOCK_ENUM || entryValue >= m_enum_size)
|
if (m_block != Block::BLOCK_ENUM || entryValue >= m_enum_entry_count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_enum_entries[entryValue] = entryName;
|
m_enum_entries[entryValue] = entryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StructuredDataDefDumper::BeginStruct(const std::string& structName)
|
void StructuredDataDefDumper::BeginStruct(const std::string& structName, const size_t structPropertyCount)
|
||||||
{
|
{
|
||||||
assert(m_flags.m_in_version);
|
assert(m_flags.m_in_version);
|
||||||
assert(m_block == Block::BLOCK_NONE);
|
assert(m_block == Block::BLOCK_NONE);
|
||||||
@ -116,6 +126,9 @@ void StructuredDataDefDumper::BeginStruct(const std::string& structName)
|
|||||||
if (m_block != Block::BLOCK_NONE)
|
if (m_block != Block::BLOCK_NONE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
m_struct_property_count = structPropertyCount;
|
||||||
|
m_struct_properties.reserve(structPropertyCount);
|
||||||
|
|
||||||
if (m_flags.m_empty_line_before_block)
|
if (m_flags.m_empty_line_before_block)
|
||||||
m_stream << "\n";
|
m_stream << "\n";
|
||||||
|
|
||||||
@ -136,14 +149,27 @@ void StructuredDataDefDumper::EndStruct()
|
|||||||
if (m_block != Block::BLOCK_STRUCT)
|
if (m_block != Block::BLOCK_STRUCT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
std::sort(m_struct_properties.begin(), m_struct_properties.end(), [](const StructEntry& e1, const StructEntry& e2)
|
||||||
|
{
|
||||||
|
return e1.m_offset < e2.m_offset;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (auto& structProperty : m_struct_properties)
|
||||||
|
{
|
||||||
|
Indent();
|
||||||
|
m_stream << structProperty.m_string_value << ";\n";
|
||||||
|
}
|
||||||
|
|
||||||
DecIndent();
|
DecIndent();
|
||||||
Indent();
|
Indent();
|
||||||
m_stream << "};\n";
|
m_stream << "};\n";
|
||||||
m_block = Block::BLOCK_NONE;
|
m_block = Block::BLOCK_NONE;
|
||||||
m_flags.m_empty_line_before_block = true;
|
m_flags.m_empty_line_before_block = true;
|
||||||
|
m_struct_properties.clear();
|
||||||
|
m_struct_property_count = 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StructuredDataDefDumper::BeginProperty(const std::string& propertyName)
|
void StructuredDataDefDumper::BeginProperty(const std::string& propertyName, const size_t propertyOffset)
|
||||||
{
|
{
|
||||||
assert(m_flags.m_in_version);
|
assert(m_flags.m_in_version);
|
||||||
assert(m_block == Block::BLOCK_STRUCT);
|
assert(m_block == Block::BLOCK_STRUCT);
|
||||||
@ -151,19 +177,20 @@ void StructuredDataDefDumper::BeginProperty(const std::string& propertyName)
|
|||||||
if (m_block != Block::BLOCK_STRUCT)
|
if (m_block != Block::BLOCK_STRUCT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_property_name = propertyName;
|
m_current_property_name = propertyName;
|
||||||
|
m_current_property_offset = propertyOffset;
|
||||||
|
|
||||||
m_block = Block::BLOCK_PROPERTY;
|
m_block = Block::BLOCK_PROPERTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StructuredDataDefDumper::AddPropertyArraySpecifier(const std::string& specifierName)
|
void StructuredDataDefDumper::AddPropertyArraySpecifier(const std::string& specifierName)
|
||||||
{
|
{
|
||||||
m_property_array_specifiers.emplace_back(specifierName);
|
m_current_property_array_specifiers.emplace_back(specifierName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StructuredDataDefDumper::SetPropertyTypeName(const std::string& typeName)
|
void StructuredDataDefDumper::SetPropertyTypeName(const std::string& typeName)
|
||||||
{
|
{
|
||||||
m_property_type_name = typeName;
|
m_current_property_type_name = typeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StructuredDataDefDumper::EndProperty()
|
void StructuredDataDefDumper::EndProperty()
|
||||||
@ -173,19 +200,19 @@ void StructuredDataDefDumper::EndProperty()
|
|||||||
if (m_block != Block::BLOCK_PROPERTY)
|
if (m_block != Block::BLOCK_PROPERTY)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Indent();
|
std::ostringstream ss;
|
||||||
|
ss << m_current_property_type_name << " " << m_current_property_name;
|
||||||
|
|
||||||
m_stream << m_property_type_name << " " << m_property_name;
|
for (const auto& arraySpecifierName : m_current_property_array_specifiers)
|
||||||
|
|
||||||
for(const auto& arraySpecifierName : m_property_array_specifiers)
|
|
||||||
{
|
{
|
||||||
m_stream << "[" << arraySpecifierName << "]";
|
ss << "[" << arraySpecifierName << "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
m_stream << ";\n";
|
m_struct_properties.emplace_back(ss.str(), m_current_property_offset);
|
||||||
|
|
||||||
m_block = Block::BLOCK_STRUCT;
|
m_block = Block::BLOCK_STRUCT;
|
||||||
m_property_array_specifiers.clear();
|
m_current_property_array_specifiers.clear();
|
||||||
m_property_name = std::string();
|
m_current_property_name = std::string();
|
||||||
m_property_type_name = std::string();
|
m_current_property_offset = 0u;
|
||||||
|
m_current_property_type_name = std::string();
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,14 @@
|
|||||||
|
|
||||||
class StructuredDataDefDumper : AbstractTextDumper
|
class StructuredDataDefDumper : AbstractTextDumper
|
||||||
{
|
{
|
||||||
|
struct StructEntry
|
||||||
|
{
|
||||||
|
std::string m_string_value;
|
||||||
|
size_t m_offset;
|
||||||
|
|
||||||
|
StructEntry(std::string stringValue, size_t offset);
|
||||||
|
};
|
||||||
|
|
||||||
enum class Block
|
enum class Block
|
||||||
{
|
{
|
||||||
BLOCK_NONE = 0,
|
BLOCK_NONE = 0,
|
||||||
@ -22,11 +30,14 @@ class StructuredDataDefDumper : AbstractTextDumper
|
|||||||
} m_flags;
|
} m_flags;
|
||||||
|
|
||||||
std::vector<std::string> m_enum_entries;
|
std::vector<std::string> m_enum_entries;
|
||||||
size_t m_enum_size;
|
size_t m_enum_entry_count;
|
||||||
|
|
||||||
std::string m_property_name;
|
std::vector<StructEntry> m_struct_properties;
|
||||||
std::string m_property_type_name;
|
size_t m_struct_property_count;
|
||||||
std::vector<std::string> m_property_array_specifiers;
|
std::string m_current_property_name;
|
||||||
|
size_t m_current_property_offset;
|
||||||
|
std::string m_current_property_type_name;
|
||||||
|
std::vector<std::string> m_current_property_array_specifiers;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit StructuredDataDefDumper(std::ostream& stream);
|
explicit StructuredDataDefDumper(std::ostream& stream);
|
||||||
@ -38,9 +49,9 @@ public:
|
|||||||
void EndEnum();
|
void EndEnum();
|
||||||
void WriteEnumEntry(const std::string& entryName, size_t entryValue);
|
void WriteEnumEntry(const std::string& entryName, size_t entryValue);
|
||||||
|
|
||||||
void BeginStruct(const std::string& structName);
|
void BeginStruct(const std::string& structName, size_t structPropertyCount);
|
||||||
void EndStruct();
|
void EndStruct();
|
||||||
void BeginProperty(const std::string& propertyName);
|
void BeginProperty(const std::string& propertyName, size_t propertyOffset);
|
||||||
void AddPropertyArraySpecifier(const std::string& specifierName);
|
void AddPropertyArraySpecifier(const std::string& specifierName);
|
||||||
void SetPropertyTypeName(const std::string& typeName);
|
void SetPropertyTypeName(const std::string& typeName);
|
||||||
void EndProperty();
|
void EndProperty();
|
||||||
|
@ -7,6 +7,101 @@
|
|||||||
|
|
||||||
using namespace IW4;
|
using namespace IW4;
|
||||||
|
|
||||||
|
bool AssetDumperStructuredDataDefSet::GetNextHeadValue(const StructuredDataDef* def, const bool isFirstStruct, const std::vector<bool>& structsIncludedInOrder, size_t& nextHeadValue)
|
||||||
|
{
|
||||||
|
if(isFirstStruct
|
||||||
|
&& def->rootType.type == DATA_STRUCT
|
||||||
|
&& def->rootType.u.structIndex >= 0
|
||||||
|
&& def->rootType.u.structIndex < def->structCount)
|
||||||
|
{
|
||||||
|
nextHeadValue = def->rootType.u.structIndex;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto firstNotIncludedStruct = std::find(structsIncludedInOrder.begin(), structsIncludedInOrder.end(), false);
|
||||||
|
assert(firstNotIncludedStruct != structsIncludedInOrder.end());
|
||||||
|
|
||||||
|
if (firstNotIncludedStruct == structsIncludedInOrder.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
nextHeadValue = static_cast<size_t>(firstNotIncludedStruct - structsIncludedInOrder.begin());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
StructuredDataType AssetDumperStructuredDataDefSet::GetBaseType(const StructuredDataDef* def, StructuredDataType type)
|
||||||
|
{
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
if (type.type == DATA_INDEXED_ARRAY)
|
||||||
|
{
|
||||||
|
if (def->indexedArrays != nullptr && type.u.indexedArrayIndex >= 0 && type.u.indexedArrayIndex < def->indexedArrayCount)
|
||||||
|
type = def->indexedArrays[type.u.indexedArrayIndex].elementType;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (type.type == DATA_ENUM_ARRAY)
|
||||||
|
{
|
||||||
|
if (def->enumedArrays != nullptr && type.u.enumedArrayIndex >= 0 && type.u.enumedArrayIndex < def->enumedArrayCount)
|
||||||
|
type = def->enumedArrays[type.u.enumedArrayIndex].elementType;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<size_t> AssetDumperStructuredDataDefSet::CalculateStructDumpingOrder(const StructuredDataDef* def)
|
||||||
|
{
|
||||||
|
if (def->structCount <= 0 || def->structs == nullptr)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const auto structCount = static_cast<size_t>(def->structCount);
|
||||||
|
|
||||||
|
std::vector<size_t> result;
|
||||||
|
auto resultStructHead = 0u;
|
||||||
|
auto resultStructTail = 0u;
|
||||||
|
|
||||||
|
result.reserve(def->structCount);
|
||||||
|
std::vector<bool> structIncludedInOrder(def->structCount);
|
||||||
|
|
||||||
|
while(resultStructTail < structCount)
|
||||||
|
{
|
||||||
|
size_t nextHeadValue;
|
||||||
|
if (!GetNextHeadValue(def, resultStructHead == 0, structIncludedInOrder, nextHeadValue))
|
||||||
|
return result;
|
||||||
|
result.push_back(nextHeadValue);
|
||||||
|
structIncludedInOrder[nextHeadValue] = true;
|
||||||
|
++resultStructHead;
|
||||||
|
|
||||||
|
while(resultStructHead > resultStructTail)
|
||||||
|
{
|
||||||
|
const auto& currentStruct = def->structs[result[resultStructTail++]];
|
||||||
|
|
||||||
|
if(currentStruct.properties == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
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
|
||||||
|
&& static_cast<size_t>(baseType.u.structIndex) < structCount
|
||||||
|
&& structIncludedInOrder[static_cast<size_t>(baseType.u.structIndex)] == false)
|
||||||
|
{
|
||||||
|
result.push_back(static_cast<size_t>(baseType.u.structIndex));
|
||||||
|
structIncludedInOrder[static_cast<size_t>(baseType.u.structIndex)] = true;
|
||||||
|
++resultStructHead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool AssetDumperStructuredDataDefSet::ShouldDump(XAssetInfo<StructuredDataDefSet>* asset)
|
bool AssetDumperStructuredDataDefSet::ShouldDump(XAssetInfo<StructuredDataDefSet>* asset)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@ -38,7 +133,7 @@ void AssetDumperStructuredDataDefSet::DumpEnum(StructuredDataDefDumper& dumper,
|
|||||||
|
|
||||||
void AssetDumperStructuredDataDefSet::DumpProperty(StructuredDataDefDumper& dumper, const StructuredDataStructProperty& property, const StructuredDataDef* def, const int rootStructIndex)
|
void AssetDumperStructuredDataDefSet::DumpProperty(StructuredDataDefDumper& dumper, const StructuredDataStructProperty& property, const StructuredDataDef* def, const int rootStructIndex)
|
||||||
{
|
{
|
||||||
dumper.BeginProperty(property.name);
|
dumper.BeginProperty(property.name, property.offset);
|
||||||
|
|
||||||
auto currentType = property.type;
|
auto currentType = property.type;
|
||||||
auto stopTypeIteration = false;
|
auto stopTypeIteration = false;
|
||||||
@ -145,14 +240,13 @@ void AssetDumperStructuredDataDefSet::DumpProperty(StructuredDataDefDumper& dump
|
|||||||
dumper.EndProperty();
|
dumper.EndProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetDumperStructuredDataDefSet::DumpStruct(StructuredDataDefDumper& dumper, const int structIndex, const StructuredDataStruct* _struct, const StructuredDataDef* def, const bool isRoot)
|
void AssetDumperStructuredDataDefSet::DumpStruct(StructuredDataDefDumper& dumper, const size_t structIndex, const StructuredDataStruct* _struct, const StructuredDataDef* def, const int rootStructIndex)
|
||||||
{
|
{
|
||||||
if (!_struct->properties || _struct->propertyCount <= 0)
|
if (!_struct->properties || _struct->propertyCount <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string structName;
|
std::string structName;
|
||||||
|
if (static_cast<int>(structIndex) == rootStructIndex)
|
||||||
if (isRoot)
|
|
||||||
{
|
{
|
||||||
structName = "root";
|
structName = "root";
|
||||||
}
|
}
|
||||||
@ -163,9 +257,8 @@ void AssetDumperStructuredDataDefSet::DumpStruct(StructuredDataDefDumper& dumper
|
|||||||
structName = ss.str();
|
structName = ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
dumper.BeginStruct(structName);
|
dumper.BeginStruct(structName, static_cast<size_t>(_struct->propertyCount));
|
||||||
|
|
||||||
const auto rootStructIndex = def->rootType.type == DATA_STRUCT ? def->rootType.u.structIndex : -1;
|
|
||||||
for (auto i = 0; i < _struct->propertyCount; i++)
|
for (auto i = 0; i < _struct->propertyCount; i++)
|
||||||
{
|
{
|
||||||
const auto& property = _struct->properties[i];
|
const auto& property = _struct->properties[i];
|
||||||
@ -197,8 +290,9 @@ void AssetDumperStructuredDataDefSet::DumpAsset(AssetDumpingContext& context, XA
|
|||||||
|
|
||||||
const auto rootStructIndex = def.rootType.type == DATA_STRUCT ? def.rootType.u.structIndex : -1;
|
const auto rootStructIndex = def.rootType.type == DATA_STRUCT ? def.rootType.u.structIndex : -1;
|
||||||
assert(rootStructIndex >= 0);
|
assert(rootStructIndex >= 0);
|
||||||
for (auto structIndex = 0; structIndex < def.structCount; structIndex++)
|
const auto structDumpingOrder = CalculateStructDumpingOrder(&def);
|
||||||
DumpStruct(dumper, structIndex, &def.structs[structIndex], &def, structIndex == rootStructIndex);
|
for (auto i = structDumpingOrder.rbegin(); i != structDumpingOrder.rend(); ++i)
|
||||||
|
DumpStruct(dumper, *i, &def.structs[*i], &def, rootStructIndex);
|
||||||
|
|
||||||
dumper.EndVersion();
|
dumper.EndVersion();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "Dumping/AbstractAssetDumper.h"
|
#include "Dumping/AbstractAssetDumper.h"
|
||||||
#include "Dumping/StructuredDataDef/StructuredDataDefDumper.h"
|
#include "Dumping/StructuredDataDef/StructuredDataDefDumper.h"
|
||||||
#include "Game/IW4/IW4.h"
|
#include "Game/IW4/IW4.h"
|
||||||
@ -8,9 +11,12 @@ namespace IW4
|
|||||||
{
|
{
|
||||||
class AssetDumperStructuredDataDefSet final : public AbstractAssetDumper<StructuredDataDefSet>
|
class AssetDumperStructuredDataDefSet final : public AbstractAssetDumper<StructuredDataDefSet>
|
||||||
{
|
{
|
||||||
|
static bool GetNextHeadValue(const StructuredDataDef* def, bool isFirstStruct, const std::vector<bool>& structsIncludedInOrder, size_t& nextHeadValue);
|
||||||
|
static StructuredDataType GetBaseType(const StructuredDataDef* def, StructuredDataType type);
|
||||||
|
static std::vector<size_t> CalculateStructDumpingOrder(const StructuredDataDef* def);
|
||||||
static void DumpEnum(StructuredDataDefDumper& dumper, int enumIndex, const StructuredDataEnum* _enum);
|
static void DumpEnum(StructuredDataDefDumper& dumper, int enumIndex, const StructuredDataEnum* _enum);
|
||||||
static void DumpProperty(StructuredDataDefDumper& dumper, const StructuredDataStructProperty& property, const StructuredDataDef* def, int rootStructIndex);
|
static void DumpProperty(StructuredDataDefDumper& dumper, const StructuredDataStructProperty& property, const StructuredDataDef* def, int rootStructIndex);
|
||||||
static void DumpStruct(StructuredDataDefDumper& dumper, int structIndex, const StructuredDataStruct* _struct, const StructuredDataDef* def, bool isRoot);
|
static void DumpStruct(StructuredDataDefDumper& dumper, size_t structIndex, const StructuredDataStruct* _struct, const StructuredDataDef* def, int rootStructIndex);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool ShouldDump(XAssetInfo<StructuredDataDefSet>* asset) override;
|
bool ShouldDump(XAssetInfo<StructuredDataDefSet>* asset) override;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user