ddnet/src/engine/shared/storage.cpp

406 lines
9.8 KiB
C++
Raw Normal View History

2010-11-20 10:37:14 +00:00
/* (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. */
2010-05-29 07:25:38 +00:00
#include <base/system.h>
#include <engine/storage.h>
2010-10-06 21:07:35 +00:00
#include "linereader.h"
2010-05-29 07:25:38 +00:00
// compiled-in data-dir path
#define DATA_DIR "data"
class CStorage : public IStorage
{
public:
2010-10-06 21:07:35 +00:00
enum
{
MAX_PATHS = 16,
MAX_PATH_LENGTH = 512
};
char m_aaStoragePaths[MAX_PATHS][MAX_PATH_LENGTH];
int m_NumPaths;
char m_aDatadir[MAX_PATH_LENGTH];
char m_aUserdir[MAX_PATH_LENGTH];
char m_aCurrentdir[MAX_PATH_LENGTH];
2010-05-29 07:25:38 +00:00
CStorage()
{
2010-10-06 21:07:35 +00:00
mem_zero(m_aaStoragePaths, sizeof(m_aaStoragePaths));
m_NumPaths = 0;
2010-05-29 07:25:38 +00:00
m_aDatadir[0] = 0;
2010-10-06 21:07:35 +00:00
m_aUserdir[0] = 0;
2010-05-29 07:25:38 +00:00
}
2010-08-05 18:26:03 +00:00
int Init(const char *pApplicationName, int NumArgs, const char **ppArguments)
2010-05-29 07:25:38 +00:00
{
2010-10-06 21:07:35 +00:00
// get userdir
fs_storage_path(pApplicationName, m_aUserdir, sizeof(m_aUserdir));
2010-08-05 18:26:03 +00:00
2010-10-06 21:07:35 +00:00
// get datadir
FindDatadir(ppArguments[0]);
// get currentdir
if(!fs_getcwd(m_aCurrentdir, sizeof(m_aCurrentdir)))
m_aCurrentdir[0] = 0;
2010-10-06 21:07:35 +00:00
// load paths from storage.cfg
LoadPaths(ppArguments[0]);
if(!m_NumPaths)
{
dbg_msg("storage", "using standard paths");
AddDefaultPaths();
}
// add save directories
if(m_NumPaths && (!m_aaStoragePaths[TYPE_SAVE][0] || !fs_makedir(m_aaStoragePaths[TYPE_SAVE])))
{
char aPath[MAX_PATH_LENGTH];
fs_makedir(GetPath(TYPE_SAVE, "screenshots", aPath, sizeof(aPath)));
fs_makedir(GetPath(TYPE_SAVE, "screenshots/auto", aPath, sizeof(aPath)));
2010-10-06 21:07:35 +00:00
fs_makedir(GetPath(TYPE_SAVE, "maps", aPath, sizeof(aPath)));
fs_makedir(GetPath(TYPE_SAVE, "dumps", aPath, sizeof(aPath)));
fs_makedir(GetPath(TYPE_SAVE, "downloadedmaps", aPath, sizeof(aPath)));
fs_makedir(GetPath(TYPE_SAVE, "demos", aPath, sizeof(aPath)));
fs_makedir(GetPath(TYPE_SAVE, "demos/auto", aPath, sizeof(aPath)));
2010-10-06 21:07:35 +00:00
}
return m_NumPaths ? 0 : 1;
}
void LoadPaths(const char *pArgv0)
{
// check current directory
IOHANDLE File = io_open("storage.cfg", IOFLAG_READ);
if(!File)
{
// check usable path in argv[0]
unsigned int Pos = ~0U;
for(unsigned i = 0; pArgv0[i]; i++)
if(pArgv0[i] == '/' || pArgv0[i] == '\\')
Pos = i;
if(Pos < MAX_PATH_LENGTH)
{
char aBuffer[MAX_PATH_LENGTH];
str_copy(aBuffer, pArgv0, Pos+1);
str_append(aBuffer, "/storage.cfg", sizeof(aBuffer));
File = io_open(aBuffer, IOFLAG_READ);
}
2010-10-06 21:07:35 +00:00
if(Pos >= MAX_PATH_LENGTH || !File)
{
dbg_msg("storage", "couldn't open storage.cfg");
return;
}
}
char *pLine;
CLineReader LineReader;
LineReader.Init(File);
while((pLine = LineReader.Get()))
{
if(str_length(pLine) > 9 && !str_comp_num(pLine, "add_path ", 9))
AddPath(pLine+9);
}
io_close(File);
if(!m_NumPaths)
dbg_msg("storage", "no paths found in storage.cfg");
}
void AddDefaultPaths()
{
AddPath("$USERDIR");
AddPath("$DATADIR");
AddPath("$CURRENTDIR");
}
void AddPath(const char *pPath)
{
if(m_NumPaths >= MAX_PATHS || !pPath[0])
return;
if(!str_comp(pPath, "$USERDIR"))
{
if(m_aUserdir[0])
{
2010-10-06 21:07:35 +00:00
str_copy(m_aaStoragePaths[m_NumPaths++], m_aUserdir, MAX_PATH_LENGTH);
dbg_msg("storage", "added path '$USERDIR' ('%s')", m_aUserdir);
}
2010-10-06 21:07:35 +00:00
}
else if(!str_comp(pPath, "$DATADIR"))
{
if(m_aDatadir[0])
{
2010-10-06 21:07:35 +00:00
str_copy(m_aaStoragePaths[m_NumPaths++], m_aDatadir, MAX_PATH_LENGTH);
dbg_msg("storage", "added path '$DATADIR' ('%s')", m_aDatadir);
}
2010-10-06 21:07:35 +00:00
}
else if(!str_comp(pPath, "$CURRENTDIR"))
{
m_aaStoragePaths[m_NumPaths++][0] = 0;
dbg_msg("storage", "added path '$CURRENTDIR' ('%s')", m_aCurrentdir);
2010-10-06 21:07:35 +00:00
}
else
{
if(fs_is_dir(pPath))
{
2010-10-06 21:07:35 +00:00
str_copy(m_aaStoragePaths[m_NumPaths++], pPath, MAX_PATH_LENGTH);
dbg_msg("storage", "added path '%s'", pPath);
}
2010-10-06 21:07:35 +00:00
}
2010-05-29 07:25:38 +00:00
}
2010-10-06 21:07:35 +00:00
void FindDatadir(const char *pArgv0)
2010-05-29 07:25:38 +00:00
{
// 1) use data-dir in PWD if present
2010-05-29 07:25:38 +00:00
if(fs_is_dir("data/mapres"))
{
str_copy(m_aDatadir, "data", sizeof(m_aDatadir));
2010-10-06 21:07:35 +00:00
return;
2010-05-29 07:25:38 +00:00
}
// 2) use compiled-in data-dir if present
2010-10-06 21:07:35 +00:00
if(fs_is_dir(DATA_DIR "/mapres"))
2010-05-29 07:25:38 +00:00
{
str_copy(m_aDatadir, DATA_DIR, sizeof(m_aDatadir));
2010-10-06 21:07:35 +00:00
return;
2010-05-29 07:25:38 +00:00
}
// 3) check for usable path in argv[0]
2010-05-29 07:25:38 +00:00
{
unsigned int Pos = ~0U;
for(unsigned i = 0; pArgv0[i]; i++)
2010-10-06 21:07:35 +00:00
if(pArgv0[i] == '/' || pArgv0[i] == '\\')
2010-05-29 07:25:38 +00:00
Pos = i;
2010-10-06 21:07:35 +00:00
if(Pos < MAX_PATH_LENGTH)
2010-05-29 07:25:38 +00:00
{
2010-10-06 21:07:35 +00:00
char aBaseDir[MAX_PATH_LENGTH];
str_copy(aBaseDir, pArgv0, Pos+1);
2010-05-29 07:25:38 +00:00
str_format(m_aDatadir, sizeof(m_aDatadir), "%s/data", aBaseDir);
2010-10-06 21:07:35 +00:00
str_append(aBaseDir, "/data/mapres", sizeof(aBaseDir));
2010-10-06 21:07:35 +00:00
if(fs_is_dir(aBaseDir))
return;
else
m_aDatadir[0] = 0;
2010-05-29 07:25:38 +00:00
}
}
2010-05-29 07:25:38 +00:00
#if defined(CONF_FAMILY_UNIX)
// 4) check for all default locations
2010-05-29 07:25:38 +00:00
{
const char *aDirs[] = {
2010-12-11 21:48:37 +00:00
"/usr/share/teeworlds/data",
"/usr/share/games/teeworlds/data",
"/usr/local/share/teeworlds/data",
"/usr/local/share/games/teeworlds/data",
"/opt/teeworlds/data"
2010-05-29 07:25:38 +00:00
};
const int DirsCount = sizeof(aDirs) / sizeof(aDirs[0]);
2010-05-29 07:25:38 +00:00
int i;
for (i = 0; i < DirsCount; i++)
{
2010-12-11 21:48:37 +00:00
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "%s/mapres", aDirs[i]);
if(fs_is_dir(aBuf))
2010-05-29 07:25:38 +00:00
{
str_copy(m_aDatadir, aDirs[i], sizeof(m_aDatadir));
2010-10-06 21:07:35 +00:00
return;
2010-05-29 07:25:38 +00:00
}
}
}
#endif
2010-05-29 07:25:38 +00:00
// no data-dir found
2010-10-06 21:07:35 +00:00
dbg_msg("storage", "warning no data directory found");
2010-05-29 07:25:38 +00:00
}
2010-10-06 21:07:35 +00:00
virtual void ListDirectory(int Type, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser)
2010-05-29 07:25:38 +00:00
{
2010-10-06 21:07:35 +00:00
char aBuffer[MAX_PATH_LENGTH];
if(Type == TYPE_ALL)
2010-05-29 07:25:38 +00:00
{
2010-10-06 21:07:35 +00:00
// list all available directories
for(int i = 0; i < m_NumPaths; ++i)
fs_listdir(GetPath(i, pPath, aBuffer, sizeof(aBuffer)), pfnCallback, i, pUser);
2010-05-29 07:25:38 +00:00
}
2010-10-06 21:07:35 +00:00
else if(Type >= 0 && Type < m_NumPaths)
2010-05-29 07:25:38 +00:00
{
2010-10-06 21:07:35 +00:00
// list wanted directory
fs_listdir(GetPath(Type, pPath, aBuffer, sizeof(aBuffer)), pfnCallback, Type, pUser);
2010-05-29 07:25:38 +00:00
}
}
2010-10-06 21:07:35 +00:00
const char *GetPath(int Type, const char *pDir, char *pBuffer, unsigned BufferSize)
{
2010-10-06 21:07:35 +00:00
str_format(pBuffer, BufferSize, "%s%s%s", m_aaStoragePaths[Type], !m_aaStoragePaths[Type][0] ? "" : "/", pDir);
return pBuffer;
}
2010-10-06 21:07:35 +00:00
virtual IOHANDLE OpenFile(const char *pFilename, int Flags, int Type, char *pBuffer = 0, int BufferSize = 0)
2010-05-29 07:25:38 +00:00
{
2010-10-06 21:07:35 +00:00
char aBuffer[MAX_PATH_LENGTH];
2010-05-29 07:25:38 +00:00
if(!pBuffer)
{
pBuffer = aBuffer;
BufferSize = sizeof(aBuffer);
}
2010-05-29 07:25:38 +00:00
if(Flags&IOFLAG_WRITE)
{
2010-10-06 21:07:35 +00:00
return io_open(GetPath(TYPE_SAVE, pFilename, pBuffer, BufferSize), Flags);
2010-05-29 07:25:38 +00:00
}
else
{
IOHANDLE Handle = 0;
2010-10-06 21:07:35 +00:00
if(Type == TYPE_ALL)
{
// check all available directories
for(int i = 0; i < m_NumPaths; ++i)
{
Handle = io_open(GetPath(i, pFilename, pBuffer, BufferSize), Flags);
if(Handle)
return Handle;
}
}
else if(Type >= 0 && Type < m_NumPaths)
{
// check wanted directory
Handle = io_open(GetPath(Type, pFilename, pBuffer, BufferSize), Flags);
if(Handle)
return Handle;
}
2010-05-29 07:25:38 +00:00
}
2010-05-29 07:25:38 +00:00
pBuffer[0] = 0;
return 0;
2010-05-29 07:25:38 +00:00
}
struct CFindCBData
{
CStorage *pStorage;
const char *pFilename;
const char *pPath;
char *pBuffer;
int BufferSize;
};
static int FindFileCallback(const char *pName, int IsDir, int Type, void *pUser)
{
CFindCBData Data = *static_cast<CFindCBData *>(pUser);
if(IsDir)
{
if(pName[0] == '.')
return 0;
// search within the folder
char aBuf[MAX_PATH_LENGTH];
char aPath[MAX_PATH_LENGTH];
str_format(aPath, sizeof(aPath), "%s/%s", Data.pPath, pName);
Data.pPath = aPath;
fs_listdir(Data.pStorage->GetPath(Type, aPath, aBuf, sizeof(aBuf)), FindFileCallback, Type, &Data);
if(Data.pBuffer[0])
return 1;
}
else if(!str_comp(pName, Data.pFilename))
{
// found the file = end
str_format(Data.pBuffer, Data.BufferSize, "%s/%s", Data.pPath, Data.pFilename);
return 1;
}
return 0;
}
virtual bool FindFile(const char *pFilename, const char *pPath, int Type, char *pBuffer, int BufferSize)
{
if(BufferSize < 1)
return false;
pBuffer[0] = 0;
char aBuf[MAX_PATH_LENGTH];
CFindCBData Data;
Data.pStorage = this;
Data.pFilename = pFilename;
Data.pPath = pPath;
Data.pBuffer = pBuffer;
Data.BufferSize = BufferSize;
if(Type == TYPE_ALL)
{
// search within all available directories
for(int i = 0; i < m_NumPaths; ++i)
{
fs_listdir(GetPath(i, pPath, aBuf, sizeof(aBuf)), FindFileCallback, i, &Data);
if(pBuffer[0])
return true;
}
}
else if(Type >= 0 && Type < m_NumPaths)
{
// search within wanted directory
fs_listdir(GetPath(Type, pPath, aBuf, sizeof(aBuf)), FindFileCallback, Type, &Data);
}
return pBuffer[0] != 0;
}
2010-10-06 21:07:35 +00:00
virtual bool RemoveFile(const char *pFilename, int Type)
{
2010-10-06 21:07:35 +00:00
if(Type < 0 || Type >= m_NumPaths)
return false;
char aBuffer[MAX_PATH_LENGTH];
2010-12-07 23:13:59 +00:00
return !fs_remove(GetPath(Type, pFilename, aBuffer, sizeof(aBuffer)));
}
2010-05-29 07:25:38 +00:00
virtual bool RenameFile(const char* pOldFilename, const char* pNewFilename, int Type)
{
if(Type < 0 || Type >= m_NumPaths)
return false;
char aOldBuffer[MAX_PATH_LENGTH];
char aNewBuffer[MAX_PATH_LENGTH];
return !fs_rename(GetPath(Type, pOldFilename, aOldBuffer, sizeof(aOldBuffer)), GetPath(Type, pNewFilename, aNewBuffer, sizeof (aNewBuffer)));
}
virtual bool CreateFolder(const char *pFoldername, int Type)
{
if(Type < 0 || Type >= m_NumPaths)
return false;
char aBuffer[MAX_PATH_LENGTH];
return !fs_makedir(GetPath(Type, pFoldername, aBuffer, sizeof(aBuffer)));
}
virtual void GetCompletePath(int Type, const char *pDir, char *pBuffer, unsigned BufferSize)
{
if(Type < 0 || Type >= m_NumPaths)
{
if(BufferSize > 0)
pBuffer[0] = 0;
return;
}
GetPath(Type, pDir, pBuffer, BufferSize);
}
2010-08-05 18:26:03 +00:00
static IStorage *Create(const char *pApplicationName, int NumArgs, const char **ppArguments)
2010-05-29 07:25:38 +00:00
{
CStorage *p = new CStorage();
if(p && p->Init(pApplicationName, NumArgs, ppArguments))
2010-05-29 07:25:38 +00:00
{
2010-10-06 21:07:35 +00:00
dbg_msg("storage", "initialisation failed");
2010-05-29 07:25:38 +00:00
delete p;
p = 0;
}
return p;
}
};
2010-08-05 18:26:03 +00:00
IStorage *CreateStorage(const char *pApplicationName, int NumArgs, const char **ppArguments) { return CStorage::Create(pApplicationName, NumArgs, ppArguments); }