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);
}
int CDataFileReader::GetExternalItemType(int InternalType)
int CDataFileReader::GetExternalItemType(int InternalType, CUuid *pUuid)
{
if(InternalType <= OFFSET_UUID_TYPE || InternalType == ITEMTYPE_EX)
{
if(pUuid)
*pUuid = UUID_ZEROED;
return InternalType;
}
int TypeIndex = FindItemIndex(ITEMTYPE_EX, InternalType);
if(TypeIndex < 0 || GetItemSize(TypeIndex) < (int)sizeof(CItemEx))
{
if(pUuid)
*pUuid = UUID_ZEROED;
return InternalType;
}
const CItemEx *pItemEx = (const CItemEx *)GetItem(TypeIndex);
CUuid Uuid = pItemEx->ToUuid();
if(pUuid)
*pUuid = Uuid;
// Propagate UUID_UNKNOWN, it doesn't hurt.
return g_UuidManager.LookupUuid(pItemEx->ToUuid());
return g_UuidManager.LookupUuid(Uuid);
}
int CDataFileReader::GetInternalItemType(int ExternalType)
@ -490,7 +497,7 @@ int CDataFileReader::GetInternalItemType(int ExternalType)
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)
{
@ -498,14 +505,18 @@ void *CDataFileReader::GetItem(int Index, int *pType, int *pID)
*pType = 0;
if(pID)
*pID = 0;
if(pUuid)
*pUuid = UUID_ZEROED;
return nullptr;
}
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)
{
// remove sign extension
*pType = GetExternalItemType((pItem->m_TypeAndID >> 16) & 0xffff);
*pType = Type;
}
if(pID)
{
@ -643,35 +654,51 @@ int CDataFileWriter::GetTypeFromIndex(int Index) const
return ITEMTYPE_EX - Index - 1;
}
int CDataFileWriter::GetExtendedItemTypeIndex(int Type)
int CDataFileWriter::GetExtendedItemTypeIndex(int Type, const CUuid *pUuid)
{
int Index = 0;
for(int ExtendedItemType : m_vExtendedItemTypes)
if(Type == -1)
{
if(ExtendedItemType == Type)
return Index;
++Index;
// Unknown type, search for UUID
for(const auto &ExtendedItemType : m_vExtendedItemTypes)
{
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.
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));
AddItem(ITEMTYPE_EX, GetTypeFromIndex(Index), sizeof(ExtendedType), &ExtendedType);
CItemEx ItemEx = CItemEx::FromUuid(ExtendedType.m_Uuid);
AddItem(ITEMTYPE_EX, GetTypeFromIndex(Index), sizeof(ItemEx), &ItemEx);
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(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 % 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();

View file

@ -8,6 +8,8 @@
#include <base/hash.h>
#include <base/types.h>
#include "uuid_manager.h"
#include <array>
#include <vector>
@ -25,7 +27,7 @@ class CDataFileReader
void *GetDataImpl(int Index, bool Swap);
int GetFileDataSize(int Index) const;
int GetExternalItemType(int InternalType);
int GetExternalItemType(int InternalType, CUuid *pUuid);
int GetInternalItemType(int ExternalType);
public:
@ -54,7 +56,7 @@ public:
int NumData() 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);
int FindItemIndex(int Type, int ID);
void *FindItem(int Type, int ID);
@ -94,6 +96,12 @@ class CDataFileWriter
int m_Last;
};
struct CExtendedItemType
{
int m_Type;
CUuid m_Uuid;
};
enum
{
MAX_ITEM_TYPES = 0x10000,
@ -103,10 +111,10 @@ class CDataFileWriter
std::array<CItemTypeInfo, MAX_ITEM_TYPES> m_aItemTypes;
std::vector<CItemInfo> m_vItems;
std::vector<CDataInfo> m_vDatas;
std::vector<int> m_vExtendedItemTypes;
std::vector<CExtendedItemType> m_vExtendedItemTypes;
int GetTypeFromIndex(int Index) const;
int GetExtendedItemTypeIndex(int Type);
int GetExtendedItemTypeIndex(int Type, const CUuid *pUuid);
public:
CDataFileWriter();
@ -122,7 +130,7 @@ public:
~CDataFileWriter();
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 AddDataSwapped(size_t Size, const void *pData);
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++)
{
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.
if(Type < 0 || Type == ITEMTYPE_EX)
if(Type == ITEMTYPE_EX)
{
continue;
}
@ -239,7 +239,7 @@ int main(int argc, const char **argv)
Size = sizeof(CMapItemImage);
NewImageItem.m_Version = CMapItemImage::CURRENT_VERSION;
}
g_DataWriter.AddItem(Type, ID, Size, pItem);
g_DataWriter.AddItem(Type, ID, Size, pItem, &Uuid);
}
// add all data

View file

@ -375,11 +375,11 @@ void SaveOutputMap(CDataFileReader &InputMap, CDataFileWriter &OutputMap, CMapIt
for(int i = 0; i < InputMap.NumItems(); i++)
{
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.
if(Type < 0 || Type == ITEMTYPE_EX)
if(Type == ITEMTYPE_EX)
{
continue;
}
@ -388,7 +388,7 @@ void SaveOutputMap(CDataFileReader &InputMap, CDataFileWriter &OutputMap, CMapIt
pItem = pNewItem;
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++)

View file

@ -139,11 +139,11 @@ int main(int argc, const char **argv)
for(int Index = 0, i = 0; Index < Reader.NumItems(); Index++)
{
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.
if(Type < 0 || Type == ITEMTYPE_EX)
if(Type == ITEMTYPE_EX)
{
continue;
}
@ -205,7 +205,7 @@ int main(int argc, const char **argv)
}
int Size = Reader.GetItemSize(Index);
Writer.AddItem(Type, ID, Size, pPtr);
Writer.AddItem(Type, ID, Size, pPtr, &Uuid);
}
// add all data

View file

@ -166,11 +166,11 @@ void SaveOutputMap(CDataFileReader &InputMap, CDataFileWriter &OutputMap)
for(int i = 0; i < InputMap.NumItems(); i++)
{
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.
if(Type < 0 || Type == ITEMTYPE_EX)
if(Type == ITEMTYPE_EX)
{
continue;
}
@ -179,7 +179,7 @@ void SaveOutputMap(CDataFileReader &InputMap, CDataFileWriter &OutputMap)
pItem = g_apNewItem[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++)

View file

@ -148,11 +148,11 @@ int main(int argc, const char **argv)
for(int Index = 0; Index < g_DataReader.NumItems(); Index++)
{
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.
if(Type < 0 || Type == ITEMTYPE_EX)
if(Type == ITEMTYPE_EX)
{
continue;
}
@ -169,7 +169,7 @@ int main(int argc, const char **argv)
NewImageItem.m_Version = CMapItemImage::CURRENT_VERSION;
}
Writer.AddItem(Type, ID, Size, pItem);
Writer.AddItem(Type, ID, Size, pItem, &Uuid);
}
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++)
{
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.
if(Type < 0 || Type == ITEMTYPE_EX)
if(Type == ITEMTYPE_EX)
{
continue;
}
int Size = Reader.GetItemSize(Index);
Writer.AddItem(Type, ID, Size, pPtr);
Writer.AddItem(Type, ID, Size, pPtr, &Uuid);
}
// add all data