// copyright (c) 2007 magnus auvinen, see licence.txt for more info
#include
#include
#include "engine.h"
// compiled-in data-dir path
#define DATA_DIR "data"
class CStorage : public IStorage
{
public:
char m_aApplicationSavePath[512];
char m_aDatadir[512];
CStorage()
{
m_aApplicationSavePath[0] = 0;
m_aDatadir[0] = 0;
}
int Init(const char *pApplicationName, const char *pArgv0)
{
char aPath[1024] = {0};
fs_storage_path(pApplicationName, m_aApplicationSavePath, sizeof(m_aApplicationSavePath));
if(fs_makedir(m_aApplicationSavePath) == 0)
{
str_format(aPath, sizeof(aPath), "%s/screenshots", m_aApplicationSavePath);
fs_makedir(aPath);
str_format(aPath, sizeof(aPath), "%s/maps", m_aApplicationSavePath);
fs_makedir(aPath);
str_format(aPath, sizeof(aPath), "%s/downloadedmaps", m_aApplicationSavePath);
fs_makedir(aPath);
str_format(aPath, sizeof(aPath), "%s/demos", m_aApplicationSavePath);
fs_makedir(aPath);
}
return FindDatadir(pArgv0);
}
int FindDatadir(const char *pArgv0)
{
// 1) use provided data-dir override
if(m_aDatadir[0])
{
if(fs_is_dir(m_aDatadir))
return 0;
else
{
dbg_msg("engine/datadir", "specified data-dir '%s' does not exist", m_aDatadir);
return -1;
}
}
// 2) use data-dir in PWD if present
if(fs_is_dir("data/mapres"))
{
str_copy(m_aDatadir, "data", sizeof(m_aDatadir));
return 0;
}
// 3) use compiled-in data-dir if present
if (fs_is_dir(DATA_DIR "/mapres"))
{
str_copy(m_aDatadir, DATA_DIR, sizeof(m_aDatadir));
return 0;
}
// 4) check for usable path in argv[0]
{
unsigned int Pos = ~0U;
for(unsigned i = 0; pArgv0[i]; i++)
if(pArgv0[i] == '/')
Pos = i;
if (Pos < sizeof(m_aDatadir))
{
char aBaseDir[sizeof(m_aDatadir)];
str_copy(aBaseDir, pArgv0, Pos);
aBaseDir[Pos] = '\0';
str_format(m_aDatadir, sizeof(m_aDatadir), "%s/data", aBaseDir);
if (fs_is_dir(m_aDatadir))
return 0;
}
}
#if defined(CONF_FAMILY_UNIX)
// 5) check for all default locations
{
const char *aDirs[] = {
"/usr/share/teeworlds/data",
"/usr/share/games/teeworlds/data",
"/usr/local/share/teeworlds/data",
"/usr/local/share/games/teeworlds/data",
"/opt/teeworlds/data"
};
const int DirsCount = sizeof(aDirs) / sizeof(aDirs[0]);
int i;
for (i = 0; i < DirsCount; i++)
{
if (fs_is_dir(aDirs[i]))
{
str_copy(m_aDatadir, aDirs[i], sizeof(m_aDatadir));
return 0;
}
}
}
#endif
// no data-dir found
dbg_msg("engine/datadir", "warning no data directory found");
return -1;
}
virtual void ListDirectory(int Types, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser)
{
char aBuffer[1024];
// list current directory
if(Types&TYPE_CURRENT)
{
fs_listdir(pPath, pfnCallback, pUser);
}
// list users directory
if(Types&TYPE_SAVE)
{
str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aApplicationSavePath, pPath);
fs_listdir(aBuffer, pfnCallback, pUser);
}
// list datadir directory
if(Types&TYPE_DATA)
{
str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aDatadir, pPath);
fs_listdir(aBuffer, pfnCallback, pUser);
}
}
virtual IOHANDLE OpenFile(const char *pFilename, int Flags, char *pBuffer = 0, int BufferSize = 0)
{
char aBuffer[1024];
if(!pBuffer)
{
pBuffer = aBuffer;
BufferSize = sizeof(aBuffer);
}
if(Flags&IOFLAG_WRITE)
{
str_format(pBuffer, BufferSize, "%s/%s", m_aApplicationSavePath, pFilename);
return io_open(pBuffer, Flags);
}
else
{
IOHANDLE Handle = 0;
// check current directory
Handle = io_open(pFilename, Flags);
if(Handle)
return Handle;
// check user directory
str_format(pBuffer, BufferSize, "%s/%s", m_aApplicationSavePath, pFilename);
Handle = io_open(pBuffer, Flags);
if(Handle)
return Handle;
// check normal data directory
str_format(pBuffer, BufferSize, "%s/%s", m_aDatadir, pFilename);
Handle = io_open(pBuffer, Flags);
if(Handle)
return Handle;
}
pBuffer[0] = 0;
return 0;
}
static IStorage *Create(const char *pApplicationName, const char *pArgv0)
{
CStorage *p = new CStorage();
if(p->Init(pApplicationName, pArgv0))
{
delete p;
p = 0;
}
return p;
}
};
IStorage *CreateStorage(const char *pApplicationName, const char *pArgv0) { return CStorage::Create(pApplicationName, pArgv0); }