Add functions for reading/writing strings from/to datafile

Simplify the usage of datafile reader and writer by adding utility functions to read and write zero-terminated UTF-8 strings.

Improve validation of string data read from datafiles. It is ensure that string data is null-terminated, has no internal NUL-characters and is valid UTF-8.

Fix loading of external sounds in the editor. The wrong path variable was being used, so the sound files would not be loaded from correct folder.

Add tests for new datafile reader/writer functions.
This commit is contained in:
Robert Müller 2023-08-13 11:50:35 +02:00
parent 106b04ee79
commit 7acf2c1573
12 changed files with 201 additions and 85 deletions

View file

@ -18,6 +18,7 @@ public:
virtual int GetDataSize(int Index) const = 0;
virtual void *GetData(int Index) = 0;
virtual void *GetDataSwapped(int Index) = 0;
virtual const char *GetDataString(int Index) = 0;
virtual void UnloadData(int Index) = 0;
virtual int NumData() const = 0;

View file

@ -402,6 +402,19 @@ void *CDataFileReader::GetDataSwapped(int Index)
return GetDataImpl(Index, true);
}
const char *CDataFileReader::GetDataString(int Index)
{
if(Index == -1)
return "";
const int DataSize = GetDataSize(Index);
if(!DataSize)
return nullptr;
const char *pData = static_cast<char *>(GetData(Index));
if(pData == nullptr || mem_has_null(pData, DataSize - 1) || pData[DataSize - 1] != '\0' || !str_utf8_check(pData))
return nullptr;
return pData;
}
void CDataFileReader::ReplaceData(int Index, char *pData, size_t Size)
{
dbg_assert(Index >= 0 && Index < m_pDataFile->m_Header.m_NumRawData, "Index invalid");
@ -747,6 +760,13 @@ int CDataFileWriter::AddDataSwapped(int Size, const void *pData)
#endif
}
int CDataFileWriter::AddDataString(const char *pStr)
{
if(pStr[0] == '\0')
return -1;
return AddData(str_length(pStr) + 1, pStr);
}
void CDataFileWriter::Finish()
{
dbg_assert((bool)m_File, "file not open");

View file

@ -45,6 +45,7 @@ public:
int GetDataSize(int Index) const;
void *GetData(int Index);
void *GetDataSwapped(int Index); // makes sure that the data is 32bit LE ints when saved
const char *GetDataString(int Index);
void ReplaceData(int Index, char *pData, size_t Size); // memory for data must have been allocated with malloc
void UnloadData(int Index);
int NumData() const;
@ -136,6 +137,7 @@ public:
bool Open(class IStorage *pStorage, const char *pFilename, int StorageType = IStorage::TYPE_SAVE);
int AddData(int Size, const void *pData, int CompressionLevel = Z_DEFAULT_COMPRESSION);
int AddDataSwapped(int Size, const void *pData);
int AddDataString(const char *pStr);
int AddItem(int Type, int ID, int Size, const void *pData);
void Finish();
};

View file

@ -25,6 +25,11 @@ void *CMap::GetDataSwapped(int Index)
return m_DataFile.GetDataSwapped(Index);
}
const char *CMap::GetDataString(int Index)
{
return m_DataFile.GetDataString(Index);
}
void CMap::UnloadData(int Index)
{
m_DataFile.UnloadData(Index);

View file

@ -20,6 +20,7 @@ public:
int GetDataSize(int Index) const override;
void *GetData(int Index) override;
void *GetDataSwapped(int Index) override;
const char *GetDataString(int Index) override;
void UnloadData(int Index) override;
int NumData() const override;

View file

@ -1,17 +1,18 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <base/log.h>
#include <engine/graphics.h>
#include <engine/map.h>
#include <engine/storage.h>
#include <engine/textrender.h>
#include <game/generated/client_data.h>
#include <game/mapitems.h>
#include <game/layers.h>
#include "mapimages.h"
#include <game/client/gameclient.h>
#include <game/generated/client_data.h>
#include <game/layers.h>
#include <game/mapitems.h>
#include "mapimages.h"
const char *const gs_apModEntitiesNames[] = {
"ddnet",
@ -99,37 +100,37 @@ void CMapImages::OnMapLoadImpl(class CLayers *pLayers, IMap *pMap)
}
}
int TextureLoadFlag = Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
const int TextureLoadFlag = Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
// load new textures
for(int i = 0; i < m_Count; i++)
{
int LoadFlag = (((m_aTextureUsedByTileOrQuadLayerFlag[i] & 1) != 0) ? TextureLoadFlag : 0) | (((m_aTextureUsedByTileOrQuadLayerFlag[i] & 2) != 0) ? 0 : (Graphics()->IsTileBufferingEnabled() ? IGraphics::TEXLOAD_NO_2D_TEXTURE : 0));
const int LoadFlag = (((m_aTextureUsedByTileOrQuadLayerFlag[i] & 1) != 0) ? TextureLoadFlag : 0) | (((m_aTextureUsedByTileOrQuadLayerFlag[i] & 2) != 0) ? 0 : (Graphics()->IsTileBufferingEnabled() ? IGraphics::TEXLOAD_NO_2D_TEXTURE : 0));
const CMapItemImage_v2 *pImg = (CMapItemImage_v2 *)pMap->GetItem(Start + i);
const CImageInfo::EImageFormat Format = pImg->m_Version < CMapItemImage_v2::CURRENT_VERSION ? CImageInfo::FORMAT_RGBA : CImageInfo::ImageFormatFromInt(pImg->m_Format);
const char *pName = pMap->GetDataString(pImg->m_ImageName);
if(pName == nullptr || pName[0] == '\0')
{
log_error("mapimages", "Failed to load map image %d: failed to load name.", i);
continue;
}
if(pImg->m_External)
{
char aPath[IO_MAX_PATH_LENGTH];
char *pName = (char *)pMap->GetData(pImg->m_ImageName);
str_format(aPath, sizeof(aPath), "mapres/%s.png", pName);
m_aTextures[i] = Graphics()->LoadTexture(aPath, IStorage::TYPE_ALL, LoadFlag);
pMap->UnloadData(pImg->m_ImageName);
}
else if(Format != CImageInfo::FORMAT_RGBA)
{
m_aTextures[i] = Graphics()->InvalidTexture();
pMap->UnloadData(pImg->m_ImageName);
}
else
else if(Format == CImageInfo::FORMAT_RGBA)
{
void *pData = pMap->GetData(pImg->m_ImageData);
char *pName = (char *)pMap->GetData(pImg->m_ImageName);
char aTexName[128];
str_format(aTexName, sizeof(aTexName), "%s %s", "embedded:", pName);
char aTexName[IO_MAX_PATH_LENGTH];
str_format(aTexName, sizeof(aTexName), "embedded: %s", pName);
m_aTextures[i] = Graphics()->LoadTextureRaw(pImg->m_Width, pImg->m_Height, Format, pData, LoadFlag, aTexName);
pMap->UnloadData(pImg->m_ImageName);
pMap->UnloadData(pImg->m_ImageData);
}
pMap->UnloadData(pImg->m_ImageName);
}
}

View file

@ -1,12 +1,11 @@
#include <base/log.h>
#include <engine/demo.h>
#include <engine/sound.h>
#include <game/client/components/camera.h>
#include <game/client/components/maplayers.h> // envelope
#include <game/client/components/sounds.h>
#include <game/client/gameclient.h>
#include <game/layers.h>
#include <game/mapitems.h>
@ -30,15 +29,20 @@ void CMapSounds::OnMapLoad()
// load new samples
for(int i = 0; i < m_Count; i++)
{
m_aSounds[i] = 0;
CMapItemSound *pSound = (CMapItemSound *)pMap->GetItem(Start + i);
if(pSound->m_External)
{
const char *pName = pMap->GetDataString(pSound->m_SoundName);
if(pName == nullptr || pName[0] == '\0')
{
log_error("mapsounds", "Failed to load map sound %d: failed to load name.", i);
continue;
}
char aBuf[IO_MAX_PATH_LENGTH];
char *pName = (char *)pMap->GetData(pSound->m_SoundName);
str_format(aBuf, sizeof(aBuf), "mapres/%s.opus", pName);
m_aSounds[i] = Sound()->LoadOpus(aBuf);
pMap->UnloadData(pSound->m_SoundName);
}
else
{

View file

@ -59,23 +59,10 @@ bool CEditorMap::Save(const char *pFileName)
{
CMapItemInfoSettings Item;
Item.m_Version = 1;
if(m_MapInfo.m_aAuthor[0])
Item.m_Author = Writer.AddData(str_length(m_MapInfo.m_aAuthor) + 1, m_MapInfo.m_aAuthor);
else
Item.m_Author = -1;
if(m_MapInfo.m_aVersion[0])
Item.m_MapVersion = Writer.AddData(str_length(m_MapInfo.m_aVersion) + 1, m_MapInfo.m_aVersion);
else
Item.m_MapVersion = -1;
if(m_MapInfo.m_aCredits[0])
Item.m_Credits = Writer.AddData(str_length(m_MapInfo.m_aCredits) + 1, m_MapInfo.m_aCredits);
else
Item.m_Credits = -1;
if(m_MapInfo.m_aLicense[0])
Item.m_License = Writer.AddData(str_length(m_MapInfo.m_aLicense) + 1, m_MapInfo.m_aLicense);
else
Item.m_License = -1;
Item.m_Author = Writer.AddDataString(m_MapInfo.m_aAuthor);
Item.m_MapVersion = Writer.AddDataString(m_MapInfo.m_aVersion);
Item.m_Credits = Writer.AddDataString(m_MapInfo.m_aCredits);
Item.m_License = Writer.AddDataString(m_MapInfo.m_aLicense);
Item.m_Settings = -1;
if(!m_vSettings.empty())
@ -116,7 +103,7 @@ bool CEditorMap::Save(const char *pFileName)
Item.m_Width = pImg->m_Width;
Item.m_Height = pImg->m_Height;
Item.m_External = pImg->m_External;
Item.m_ImageName = Writer.AddData(str_length(pImg->m_aName) + 1, pImg->m_aName);
Item.m_ImageName = Writer.AddDataString(pImg->m_aName);
if(pImg->m_External)
{
Item.m_ImageData = -1;
@ -157,7 +144,7 @@ bool CEditorMap::Save(const char *pFileName)
Item.m_Version = 1;
Item.m_External = 0;
Item.m_SoundName = Writer.AddData(str_length(pSound->m_aName) + 1, pSound->m_aName);
Item.m_SoundName = Writer.AddDataString(pSound->m_aName);
Item.m_SoundData = Writer.AddData(pSound->m_DataSize, pSound->m_pData);
Item.m_SoundDataSize = pSound->m_DataSize;
@ -449,14 +436,25 @@ bool CEditorMap::Load(const char *pFileName, int StorageType, const std::functio
if(!pItem || ItemID != 0)
continue;
if(pItem->m_Author > -1)
str_copy(m_MapInfo.m_aAuthor, (char *)DataFile.GetData(pItem->m_Author));
if(pItem->m_MapVersion > -1)
str_copy(m_MapInfo.m_aVersion, (char *)DataFile.GetData(pItem->m_MapVersion));
if(pItem->m_Credits > -1)
str_copy(m_MapInfo.m_aCredits, (char *)DataFile.GetData(pItem->m_Credits));
if(pItem->m_License > -1)
str_copy(m_MapInfo.m_aLicense, (char *)DataFile.GetData(pItem->m_License));
const auto &&ReadStringInfo = [&](int Index, char *pBuffer, size_t BufferSize, const char *pErrorContext) {
const char *pStr = DataFile.GetDataString(Index);
if(pStr == nullptr)
{
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "Error: Failed to read %s from map info.", pErrorContext);
ErrorHandler(aBuf);
pBuffer[0] = '\0';
}
else
{
str_copy(pBuffer, pStr, BufferSize);
}
};
ReadStringInfo(pItem->m_Author, m_MapInfo.m_aAuthor, sizeof(m_MapInfo.m_aAuthor), "author");
ReadStringInfo(pItem->m_MapVersion, m_MapInfo.m_aVersion, sizeof(m_MapInfo.m_aVersion), "version");
ReadStringInfo(pItem->m_Credits, m_MapInfo.m_aCredits, sizeof(m_MapInfo.m_aCredits), "credits");
ReadStringInfo(pItem->m_License, m_MapInfo.m_aLicense, sizeof(m_MapInfo.m_aLicense), "license");
if(pItem->m_Version != 1 || ItemSize < (int)sizeof(CMapItemInfoSettings))
break;
@ -483,17 +481,26 @@ bool CEditorMap::Load(const char *pFileName, int StorageType, const std::functio
for(int i = 0; i < Num; i++)
{
CMapItemImage_v2 *pItem = (CMapItemImage_v2 *)DataFile.GetItem(Start + i);
char *pName = (char *)DataFile.GetData(pItem->m_ImageName);
// copy base info
std::shared_ptr<CEditorImage> pImg = std::make_shared<CEditorImage>(m_pEditor);
pImg->m_External = pItem->m_External;
const char *pName = DataFile.GetDataString(pItem->m_ImageName);
if(pName == nullptr || pName[0] == '\0')
{
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "Error: Failed to read name of image %d.", i);
ErrorHandler(aBuf);
}
else
str_copy(pImg->m_aName, pName);
const CImageInfo::EImageFormat Format = pItem->m_Version < CMapItemImage_v2::CURRENT_VERSION ? CImageInfo::FORMAT_RGBA : CImageInfo::ImageFormatFromInt(pItem->m_Format);
if(pImg->m_External || (Format != CImageInfo::FORMAT_RGB && Format != CImageInfo::FORMAT_RGBA))
{
char aBuf[IO_MAX_PATH_LENGTH];
str_format(aBuf, sizeof(aBuf), "mapres/%s.png", pName);
str_format(aBuf, sizeof(aBuf), "mapres/%s.png", pImg->m_aName);
// load external
CEditorImage ImgInfo(m_pEditor);
@ -525,10 +532,6 @@ bool CEditorMap::Load(const char *pFileName, int StorageType, const std::functio
pImg->m_Texture = m_pEditor->Graphics()->LoadTextureRaw(pImg->m_Width, pImg->m_Height, pImg->m_Format, pImg->m_pData, TextureLoadFlag);
}
// copy image name
if(pName)
str_copy(pImg->m_aName, pName);
// load auto mapper file
pImg->m_AutoMapper.Load(pImg->m_aName);
@ -547,17 +550,27 @@ bool CEditorMap::Load(const char *pFileName, int StorageType, const std::functio
for(int i = 0; i < Num; i++)
{
CMapItemSound *pItem = (CMapItemSound *)DataFile.GetItem(Start + i);
char *pName = (char *)DataFile.GetData(pItem->m_SoundName);
// copy base info
std::shared_ptr<CEditorSound> pSound = std::make_shared<CEditorSound>(m_pEditor);
const char *pName = DataFile.GetDataString(pItem->m_SoundName);
if(pName == nullptr || pName[0] == '\0')
{
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "Error: Failed to read name of sound %d.", i);
ErrorHandler(aBuf);
}
else
str_copy(pSound->m_aName, pName);
if(pItem->m_External)
{
char aBuf[IO_MAX_PATH_LENGTH];
str_format(aBuf, sizeof(aBuf), "mapres/%s.opus", pName);
str_format(aBuf, sizeof(aBuf), "mapres/%s.opus", pSound->m_aName);
// load external
if(m_pEditor->Storage()->ReadFile(pName, IStorage::TYPE_ALL, &pSound->m_pData, &pSound->m_DataSize))
if(m_pEditor->Storage()->ReadFile(aBuf, IStorage::TYPE_ALL, &pSound->m_pData, &pSound->m_DataSize))
{
pSound->m_SoundID = m_pEditor->Sound()->LoadOpusFromMem(pSound->m_pData, pSound->m_DataSize, true);
}
@ -573,13 +586,9 @@ bool CEditorMap::Load(const char *pFileName, int StorageType, const std::functio
pSound->m_SoundID = m_pEditor->Sound()->LoadOpusFromMem(pSound->m_pData, pSound->m_DataSize, true);
}
// copy image name
if(pName)
str_copy(pSound->m_aName, pName);
m_vpSounds.push_back(pSound);
// unload image
// unload sound
DataFile.UnloadData(pItem->m_SoundData);
DataFile.UnloadData(pItem->m_SoundName);
}

View file

@ -51,6 +51,53 @@ TEST(Datafile, ExtendedType)
EXPECT_EQ(pTest->m_aFields[1], ItemTest.m_aFields[1]);
EXPECT_EQ(pTest->m_Field3, ItemTest.m_Field3);
EXPECT_EQ(pTest->m_Field4, ItemTest.m_Field4);
Reader.Close();
}
if(!HasFailure())
{
pStorage->RemoveFile(Info.m_aFilename, IStorage::TYPE_SAVE);
}
}
TEST(Datafile, StringData)
{
auto pStorage = std::unique_ptr<IStorage>(CreateLocalStorage());
CTestInfo Info;
{
CDataFileWriter Writer;
Writer.Open(pStorage.get(), Info.m_aFilename);
EXPECT_EQ(Writer.AddDataString(""), -1); // Empty string is not added
EXPECT_EQ(Writer.AddDataString("Abc"), 0);
EXPECT_EQ(Writer.AddDataString("DDNet最好了"), 1);
EXPECT_EQ(Writer.AddDataString("aβい🐘"), 2);
EXPECT_EQ(Writer.AddData(3, "Abc"), 3); // Not zero-terminated
EXPECT_EQ(Writer.AddData(7, "foo\0bar"), 4); // Early zero-terminator
EXPECT_EQ(Writer.AddData(5, "xyz\xff\0"), 5); // Truncated UTF-8
EXPECT_EQ(Writer.AddData(4, "XYZ\xff"), 6); // Truncated UTF-8 and not zero-terminated
Writer.Finish();
}
{
CDataFileReader Reader;
Reader.Open(pStorage.get(), Info.m_aFilename, IStorage::TYPE_ALL);
EXPECT_EQ(Reader.GetDataString(-1000), nullptr);
EXPECT_STREQ(Reader.GetDataString(-1), "");
EXPECT_STREQ(Reader.GetDataString(0), "Abc");
EXPECT_STREQ(Reader.GetDataString(1), "DDNet最好了");
EXPECT_STREQ(Reader.GetDataString(2), "aβい🐘");
EXPECT_EQ(Reader.GetDataString(3), nullptr);
EXPECT_EQ(Reader.GetDataString(4), nullptr);
EXPECT_EQ(Reader.GetDataString(5), nullptr);
EXPECT_EQ(Reader.GetDataString(6), nullptr);
EXPECT_EQ(Reader.GetDataString(1000), nullptr);
Reader.Close();
}
if(!HasFailure())

View file

@ -91,17 +91,24 @@ bool CheckImageDimensions(void *pLayerItem, int LayerType, const char *pFilename
char aTileLayerName[12];
IntsToStr(pTMap->m_aName, sizeof(pTMap->m_aName) / sizeof(int), aTileLayerName);
char *pName = (char *)g_DataReader.GetData(pImgItem->m_ImageName);
dbg_msg("map_convert_07", "%s: Tile layer \"%s\" uses image \"%s\" with width %d, height %d, which is not divisible by 16. This is not supported in Teeworlds 0.7. Please scale the image and replace it manually.", pFilename, aTileLayerName, pName, pImgItem->m_Width, pImgItem->m_Height);
const char *pName = g_DataReader.GetDataString(pImgItem->m_ImageName);
dbg_msg("map_convert_07", "%s: Tile layer \"%s\" uses image \"%s\" with width %d, height %d, which is not divisible by 16. This is not supported in Teeworlds 0.7. Please scale the image and replace it manually.", pFilename, aTileLayerName, pName == nullptr ? "(error)" : pName, pImgItem->m_Width, pImgItem->m_Height);
return false;
}
void *ReplaceImageItem(CMapItemImage *pImgItem, CMapItemImage *pNewImgItem)
void *ReplaceImageItem(int Index, CMapItemImage *pImgItem, CMapItemImage *pNewImgItem)
{
if(!pImgItem->m_External)
return pImgItem;
char *pName = (char *)g_DataReader.GetData(pImgItem->m_ImageName);
const char *pName = g_DataReader.GetDataString(pImgItem->m_ImageName);
if(pName == nullptr || pName[0] == '\0')
{
dbg_msg("map_convert_07", "failed to load name of image %d", Index);
return pImgItem;
}
dbg_msg("map_convert_07", "embedding image '%s'", pName);
CImageInfo ImgInfo;
@ -220,7 +227,7 @@ int main(int argc, const char **argv)
CMapItemImage NewImageItem;
if(Type == MAPITEMTYPE_IMAGE)
{
pItem = ReplaceImageItem((CMapItemImage *)pItem, &NewImageItem);
pItem = ReplaceImageItem(Index, (CMapItemImage *)pItem, &NewImageItem);
if(!pItem)
return -1;
Size = sizeof(CMapItemImage);

View file

@ -27,10 +27,14 @@ bool Process(IStorage *pStorage, const char *pMapName, const char *pPathSave)
if(pInfo)
{
dbg_msg("map_extract", "author: %s", (char *)Reader.GetData(pInfo->m_Author));
dbg_msg("map_extract", "version: %s", (char *)Reader.GetData(pInfo->m_MapVersion));
dbg_msg("map_extract", "credits: %s", (char *)Reader.GetData(pInfo->m_Credits));
dbg_msg("map_extract", "license: %s", (char *)Reader.GetData(pInfo->m_License));
const char *pAuthor = Reader.GetDataString(pInfo->m_Author);
dbg_msg("map_extract", "author: %s", pAuthor == nullptr ? "(error)" : pAuthor);
const char *pMapVersion = Reader.GetDataString(pInfo->m_MapVersion);
dbg_msg("map_extract", "version: %s", pMapVersion == nullptr ? "(error)" : pMapVersion);
const char *pCredits = Reader.GetDataString(pInfo->m_Credits);
dbg_msg("map_extract", "credits: %s", pCredits == nullptr ? "(error)" : pCredits);
const char *pLicense = Reader.GetDataString(pInfo->m_License);
dbg_msg("map_extract", "license: %s", pLicense == nullptr ? "(error)" : pLicense);
}
int Start, Num;
@ -41,12 +45,17 @@ bool Process(IStorage *pStorage, const char *pMapName, const char *pPathSave)
for(int i = 0; i < Num; i++)
{
CMapItemImage_v2 *pItem = (CMapItemImage_v2 *)Reader.GetItem(Start + i);
char *pName = (char *)Reader.GetData(pItem->m_ImageName);
if(pItem->m_External)
continue;
char aBuf[512];
const char *pName = Reader.GetDataString(pItem->m_ImageName);
if(pName == nullptr || pName[0] == '\0')
{
dbg_msg("map_extract", "failed to load name of image %d", i);
continue;
}
char aBuf[IO_MAX_PATH_LENGTH];
str_format(aBuf, sizeof(aBuf), "%s/%s.png", pPathSave, pName);
dbg_msg("map_extract", "writing image: %s (%dx%d)", aBuf, pItem->m_Width, pItem->m_Height);
@ -81,12 +90,17 @@ bool Process(IStorage *pStorage, const char *pMapName, const char *pPathSave)
for(int i = 0; i < Num; i++)
{
CMapItemSound *pItem = (CMapItemSound *)Reader.GetItem(Start + i);
char *pName = (char *)Reader.GetData(pItem->m_SoundName);
if(pItem->m_External)
continue;
char aBuf[512];
const char *pName = Reader.GetDataString(pItem->m_SoundName);
if(pName == nullptr || pName[0] == '\0')
{
dbg_msg("map_extract", "failed to load name of sound %d", i);
continue;
}
char aBuf[IO_MAX_PATH_LENGTH];
str_format(aBuf, sizeof(aBuf), "%s/%s.opus", pPathSave, pName);
dbg_msg("map_extract", "writing sound: %s (%d B)", aBuf, pItem->m_SoundDataSize);

View file

@ -67,9 +67,14 @@ int LoadPNG(CImageInfo *pImg, const char *pFilename)
return 1;
}
void *ReplaceImageItem(CMapItemImage *pImgItem, const char *pImgName, const char *pImgFile, CMapItemImage *pNewImgItem)
void *ReplaceImageItem(int Index, CMapItemImage *pImgItem, const char *pImgName, const char *pImgFile, CMapItemImage *pNewImgItem)
{
char *pName = (char *)g_DataReader.GetData(pImgItem->m_ImageName);
const char *pName = g_DataReader.GetDataString(pImgItem->m_ImageName);
if(pName == nullptr || pName[0] == '\0')
{
dbg_msg("map_replace_image", "failed to load name of image %d", Index);
return pImgItem;
}
if(str_comp(pImgName, pName) != 0)
return pImgItem;
@ -154,7 +159,7 @@ int main(int argc, const char **argv)
CMapItemImage NewImageItem;
if(Type == MAPITEMTYPE_IMAGE)
{
pItem = ReplaceImageItem((CMapItemImage *)pItem, pImageName, pImageFile, &NewImageItem);
pItem = ReplaceImageItem(Index, (CMapItemImage *)pItem, pImageName, pImageFile, &NewImageItem);
if(!pItem)
return -1;
Size = sizeof(CMapItemImage);