Propagate unknown UUID-based map items in map tools

Adapt the `CDataFileReader::GetItem` function so it optionally also returns a `CUuid` for UUID-based map items, including for items with unknown UUIDs where the item type will be `-1`. Adapt the `CDataFileWriter::AddItem` function so it optionally also accepts a `CUuid` which will be used if the item type is `-1`.

The additional checks for invalid map item types in the map tools are removed again and instead the new UUID parameters are used so map items with unknown UUIDs are written back to maps correctly.

Closes #7701.
This commit is contained in:
Robert Müller 2023-12-29 16:27:25 +01:00
parent fe87fe6a3f
commit 999119c60f
8 changed files with 81 additions and 46 deletions

View file

@ -450,20 +450,27 @@ int CDataFileReader::GetItemSize(int Index) const
return m_pDataFile->m_Info.m_pItemOffsets[Index + 1] - m_pDataFile->m_Info.m_pItemOffsets[Index] - sizeof(CDatafileItem); return m_pDataFile->m_Info.m_pItemOffsets[Index + 1] - m_pDataFile->m_Info.m_pItemOffsets[Index] - sizeof(CDatafileItem);
} }
int CDataFileReader::GetExternalItemType(int InternalType) int CDataFileReader::GetExternalItemType(int InternalType, CUuid *pUuid)
{ {
if(InternalType <= OFFSET_UUID_TYPE || InternalType == ITEMTYPE_EX) if(InternalType <= OFFSET_UUID_TYPE || InternalType == ITEMTYPE_EX)
{ {
if(pUuid)
*pUuid = UUID_ZEROED;
return InternalType; return InternalType;
} }
int TypeIndex = FindItemIndex(ITEMTYPE_EX, InternalType); int TypeIndex = FindItemIndex(ITEMTYPE_EX, InternalType);
if(TypeIndex < 0 || GetItemSize(TypeIndex) < (int)sizeof(CItemEx)) if(TypeIndex < 0 || GetItemSize(TypeIndex) < (int)sizeof(CItemEx))
{ {
if(pUuid)
*pUuid = UUID_ZEROED;
return InternalType; return InternalType;
} }
const CItemEx *pItemEx = (const CItemEx *)GetItem(TypeIndex); const CItemEx *pItemEx = (const CItemEx *)GetItem(TypeIndex);
CUuid Uuid = pItemEx->ToUuid();
if(pUuid)
*pUuid = Uuid;
// Propagate UUID_UNKNOWN, it doesn't hurt. // Propagate UUID_UNKNOWN, it doesn't hurt.
return g_UuidManager.LookupUuid(pItemEx->ToUuid()); return g_UuidManager.LookupUuid(Uuid);
} }
int CDataFileReader::GetInternalItemType(int ExternalType) int CDataFileReader::GetInternalItemType(int ExternalType)
@ -490,7 +497,7 @@ int CDataFileReader::GetInternalItemType(int ExternalType)
return -1; return -1;
} }
void *CDataFileReader::GetItem(int Index, int *pType, int *pID) void *CDataFileReader::GetItem(int Index, int *pType, int *pID, CUuid *pUuid)
{ {
if(!m_pDataFile) if(!m_pDataFile)
{ {
@ -498,14 +505,18 @@ void *CDataFileReader::GetItem(int Index, int *pType, int *pID)
*pType = 0; *pType = 0;
if(pID) if(pID)
*pID = 0; *pID = 0;
if(pUuid)
*pUuid = UUID_ZEROED;
return nullptr; return nullptr;
} }
CDatafileItem *pItem = (CDatafileItem *)(m_pDataFile->m_Info.m_pItemStart + m_pDataFile->m_Info.m_pItemOffsets[Index]); CDatafileItem *pItem = (CDatafileItem *)(m_pDataFile->m_Info.m_pItemStart + m_pDataFile->m_Info.m_pItemOffsets[Index]);
// remove sign extension
const int Type = GetExternalItemType((pItem->m_TypeAndID >> 16) & 0xffff, pUuid);
if(pType) if(pType)
{ {
// remove sign extension *pType = Type;
*pType = GetExternalItemType((pItem->m_TypeAndID >> 16) & 0xffff);
} }
if(pID) if(pID)
{ {
@ -643,35 +654,51 @@ int CDataFileWriter::GetTypeFromIndex(int Index) const
return ITEMTYPE_EX - Index - 1; return ITEMTYPE_EX - Index - 1;
} }
int CDataFileWriter::GetExtendedItemTypeIndex(int Type) int CDataFileWriter::GetExtendedItemTypeIndex(int Type, const CUuid *pUuid)
{ {
int Index = 0; int Index = 0;
for(int ExtendedItemType : m_vExtendedItemTypes) if(Type == -1)
{ {
if(ExtendedItemType == Type) // Unknown type, search for UUID
return Index; for(const auto &ExtendedItemType : m_vExtendedItemTypes)
++Index; {
if(ExtendedItemType.m_Uuid == *pUuid)
return Index;
++Index;
}
}
else
{
for(const auto &ExtendedItemType : m_vExtendedItemTypes)
{
if(ExtendedItemType.m_Type == Type)
return Index;
++Index;
}
} }
// Type not found, add it. // Type not found, add it.
m_vExtendedItemTypes.push_back(Type); CExtendedItemType ExtendedType;
ExtendedType.m_Type = Type;
ExtendedType.m_Uuid = Type == -1 ? *pUuid : g_UuidManager.GetUuid(Type);
m_vExtendedItemTypes.push_back(ExtendedType);
CItemEx ExtendedType = CItemEx::FromUuid(g_UuidManager.GetUuid(Type)); CItemEx ItemEx = CItemEx::FromUuid(ExtendedType.m_Uuid);
AddItem(ITEMTYPE_EX, GetTypeFromIndex(Index), sizeof(ExtendedType), &ExtendedType); AddItem(ITEMTYPE_EX, GetTypeFromIndex(Index), sizeof(ItemEx), &ItemEx);
return Index; return Index;
} }
int CDataFileWriter::AddItem(int Type, int ID, size_t Size, const void *pData) int CDataFileWriter::AddItem(int Type, int ID, size_t Size, const void *pData, const CUuid *pUuid)
{ {
dbg_assert((Type >= 0 && Type < MAX_ITEM_TYPES) || Type >= OFFSET_UUID, "Invalid type"); dbg_assert((Type >= 0 && Type < MAX_ITEM_TYPES) || Type >= OFFSET_UUID || (Type == -1 && pUuid != nullptr), "Invalid type");
dbg_assert(ID >= 0 && ID <= ITEMTYPE_EX, "Invalid ID"); dbg_assert(ID >= 0 && ID <= ITEMTYPE_EX, "Invalid ID");
dbg_assert(Size == 0 || pData != nullptr, "Data missing"); // Items without data are allowed dbg_assert(Size == 0 || pData != nullptr, "Data missing"); // Items without data are allowed
dbg_assert(Size <= (size_t)std::numeric_limits<int>::max(), "Data too large"); dbg_assert(Size <= (size_t)std::numeric_limits<int>::max(), "Data too large");
dbg_assert(Size % sizeof(int) == 0, "Invalid data boundary"); dbg_assert(Size % sizeof(int) == 0, "Invalid data boundary");
if(Type >= OFFSET_UUID) if(Type == -1 || Type >= OFFSET_UUID)
{ {
Type = GetTypeFromIndex(GetExtendedItemTypeIndex(Type)); Type = GetTypeFromIndex(GetExtendedItemTypeIndex(Type, pUuid));
} }
const int NumItems = m_vItems.size(); const int NumItems = m_vItems.size();

View file

@ -8,6 +8,8 @@
#include <base/hash.h> #include <base/hash.h>
#include <base/types.h> #include <base/types.h>
#include "uuid_manager.h"
#include <array> #include <array>
#include <vector> #include <vector>
@ -25,7 +27,7 @@ class CDataFileReader
void *GetDataImpl(int Index, bool Swap); void *GetDataImpl(int Index, bool Swap);
int GetFileDataSize(int Index) const; int GetFileDataSize(int Index) const;
int GetExternalItemType(int InternalType); int GetExternalItemType(int InternalType, CUuid *pUuid);
int GetInternalItemType(int ExternalType); int GetInternalItemType(int ExternalType);
public: public:
@ -54,7 +56,7 @@ public:
int NumData() const; int NumData() const;
int GetItemSize(int Index) const; int GetItemSize(int Index) const;
void *GetItem(int Index, int *pType = nullptr, int *pID = nullptr); void *GetItem(int Index, int *pType = nullptr, int *pID = nullptr, CUuid *pUuid = nullptr);
void GetType(int Type, int *pStart, int *pNum); void GetType(int Type, int *pStart, int *pNum);
int FindItemIndex(int Type, int ID); int FindItemIndex(int Type, int ID);
void *FindItem(int Type, int ID); void *FindItem(int Type, int ID);
@ -94,6 +96,12 @@ class CDataFileWriter
int m_Last; int m_Last;
}; };
struct CExtendedItemType
{
int m_Type;
CUuid m_Uuid;
};
enum enum
{ {
MAX_ITEM_TYPES = 0x10000, MAX_ITEM_TYPES = 0x10000,
@ -103,10 +111,10 @@ class CDataFileWriter
std::array<CItemTypeInfo, MAX_ITEM_TYPES> m_aItemTypes; std::array<CItemTypeInfo, MAX_ITEM_TYPES> m_aItemTypes;
std::vector<CItemInfo> m_vItems; std::vector<CItemInfo> m_vItems;
std::vector<CDataInfo> m_vDatas; std::vector<CDataInfo> m_vDatas;
std::vector<int> m_vExtendedItemTypes; std::vector<CExtendedItemType> m_vExtendedItemTypes;
int GetTypeFromIndex(int Index) const; int GetTypeFromIndex(int Index) const;
int GetExtendedItemTypeIndex(int Type); int GetExtendedItemTypeIndex(int Type, const CUuid *pUuid);
public: public:
CDataFileWriter(); CDataFileWriter();
@ -122,7 +130,7 @@ public:
~CDataFileWriter(); ~CDataFileWriter();
bool Open(class IStorage *pStorage, const char *pFilename, int StorageType = IStorage::TYPE_SAVE); bool Open(class IStorage *pStorage, const char *pFilename, int StorageType = IStorage::TYPE_SAVE);
int AddItem(int Type, int ID, size_t Size, const void *pData); int AddItem(int Type, int ID, size_t Size, const void *pData, const CUuid *pUuid = nullptr);
int AddData(size_t Size, const void *pData, int CompressionLevel = Z_DEFAULT_COMPRESSION); int AddData(size_t Size, const void *pData, int CompressionLevel = Z_DEFAULT_COMPRESSION);
int AddDataSwapped(size_t Size, const void *pData); int AddDataSwapped(size_t Size, const void *pData);
int AddDataString(const char *pStr); int AddDataString(const char *pStr);

View file

@ -218,11 +218,11 @@ int main(int argc, const char **argv)
for(int Index = 0; Index < g_DataReader.NumItems(); Index++) for(int Index = 0; Index < g_DataReader.NumItems(); Index++)
{ {
int Type, ID; int Type, ID;
void *pItem = g_DataReader.GetItem(Index, &Type, &ID); CUuid Uuid;
void *pItem = g_DataReader.GetItem(Index, &Type, &ID, &Uuid);
// Filter items with unknown type, as we can't write them back.
// Filter ITEMTYPE_EX items, they will be automatically added again. // Filter ITEMTYPE_EX items, they will be automatically added again.
if(Type < 0 || Type == ITEMTYPE_EX) if(Type == ITEMTYPE_EX)
{ {
continue; continue;
} }
@ -239,7 +239,7 @@ int main(int argc, const char **argv)
Size = sizeof(CMapItemImage); Size = sizeof(CMapItemImage);
NewImageItem.m_Version = CMapItemImage::CURRENT_VERSION; NewImageItem.m_Version = CMapItemImage::CURRENT_VERSION;
} }
g_DataWriter.AddItem(Type, ID, Size, pItem); g_DataWriter.AddItem(Type, ID, Size, pItem, &Uuid);
} }
// add all data // add all data

View file

@ -375,11 +375,11 @@ void SaveOutputMap(CDataFileReader &InputMap, CDataFileWriter &OutputMap, CMapIt
for(int i = 0; i < InputMap.NumItems(); i++) for(int i = 0; i < InputMap.NumItems(); i++)
{ {
int ID, Type; int ID, Type;
void *pItem = InputMap.GetItem(i, &Type, &ID); CUuid Uuid;
void *pItem = InputMap.GetItem(i, &Type, &ID, &Uuid);
// Filter items with unknown type, as we can't write them back.
// Filter ITEMTYPE_EX items, they will be automatically added again. // Filter ITEMTYPE_EX items, they will be automatically added again.
if(Type < 0 || Type == ITEMTYPE_EX) if(Type == ITEMTYPE_EX)
{ {
continue; continue;
} }
@ -388,7 +388,7 @@ void SaveOutputMap(CDataFileReader &InputMap, CDataFileWriter &OutputMap, CMapIt
pItem = pNewItem; pItem = pNewItem;
int Size = InputMap.GetItemSize(i); int Size = InputMap.GetItemSize(i);
OutputMap.AddItem(Type, ID, Size, pItem); OutputMap.AddItem(Type, ID, Size, pItem, &Uuid);
} }
for(int i = 0; i < InputMap.NumData(); i++) for(int i = 0; i < InputMap.NumData(); i++)

View file

@ -139,11 +139,11 @@ int main(int argc, const char **argv)
for(int Index = 0, i = 0; Index < Reader.NumItems(); Index++) for(int Index = 0, i = 0; Index < Reader.NumItems(); Index++)
{ {
int Type, ID; int Type, ID;
void *pPtr = Reader.GetItem(Index, &Type, &ID); CUuid Uuid;
void *pPtr = Reader.GetItem(Index, &Type, &ID, &Uuid);
// Filter items with unknown type, as we can't write them back.
// Filter ITEMTYPE_EX items, they will be automatically added again. // Filter ITEMTYPE_EX items, they will be automatically added again.
if(Type < 0 || Type == ITEMTYPE_EX) if(Type == ITEMTYPE_EX)
{ {
continue; continue;
} }
@ -205,7 +205,7 @@ int main(int argc, const char **argv)
} }
int Size = Reader.GetItemSize(Index); int Size = Reader.GetItemSize(Index);
Writer.AddItem(Type, ID, Size, pPtr); Writer.AddItem(Type, ID, Size, pPtr, &Uuid);
} }
// add all data // add all data

View file

@ -166,11 +166,11 @@ void SaveOutputMap(CDataFileReader &InputMap, CDataFileWriter &OutputMap)
for(int i = 0; i < InputMap.NumItems(); i++) for(int i = 0; i < InputMap.NumItems(); i++)
{ {
int ID, Type; int ID, Type;
void *pItem = InputMap.GetItem(i, &Type, &ID); CUuid Uuid;
void *pItem = InputMap.GetItem(i, &Type, &ID, &Uuid);
// Filter items with unknown type, as we can't write them back.
// Filter ITEMTYPE_EX items, they will be automatically added again. // Filter ITEMTYPE_EX items, they will be automatically added again.
if(Type < 0 || Type == ITEMTYPE_EX) if(Type == ITEMTYPE_EX)
{ {
continue; continue;
} }
@ -179,7 +179,7 @@ void SaveOutputMap(CDataFileReader &InputMap, CDataFileWriter &OutputMap)
pItem = g_apNewItem[i]; pItem = g_apNewItem[i];
int Size = InputMap.GetItemSize(i); int Size = InputMap.GetItemSize(i);
OutputMap.AddItem(Type, ID, Size, pItem); OutputMap.AddItem(Type, ID, Size, pItem, &Uuid);
} }
for(int i = 0; i < InputMap.NumData(); i++) for(int i = 0; i < InputMap.NumData(); i++)

View file

@ -148,11 +148,11 @@ int main(int argc, const char **argv)
for(int Index = 0; Index < g_DataReader.NumItems(); Index++) for(int Index = 0; Index < g_DataReader.NumItems(); Index++)
{ {
int Type, ID; int Type, ID;
void *pItem = g_DataReader.GetItem(Index, &Type, &ID); CUuid Uuid;
void *pItem = g_DataReader.GetItem(Index, &Type, &ID, &Uuid);
// Filter items with unknown type, as we can't write them back.
// Filter ITEMTYPE_EX items, they will be automatically added again. // Filter ITEMTYPE_EX items, they will be automatically added again.
if(Type < 0 || Type == ITEMTYPE_EX) if(Type == ITEMTYPE_EX)
{ {
continue; continue;
} }
@ -169,7 +169,7 @@ int main(int argc, const char **argv)
NewImageItem.m_Version = CMapItemImage::CURRENT_VERSION; NewImageItem.m_Version = CMapItemImage::CURRENT_VERSION;
} }
Writer.AddItem(Type, ID, Size, pItem); Writer.AddItem(Type, ID, Size, pItem, &Uuid);
} }
if(g_NewDataID == -1) if(g_NewDataID == -1)

View file

@ -30,17 +30,17 @@ static int ResaveMap(const char *pSourceMap, const char *pDestinationMap, IStora
for(int Index = 0; Index < Reader.NumItems(); Index++) for(int Index = 0; Index < Reader.NumItems(); Index++)
{ {
int Type, ID; int Type, ID;
const void *pPtr = Reader.GetItem(Index, &Type, &ID); CUuid Uuid;
const void *pPtr = Reader.GetItem(Index, &Type, &ID, &Uuid);
// Filter items with unknown type, as we can't write them back.
// Filter ITEMTYPE_EX items, they will be automatically added again. // Filter ITEMTYPE_EX items, they will be automatically added again.
if(Type < 0 || Type == ITEMTYPE_EX) if(Type == ITEMTYPE_EX)
{ {
continue; continue;
} }
int Size = Reader.GetItemSize(Index); int Size = Reader.GetItemSize(Index);
Writer.AddItem(Type, ID, Size, pPtr); Writer.AddItem(Type, ID, Size, pPtr, &Uuid);
} }
// add all data // add all data