From 1373c331eef0c3100c332fdda2bd3b2d20c18a06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sun, 13 Aug 2023 11:50:35 +0200 Subject: [PATCH] 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. --- src/engine/map.h | 1 + src/engine/shared/datafile.cpp | 18 +++++ src/engine/shared/datafile.h | 2 + src/engine/shared/map.cpp | 5 ++ src/engine/shared/map.h | 1 + src/game/client/components/mapimages.cpp | 37 ++++----- src/game/client/components/mapsounds.cpp | 16 ++-- src/game/editor/io.cpp | 95 ++++++++++++++---------- src/test/datafile.cpp | 45 +++++++++++ src/tools/map_convert_07.cpp | 17 +++-- src/tools/map_extract.cpp | 34 ++++++--- src/tools/map_replace_image.cpp | 11 ++- 12 files changed, 200 insertions(+), 82 deletions(-) diff --git a/src/engine/map.h b/src/engine/map.h index cb790bf16eb..af186ddcf89 100644 --- a/src/engine/map.h +++ b/src/engine/map.h @@ -18,6 +18,7 @@ class IMap : public IInterface 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; diff --git a/src/engine/shared/datafile.cpp b/src/engine/shared/datafile.cpp index 889ba220f3a..a0144285c02 100644 --- a/src/engine/shared/datafile.cpp +++ b/src/engine/shared/datafile.cpp @@ -402,6 +402,17 @@ void *CDataFileReader::GetDataSwapped(int Index) return GetDataImpl(Index, true); } +const char *CDataFileReader::GetDataString(int Index) +{ + const int DataSize = GetDataSize(Index); + if(!DataSize) + return nullptr; + const char *pData = static_cast(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 +758,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"); diff --git a/src/engine/shared/datafile.h b/src/engine/shared/datafile.h index 7b59fa5bcdc..572a0238410 100644 --- a/src/engine/shared/datafile.h +++ b/src/engine/shared/datafile.h @@ -38,6 +38,7 @@ class CDataFileReader 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; @@ -129,6 +130,7 @@ class CDataFileWriter 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(); }; diff --git a/src/engine/shared/map.cpp b/src/engine/shared/map.cpp index 374a1323732..cb81f0d527e 100644 --- a/src/engine/shared/map.cpp +++ b/src/engine/shared/map.cpp @@ -23,6 +23,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); diff --git a/src/engine/shared/map.h b/src/engine/shared/map.h index e2a6077aa58..ebb3a8591cb 100644 --- a/src/engine/shared/map.h +++ b/src/engine/shared/map.h @@ -20,6 +20,7 @@ class CMap : public IEngineMap 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; diff --git a/src/game/client/components/mapimages.cpp b/src/game/client/components/mapimages.cpp index 0076eb88ed5..e9faa46fe33 100644 --- a/src/game/client/components/mapimages.cpp +++ b/src/game/client/components/mapimages.cpp @@ -1,18 +1,19 @@ /* (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 + #include #include #include #include -#include -#include +#include +#include #include +#include #include "mapimages.h" -#include - const char *const gs_apModEntitiesNames[] = { "ddnet", "ddrace", @@ -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 int Format = pImg->m_Version < CMapItemImage_v2::CURRENT_VERSION ? CImageInfo::FORMAT_RGBA : pImg->m_Format; + + const char *pName = pMap->GetDataString(pImg->m_ImageName); + if(pName == nullptr) + { + 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, CImageInfo::FORMAT_AUTO, 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, CImageInfo::FORMAT_RGBA, LoadFlag, aTexName); - pMap->UnloadData(pImg->m_ImageName); pMap->UnloadData(pImg->m_ImageData); } + pMap->UnloadData(pImg->m_ImageName); } } diff --git a/src/game/client/components/mapsounds.cpp b/src/game/client/components/mapsounds.cpp index 704aaa5e603..2657689de0d 100644 --- a/src/game/client/components/mapsounds.cpp +++ b/src/game/client/components/mapsounds.cpp @@ -1,12 +1,11 @@ +#include + #include #include #include -#include // envelope #include - #include - #include #include @@ -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) + { + 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 { diff --git a/src/game/editor/io.cpp b/src/game/editor/io.cpp index a5516e18af3..4e74e746a75 100644 --- a/src/game/editor/io.cpp +++ b/src/game/editor/io.cpp @@ -66,23 +66,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()) @@ -123,7 +110,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; @@ -162,7 +149,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; @@ -478,14 +465,32 @@ 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) { + if(Index == -1) + { + pBuffer[0] = '\0'; + } + else + { + 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; @@ -512,17 +517,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 pImg = std::make_shared(m_pEditor); pImg->m_External = pItem->m_External; + const char *pName = DataFile.GetDataString(pItem->m_ImageName); + if(pName == nullptr) + { + 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 int Format = pItem->m_Version < CMapItemImage_v2::CURRENT_VERSION ? CImageInfo::FORMAT_RGBA : 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); @@ -554,10 +568,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, CImageInfo::FORMAT_AUTO, TextureLoadFlag); } - // copy image name - if(pName) - str_copy(pImg->m_aName, pName); - // load auto mapper file pImg->m_AutoMapper.Load(pImg->m_aName); @@ -576,18 +586,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 pSound = std::make_shared(m_pEditor); + const char *pName = DataFile.GetDataString(pItem->m_SoundName); + if(pName == nullptr) + { + 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); } @@ -603,10 +622,6 @@ 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 diff --git a/src/test/datafile.cpp b/src/test/datafile.cpp index 95773306c4a..dec2be49839 100644 --- a/src/test/datafile.cpp +++ b/src/test/datafile.cpp @@ -51,6 +51,51 @@ 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(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); + + char aBuf[256]; + 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); + + Reader.Close(); } if(!HasFailure()) diff --git a/src/tools/map_convert_07.cpp b/src/tools/map_convert_07.cpp index 679fde2f3bf..dbb05f6c204 100644 --- a/src/tools/map_convert_07.cpp +++ b/src/tools/map_convert_07.cpp @@ -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) + { + 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); diff --git a/src/tools/map_extract.cpp b/src/tools/map_extract.cpp index a6902285420..e7fcadfd745 100644 --- a/src/tools/map_extract.cpp +++ b/src/tools/map_extract.cpp @@ -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) + { + 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) + { + 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); diff --git a/src/tools/map_replace_image.cpp b/src/tools/map_replace_image.cpp index ca223526f0b..ca1b8685566 100644 --- a/src/tools/map_replace_image.cpp +++ b/src/tools/map_replace_image.cpp @@ -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) + { + 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);