Merge pull request #7289 from Robyt3/Map-Version-Check

Ensure current map is not corrupted when loading another fails
This commit is contained in:
Dennis Felsing 2023-10-03 13:17:03 +00:00 committed by GitHub
commit dbd9da3c7b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 517 additions and 499 deletions

View file

@ -30,6 +30,13 @@ public:
m_pDataFile(nullptr) {}
~CDataFileReader() { Close(); }
CDataFileReader &operator=(CDataFileReader &&Other)
{
m_pDataFile = Other.m_pDataFile;
Other.m_pDataFile = nullptr;
return *this;
}
bool Open(class IStorage *pStorage, const char *pFilename, int StorageType);
bool Close();
bool IsOpen() const { return m_pDataFile != nullptr; }

View file

@ -2,6 +2,8 @@
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include "map.h"
#include <base/log.h>
#include <engine/storage.h>
#include <game/mapitems.h>
@ -63,23 +65,32 @@ bool CMap::Load(const char *pMapName)
IStorage *pStorage = Kernel()->RequestInterface<IStorage>();
if(!pStorage)
return false;
if(!m_DataFile.Open(pStorage, pMapName, IStorage::TYPE_ALL))
return false;
// check version
const CMapItemVersion *pItem = (CMapItemVersion *)m_DataFile.FindItem(MAPITEMTYPE_VERSION, 0);
if(!pItem || pItem->m_Version != CMapItemVersion::CURRENT_VERSION)
// Ensure current datafile is not left in an inconsistent state if loading fails,
// by loading the new datafile separately first.
CDataFileReader NewDataFile;
if(!NewDataFile.Open(pStorage, pMapName, IStorage::TYPE_ALL))
return false;
// replace compressed tile layers with uncompressed ones
// Check version
const CMapItemVersion *pItem = (CMapItemVersion *)NewDataFile.FindItem(MAPITEMTYPE_VERSION, 0);
if(pItem == nullptr || pItem->m_Version != CMapItemVersion::CURRENT_VERSION)
{
log_error("map/load", "Error: map version not supported.");
NewDataFile.Close();
return false;
}
// Replace compressed tile layers with uncompressed ones
int GroupsStart, GroupsNum, LayersStart, LayersNum;
m_DataFile.GetType(MAPITEMTYPE_GROUP, &GroupsStart, &GroupsNum);
m_DataFile.GetType(MAPITEMTYPE_LAYER, &LayersStart, &LayersNum);
NewDataFile.GetType(MAPITEMTYPE_GROUP, &GroupsStart, &GroupsNum);
NewDataFile.GetType(MAPITEMTYPE_LAYER, &LayersStart, &LayersNum);
for(int g = 0; g < GroupsNum; g++)
{
const CMapItemGroup *pGroup = static_cast<CMapItemGroup *>(m_DataFile.GetItem(GroupsStart + g));
const CMapItemGroup *pGroup = static_cast<CMapItemGroup *>(NewDataFile.GetItem(GroupsStart + g));
for(int l = 0; l < pGroup->m_NumLayers; l++)
{
CMapItemLayer *pLayer = static_cast<CMapItemLayer *>(m_DataFile.GetItem(LayersStart + pGroup->m_StartLayer + l));
CMapItemLayer *pLayer = static_cast<CMapItemLayer *>(NewDataFile.GetItem(LayersStart + pGroup->m_StartLayer + l));
if(pLayer->m_Type == LAYERTYPE_TILES)
{
CMapItemLayerTilemap *pTilemap = reinterpret_cast<CMapItemLayerTilemap *>(pLayer);
@ -87,13 +98,16 @@ bool CMap::Load(const char *pMapName)
{
const size_t TilemapSize = (size_t)pTilemap->m_Width * pTilemap->m_Height * sizeof(CTile);
CTile *pTiles = static_cast<CTile *>(malloc(TilemapSize));
ExtractTiles(pTiles, (size_t)pTilemap->m_Width * pTilemap->m_Height, static_cast<CTile *>(m_DataFile.GetData(pTilemap->m_Data)), m_DataFile.GetDataSize(pTilemap->m_Data) / sizeof(CTile));
m_DataFile.ReplaceData(pTilemap->m_Data, reinterpret_cast<char *>(pTiles), TilemapSize);
ExtractTiles(pTiles, (size_t)pTilemap->m_Width * pTilemap->m_Height, static_cast<CTile *>(NewDataFile.GetData(pTilemap->m_Data)), NewDataFile.GetDataSize(pTilemap->m_Data) / sizeof(CTile));
NewDataFile.ReplaceData(pTilemap->m_Data, reinterpret_cast<char *>(pTiles), TilemapSize);
}
}
}
}
// Replace existing datafile with new datafile
m_DataFile.Close();
m_DataFile = std::move(NewDataFile);
return true;
}

View file

@ -7907,7 +7907,6 @@ bool CEditor::Load(const char *pFileName, int StorageType)
else
{
m_aFileName[0] = 0;
Reset();
}
return Result;
}

View file

@ -427,16 +427,16 @@ bool CEditorMap::Load(const char *pFileName, int StorageType, const std::functio
if(!DataFile.Open(m_pEditor->Storage(), pFileName, StorageType))
return false;
Clean();
// check version
CMapItemVersion *pItemVersion = (CMapItemVersion *)DataFile.FindItem(MAPITEMTYPE_VERSION, 0);
if(!pItemVersion)
const CMapItemVersion *pItemVersion = static_cast<CMapItemVersion *>(DataFile.FindItem(MAPITEMTYPE_VERSION, 0));
if(pItemVersion == nullptr || pItemVersion->m_Version != CMapItemVersion::CURRENT_VERSION)
{
ErrorHandler("Error: The map has an unsupported version.");
return false;
}
else if(pItemVersion->m_Version == CMapItemVersion::CURRENT_VERSION)
{
Clean();
// load map info
{
int Start, Num;
@ -936,6 +936,7 @@ bool CEditorMap::Load(const char *pFileName, int StorageType, const std::functio
}
}
// load automapper configurations
{
int AutomapperConfigStart, AutomapperConfigNum;
DataFile.GetType(MAPITEMTYPE_AUTOMAPPER_CONFIG, &AutomapperConfigStart, &AutomapperConfigNum);
@ -964,9 +965,6 @@ bool CEditorMap::Load(const char *pFileName, int StorageType, const std::functio
}
}
}
}
else
return false;
PerformSanityChecks(ErrorHandler);