mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
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:
parent
106b04ee79
commit
7acf2c1573
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue