mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-07-03 06:24:32 +00:00
Revert "added partial VFS support - enough to read static data from any source"
This reverts commit fa3e9e7329
.
This commit is contained in:
parent
fa3e9e7329
commit
56c6833220
56 changed files with 608 additions and 4023 deletions
|
@ -24,7 +24,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include "ScriptedEntity.h"
|
#include "ScriptedEntity.h"
|
||||||
#include "AutoMap.h"
|
#include "AutoMap.h"
|
||||||
#include "GridRender.h"
|
#include "GridRender.h"
|
||||||
#include <VFSFile.h>
|
|
||||||
|
|
||||||
#include "tinyxml.h"
|
#include "tinyxml.h"
|
||||||
|
|
||||||
|
@ -871,7 +870,7 @@ void Continuity::loadTreasureData()
|
||||||
std::string line, gfx;
|
std::string line, gfx;
|
||||||
int num, use;
|
int num, use;
|
||||||
float sz;
|
float sz;
|
||||||
VFSTextStdStreamIn in2("data/treasures.txt");
|
std::ifstream in2("data/treasures.txt");
|
||||||
while (std::getline(in2, line))
|
while (std::getline(in2, line))
|
||||||
{
|
{
|
||||||
std::istringstream is(line);
|
std::istringstream is(line);
|
||||||
|
@ -904,7 +903,7 @@ void Continuity::loadIngredientData()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
int num;
|
int num;
|
||||||
VFSTextStreamIn in2("data/ingredientdescriptions.txt");
|
std::ifstream in2("data/ingredientdescriptions.txt");
|
||||||
while (std::getline(in2, line))
|
while (std::getline(in2, line))
|
||||||
{
|
{
|
||||||
IngredientDescription desc;
|
IngredientDescription desc;
|
||||||
|
@ -917,7 +916,7 @@ void Continuity::loadIngredientData()
|
||||||
clearIngredientData();
|
clearIngredientData();
|
||||||
recipes.clear();
|
recipes.clear();
|
||||||
|
|
||||||
VFSTextStdStreamIn in("data/ingredients.txt");
|
std::ifstream in("data/ingredients.txt");
|
||||||
|
|
||||||
bool recipes = false;
|
bool recipes = false;
|
||||||
while (std::getline(in, line))
|
while (std::getline(in, line))
|
||||||
|
@ -1242,7 +1241,7 @@ void Continuity::loadEatBank()
|
||||||
{
|
{
|
||||||
eats.clear();
|
eats.clear();
|
||||||
|
|
||||||
VFSTextStdStreamIn inf("data/eats.txt");
|
std::ifstream inf("data/eats.txt");
|
||||||
|
|
||||||
EatData curData;
|
EatData curData;
|
||||||
std::string read;
|
std::string read;
|
||||||
|
@ -2182,7 +2181,7 @@ void Continuity::setActivePet(int flag)
|
||||||
void Continuity::loadPetData()
|
void Continuity::loadPetData()
|
||||||
{
|
{
|
||||||
petData.clear();
|
petData.clear();
|
||||||
VFSTextStdStreamIn in("data/pets.txt");
|
std::ifstream in("data/pets.txt");
|
||||||
std::string read;
|
std::string read;
|
||||||
while (std::getline(in, read))
|
while (std::getline(in, read))
|
||||||
{
|
{
|
||||||
|
@ -3260,7 +3259,7 @@ void Continuity::reset()
|
||||||
health = maxHealth;
|
health = maxHealth;
|
||||||
|
|
||||||
speedTypes.clear();
|
speedTypes.clear();
|
||||||
VFSTextStreamIn inFile("data/speedtypes.txt");
|
std::ifstream inFile("data/speedtypes.txt");
|
||||||
int n, spd;
|
int n, spd;
|
||||||
while (inFile >> n)
|
while (inFile >> n)
|
||||||
{
|
{
|
||||||
|
|
129
Aquaria/DSQ.cpp
129
Aquaria/DSQ.cpp
|
@ -172,6 +172,28 @@ DSQ::DSQ(std::string fileSystem) : Core(fileSystem, LR_MAX, APPNAME, PARTICLE_AM
|
||||||
almb = armb = 0;
|
almb = armb = 0;
|
||||||
bar_left = bar_right = bar_up = bar_down = barFade_left = barFade_right = 0;
|
bar_left = bar_right = bar_up = bar_down = barFade_left = barFade_right = 0;
|
||||||
|
|
||||||
|
// do copy stuff
|
||||||
|
#ifdef BBGE_BUILD_UNIX
|
||||||
|
std::string fn;
|
||||||
|
fn = getPreferencesFolder() + "/" + userSettingsFilename;
|
||||||
|
if (!exists(fn))
|
||||||
|
Linux_CopyTree(core->adjustFilenameCase(userSettingsFilename).c_str(), core->adjustFilenameCase(fn).c_str());
|
||||||
|
|
||||||
|
fn = getUserDataFolder() + "/_mods";
|
||||||
|
if (!exists(fn))
|
||||||
|
Linux_CopyTree(core->adjustFilenameCase("_mods").c_str(), core->adjustFilenameCase(fn).c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(BBGE_BUILD_UNIX)
|
||||||
|
std::string p1 = getUserDataFolder();
|
||||||
|
std::string p2 = getUserDataFolder() + "/save";
|
||||||
|
mkdir(p1.c_str(), S_IRWXU);
|
||||||
|
mkdir(p2.c_str(), S_IRWXU);
|
||||||
|
|
||||||
|
//debugLogPath = ;
|
||||||
|
#endif
|
||||||
|
|
||||||
difficulty = DIFF_NORMAL;
|
difficulty = DIFF_NORMAL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -209,6 +231,9 @@ DSQ::DSQ(std::string fileSystem) : Core(fileSystem, LR_MAX, APPNAME, PARTICLE_AM
|
||||||
achievement_box = 0;
|
achievement_box = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
vars = &v;
|
||||||
|
v.load();
|
||||||
|
|
||||||
#ifdef AQUARIA_BUILD_CONSOLE
|
#ifdef AQUARIA_BUILD_CONSOLE
|
||||||
console = 0;
|
console = 0;
|
||||||
#endif
|
#endif
|
||||||
|
@ -230,6 +255,25 @@ DSQ::DSQ(std::string fileSystem) : Core(fileSystem, LR_MAX, APPNAME, PARTICLE_AM
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
firstElementOnLayer[i] = 0;
|
firstElementOnLayer[i] = 0;
|
||||||
|
|
||||||
|
addStateInstance(game = new Game);
|
||||||
|
addStateInstance(new GameOver);
|
||||||
|
#ifdef AQUARIA_BUILD_SCENEEDITOR
|
||||||
|
addStateInstance(new AnimationEditor);
|
||||||
|
#endif
|
||||||
|
addStateInstance(new Intro2);
|
||||||
|
addStateInstance(new BitBlotLogo);
|
||||||
|
#ifdef AQUARIA_BUILD_SCENEEDITOR
|
||||||
|
addStateInstance(new ParticleEditor);
|
||||||
|
#endif
|
||||||
|
addStateInstance(new Credits);
|
||||||
|
addStateInstance(new Intro);
|
||||||
|
addStateInstance(new Nag);
|
||||||
|
|
||||||
|
//addStateInstance(new Logo);
|
||||||
|
//addStateInstance(new SCLogo);
|
||||||
|
//addStateInstance(new IntroText);
|
||||||
|
//addStateInstance(new Intro);
|
||||||
|
|
||||||
//stream = 0;
|
//stream = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +343,7 @@ void DSQ::newGame()
|
||||||
|
|
||||||
void DSQ::loadElementEffects()
|
void DSQ::loadElementEffects()
|
||||||
{
|
{
|
||||||
VFSTextStdStreamIn inFile("data/elementeffects.txt");
|
std::ifstream inFile("data/elementeffects.txt");
|
||||||
elementEffects.clear();
|
elementEffects.clear();
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(inFile, line))
|
while (std::getline(inFile, line))
|
||||||
|
@ -871,55 +915,6 @@ static bool sdlVideoModeOK(const int w, const int h, const int bpp)
|
||||||
|
|
||||||
void DSQ::init()
|
void DSQ::init()
|
||||||
{
|
{
|
||||||
setupVFS(getenv("AQUARIA_DATA_PATH"));
|
|
||||||
|
|
||||||
// FG: TODO: do the moving & copying below with VFS code, and leave the original file system alone!
|
|
||||||
|
|
||||||
// do copy stuff
|
|
||||||
#ifdef BBGE_BUILD_UNIX
|
|
||||||
std::string fn;
|
|
||||||
fn = getPreferencesFolder() + "/" + userSettingsFilename;
|
|
||||||
if (!exists(fn))
|
|
||||||
Linux_CopyTree(core->adjustFilenameCase(userSettingsFilename).c_str(), core->adjustFilenameCase(fn).c_str());
|
|
||||||
|
|
||||||
fn = getUserDataFolder() + "/_mods";
|
|
||||||
if (!exists(fn))
|
|
||||||
Linux_CopyTree(core->adjustFilenameCase("_mods").c_str(), core->adjustFilenameCase(fn).c_str());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(BBGE_BUILD_UNIX)
|
|
||||||
std::string p1 = getUserDataFolder();
|
|
||||||
std::string p2 = getUserDataFolder() + "/save";
|
|
||||||
mkdir(p1.c_str(), S_IRWXU);
|
|
||||||
mkdir(p2.c_str(), S_IRWXU);
|
|
||||||
|
|
||||||
//debugLogPath = ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
vars = &v;
|
|
||||||
v.load();
|
|
||||||
|
|
||||||
addStateInstance(game = new Game);
|
|
||||||
addStateInstance(new GameOver);
|
|
||||||
#ifdef AQUARIA_BUILD_SCENEEDITOR
|
|
||||||
addStateInstance(new AnimationEditor);
|
|
||||||
#endif
|
|
||||||
addStateInstance(new Intro2);
|
|
||||||
addStateInstance(new BitBlotLogo);
|
|
||||||
#ifdef AQUARIA_BUILD_SCENEEDITOR
|
|
||||||
addStateInstance(new ParticleEditor);
|
|
||||||
#endif
|
|
||||||
addStateInstance(new Credits);
|
|
||||||
addStateInstance(new Intro);
|
|
||||||
addStateInstance(new Nag);
|
|
||||||
|
|
||||||
//addStateInstance(new Logo);
|
|
||||||
//addStateInstance(new SCLogo);
|
|
||||||
//addStateInstance(new IntroText);
|
|
||||||
//addStateInstance(new Intro);
|
|
||||||
|
|
||||||
|
|
||||||
core->settings.runInBackground = true;
|
core->settings.runInBackground = true;
|
||||||
|
|
||||||
weird = 0;
|
weird = 0;
|
||||||
|
@ -2170,13 +2165,6 @@ ModEntry* DSQ::getSelectedModEntry()
|
||||||
void DSQ::loadMods()
|
void DSQ::loadMods()
|
||||||
{
|
{
|
||||||
modEntries.clear();
|
modEntries.clear();
|
||||||
|
|
||||||
// force VFS to reload _mods dir
|
|
||||||
if(ttvfs::VFSDir *vd = vfs.GetDir("_mods"))
|
|
||||||
{
|
|
||||||
vd->load();
|
|
||||||
vfs.Reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
forEachFile(mod.getBaseModPath(), ".xml", loadModsCallback, 0);
|
forEachFile(mod.getBaseModPath(), ".xml", loadModsCallback, 0);
|
||||||
selectedMod = 0;
|
selectedMod = 0;
|
||||||
|
@ -3687,7 +3675,7 @@ void DSQ::onPlayVoice()
|
||||||
if (user.audio.subtitles)
|
if (user.audio.subtitles)
|
||||||
{
|
{
|
||||||
std::string fn = "scripts/vox/" + sound->lastVoice + ".txt";
|
std::string fn = "scripts/vox/" + sound->lastVoice + ".txt";
|
||||||
VFSTextStdStreamIn inf(fn.c_str());
|
std::ifstream inf(fn.c_str());
|
||||||
if (inf.is_open())
|
if (inf.is_open())
|
||||||
{
|
{
|
||||||
std::string dia;
|
std::string dia;
|
||||||
|
@ -3780,6 +3768,31 @@ std::string DSQ::getDialogueFilename(const std::string &f)
|
||||||
return "dialogue/" + languagePack + "/" + f + ".txt";
|
return "dialogue/" + languagePack + "/" + f + ".txt";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DSQ::jumpToSection(std::ifstream &inFile, const std::string §ion)
|
||||||
|
{
|
||||||
|
if (section.empty()) return;
|
||||||
|
std::string file = dsq->getDialogueFilename(dialogueFile);
|
||||||
|
if (!exists(file))
|
||||||
|
{
|
||||||
|
debugLog("Could not find dialogue [" + file + "]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inFile.open(core->adjustFilenameCase(file).c_str());
|
||||||
|
std::string s;
|
||||||
|
while (std::getline(inFile, s))
|
||||||
|
{
|
||||||
|
if (!s.empty())
|
||||||
|
{
|
||||||
|
if (s.find("[")!=std::string::npos && s.find(section) != std::string::npos)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debugLog("could not find section [" + section + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DSQ::runGesture(const std::string &line)
|
void DSQ::runGesture(const std::string &line)
|
||||||
{
|
{
|
||||||
std::istringstream is(line);
|
std::istringstream is(line);
|
||||||
|
|
|
@ -1395,6 +1395,8 @@ public:
|
||||||
void takeScreenshot();
|
void takeScreenshot();
|
||||||
void takeScreenshotKey();
|
void takeScreenshotKey();
|
||||||
|
|
||||||
|
void jumpToSection(std::ifstream &inFile, const std::string §ion);
|
||||||
|
|
||||||
PathFinding pathFinding;
|
PathFinding pathFinding;
|
||||||
void runGesture(const std::string &line);
|
void runGesture(const std::string &line);
|
||||||
void generateCollisionMask(RenderObject *r);
|
void generateCollisionMask(RenderObject *r);
|
||||||
|
|
|
@ -31,7 +31,7 @@ Emote::Emote()
|
||||||
void Emote::load(const std::string &file)
|
void Emote::load(const std::string &file)
|
||||||
{
|
{
|
||||||
emotes.clear();
|
emotes.clear();
|
||||||
VFSTextStdStreamIn in(file.c_str());
|
std::ifstream in(file.c_str());
|
||||||
std::string line;
|
std::string line;
|
||||||
|
|
||||||
while (std::getline(in, line))
|
while (std::getline(in, line))
|
||||||
|
|
|
@ -39,7 +39,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include "StatsAndAchievements.h"
|
#include "StatsAndAchievements.h"
|
||||||
|
|
||||||
#include "ToolTip.h"
|
#include "ToolTip.h"
|
||||||
#include <VFSFile.h>
|
|
||||||
|
|
||||||
std::vector<std::string> allowedMaps;
|
std::vector<std::string> allowedMaps;
|
||||||
|
|
||||||
|
@ -254,7 +253,7 @@ void FoodHolder::setIngredient(IngredientData *i, bool effects)
|
||||||
if (effects)
|
if (effects)
|
||||||
{
|
{
|
||||||
core->sound->playSfx("Wok");
|
core->sound->playSfx("Wok");
|
||||||
|
|
||||||
ing->scale.ensureData();
|
ing->scale.ensureData();
|
||||||
ing->scale.data->path.clear();
|
ing->scale.data->path.clear();
|
||||||
ing->scale.data->path.addPathNode(Vector(1,1),0);
|
ing->scale.data->path.addPathNode(Vector(1,1),0);
|
||||||
|
@ -2517,7 +2516,7 @@ void Game::loadEntityTypeList()
|
||||||
// and group list!
|
// and group list!
|
||||||
{
|
{
|
||||||
entityTypeList.clear();
|
entityTypeList.clear();
|
||||||
VFSTextStdStreamIn in("scripts/entities/entities.txt");
|
std::ifstream in("scripts/entities/entities.txt");
|
||||||
std::string line;
|
std::string line;
|
||||||
if(!in)
|
if(!in)
|
||||||
{
|
{
|
||||||
|
@ -2550,7 +2549,7 @@ void Game::loadEntityTypeList()
|
||||||
fn = dsq->mod.getPath() + "entitygroups.txt";
|
fn = dsq->mod.getPath() + "entitygroups.txt";
|
||||||
}
|
}
|
||||||
|
|
||||||
VFSTextStdStreamIn in2(fn.c_str());
|
std::ifstream in2(fn.c_str());
|
||||||
|
|
||||||
int curGroup=0;
|
int curGroup=0;
|
||||||
while (std::getline(in2, line))
|
while (std::getline(in2, line))
|
||||||
|
@ -5404,7 +5403,7 @@ void Game::findMaxCameraValues()
|
||||||
|
|
||||||
void Game::setWarpAreaSceneName(WarpArea &warpArea)
|
void Game::setWarpAreaSceneName(WarpArea &warpArea)
|
||||||
{
|
{
|
||||||
VFSTextStdStreamIn in("data/warpAreas.txt");
|
std::ifstream in("data/warpAreas.txt");
|
||||||
std::string color, area1, dir1, area2, dir2;
|
std::string color, area1, dir1, area2, dir2;
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(in, line))
|
while (std::getline(in, line))
|
||||||
|
@ -7934,9 +7933,9 @@ void Game::onFlipTest()
|
||||||
|
|
||||||
void appendFileToString(std::string &string, const std::string &file)
|
void appendFileToString(std::string &string, const std::string &file)
|
||||||
{
|
{
|
||||||
VFSTextStdStreamIn inf(file.c_str());
|
std::ifstream inf(file.c_str());
|
||||||
|
|
||||||
if (inf)
|
if (inf.is_open())
|
||||||
{
|
{
|
||||||
while (!inf.eof())
|
while (!inf.eof())
|
||||||
{
|
{
|
||||||
|
@ -10946,7 +10945,7 @@ void Game::loadElementTemplates(std::string pack)
|
||||||
tileCache.clean();
|
tileCache.clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
VFSTextStdStreamIn in(fn.c_str());
|
std::ifstream in(fn.c_str());
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(in, line))
|
while (std::getline(in, line))
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,13 +24,12 @@ GameplayVariables *vars = 0;
|
||||||
|
|
||||||
void GameplayVariables::load()
|
void GameplayVariables::load()
|
||||||
{
|
{
|
||||||
VFSTextStreamIn inFile("data/variables.txt");
|
std::ifstream inFile("data/variables.txt");
|
||||||
if(!inFile)
|
if(!inFile)
|
||||||
{
|
{
|
||||||
core->messageBox("error", "Variables data not found! Aborting...");
|
core->messageBox("error", "Variables data not found! Aborting...");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string s;
|
std::string s;
|
||||||
inFile >> s >> maxSlowSwimSpeed;
|
inFile >> s >> maxSlowSwimSpeed;
|
||||||
inFile >> s >> maxSwimSpeed;
|
inFile >> s >> maxSwimSpeed;
|
||||||
|
|
|
@ -41,10 +41,10 @@ static void StartAQConfig()
|
||||||
{
|
{
|
||||||
#if defined(BBGE_BUILD_WINDOWS)
|
#if defined(BBGE_BUILD_WINDOWS)
|
||||||
#if defined(AQUARIA_DEMO) || defined(AQUARIA_FULL)
|
#if defined(AQUARIA_DEMO) || defined(AQUARIA_FULL)
|
||||||
if (!exists("ran", false, true))
|
if (!exists("ran", false))
|
||||||
{
|
{
|
||||||
MakeRan();
|
MakeRan();
|
||||||
if(exists("aqconfig.exe", false, true))
|
if(exists("aqconfig.exe", false))
|
||||||
{
|
{
|
||||||
ShellExecute(NULL, "open", "aqconfig.exe", NULL, NULL, SW_SHOWNORMAL);
|
ShellExecute(NULL, "open", "aqconfig.exe", NULL, NULL, SW_SHOWNORMAL);
|
||||||
exit(0);
|
exit(0);
|
||||||
|
@ -58,7 +58,7 @@ static void StartAQConfig()
|
||||||
static void CheckConfig(void)
|
static void CheckConfig(void)
|
||||||
{
|
{
|
||||||
#ifdef BBGE_BUILD_WINDOWS
|
#ifdef BBGE_BUILD_WINDOWS
|
||||||
bool hasCfg = exists("usersettings.xml", false, true);
|
bool hasCfg = exists("usersettings.xml", false);
|
||||||
if(!hasCfg)
|
if(!hasCfg)
|
||||||
StartAQConfig();
|
StartAQConfig();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -529,7 +529,7 @@ luaFunc(indexWarnGlobal)
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << "WARNING: " << ar.short_src << ":" << ar.currentline
|
os << "WARNING: " << ar.short_src << ":" << ar.currentline
|
||||||
<< ": script tried to get/call undefined global variable "
|
<< ": script tried to get/call undefined global variable "
|
||||||
<< varname;
|
<< lua_tostring(L, -2);
|
||||||
errorLog(os.str());
|
errorLog(os.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,19 +614,7 @@ luaFunc(dofile_caseinsensitive)
|
||||||
// This is Lua's dofile(), with some tweaks. --ryan.
|
// This is Lua's dofile(), with some tweaks. --ryan.
|
||||||
std::string fname(core->adjustFilenameCase(luaL_checkstring(L, 1)));
|
std::string fname(core->adjustFilenameCase(luaL_checkstring(L, 1)));
|
||||||
int n = lua_gettop(L);
|
int n = lua_gettop(L);
|
||||||
|
if (luaL_loadfile(L, fname.c_str()) != 0) lua_error(L);
|
||||||
int result = -1;
|
|
||||||
ttvfs::VFSFile *vf = core->vfs.GetFile(fname.c_str());
|
|
||||||
if(vf)
|
|
||||||
{
|
|
||||||
const char *buf = (const char*)vf->getBuf();
|
|
||||||
result = luaL_loadbuffer(L, buf, vf->size(), fname.c_str());
|
|
||||||
vf->dropBuf(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(result)
|
|
||||||
lua_error(L);
|
|
||||||
|
|
||||||
lua_call(L, 0, LUA_MULTRET);
|
lua_call(L, 0, LUA_MULTRET);
|
||||||
return lua_gettop(L) - n;
|
return lua_gettop(L) - n;
|
||||||
}
|
}
|
||||||
|
@ -8953,20 +8941,11 @@ Script *ScriptInterface::openScript(const std::string &file)
|
||||||
lua_getglobal(baseState, "v");
|
lua_getglobal(baseState, "v");
|
||||||
|
|
||||||
// Load the file itself. This leaves the Lua chunk on the stack.
|
// Load the file itself. This leaves the Lua chunk on the stack.
|
||||||
int result = -1;
|
int result = luaL_loadfile(baseState, realFile.c_str());
|
||||||
ttvfs::VFSFile *vf = core->vfs.GetFile(realFile.c_str());
|
|
||||||
if(vf)
|
|
||||||
{
|
|
||||||
const char *buf = (const char*)vf->getBuf();
|
|
||||||
result = luaL_loadbuffer(baseState, buf, vf->size(), realFile.c_str());
|
|
||||||
vf->dropBuf(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
{
|
{
|
||||||
const char *msg = lua_tostring(baseState, -1);
|
debugLog("Error loading script [" + realFile + "]: " + lua_tostring(baseState, -1));
|
||||||
debugLog("Error loading script [" + realFile + "]: " + (msg ? msg : "unk error")); // loading from buffer does not push a string on the stack
|
lua_pop(baseState, 2);
|
||||||
//lua_pop(baseState, 2);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
#include "../BBGE/MathFunctions.h"
|
#include "../BBGE/MathFunctions.h"
|
||||||
|
|
||||||
#include <VFSFile.h>
|
|
||||||
|
|
||||||
Shot::Shots Shot::shots;
|
Shot::Shots Shot::shots;
|
||||||
Shot::ShotBank Shot::shotBank;
|
Shot::ShotBank Shot::shotBank;
|
||||||
|
|
||||||
|
@ -66,7 +64,7 @@ ShotData::ShotData()
|
||||||
ignoreShield = false;
|
ignoreShield = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> void readEquals2(T &in)
|
void readEquals2(std::ifstream &in)
|
||||||
{
|
{
|
||||||
std::string temp;
|
std::string temp;
|
||||||
in >> temp;
|
in >> temp;
|
||||||
|
@ -95,7 +93,7 @@ void ShotData::bankLoad(const std::string &file, const std::string &path)
|
||||||
}
|
}
|
||||||
|
|
||||||
debugLog(usef);
|
debugLog(usef);
|
||||||
VFSTextStreamIn inf(usef.c_str());
|
std::ifstream inf(usef.c_str());
|
||||||
std::string token;
|
std::string token;
|
||||||
while (inf >> token)
|
while (inf >> token)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,7 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Avatar.h"
|
#include "Avatar.h"
|
||||||
#include "StatsAndAchievements.h"
|
#include "StatsAndAchievements.h"
|
||||||
#include <VFSFile.h>
|
|
||||||
|
|
||||||
#ifndef ARRAYSIZE
|
#ifndef ARRAYSIZE
|
||||||
#define ARRAYSIZE(x) (sizeof (x) / sizeof ((x)[0]))
|
#define ARRAYSIZE(x) (sizeof (x) / sizeof ((x)[0]))
|
||||||
|
@ -172,50 +171,46 @@ void StatsAndAchievements::RunFrame()
|
||||||
requestedStats = true;
|
requestedStats = true;
|
||||||
|
|
||||||
const size_t max_achievements = ARRAYSIZE(g_rgAchievements);
|
const size_t max_achievements = ARRAYSIZE(g_rgAchievements);
|
||||||
|
FILE *io = NULL;
|
||||||
|
|
||||||
char *achtxt = "";
|
// Get generic achievement data...
|
||||||
VFSTextStdStreamIn in("data/achievements.txt");
|
io = fopen("data/achievements.txt", "r");
|
||||||
std::string line;
|
char line[1024];
|
||||||
|
for (size_t i = 0; i < max_achievements; i++)
|
||||||
|
{
|
||||||
|
if (!io || (fgets(line, sizeof (line), io) == NULL))
|
||||||
|
snprintf(line, sizeof (line), "Achievement #%d", (int) i);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (char *ptr = (line + strlen(line)) - 1; (ptr >= line) && ((*ptr == '\r') || (*ptr == '\n')); ptr--)
|
||||||
|
*ptr = '\0';
|
||||||
|
}
|
||||||
|
line[sizeof (g_rgAchievements[i].name) - 1] = '\0'; // just in case.
|
||||||
|
strcpy(g_rgAchievements[i].name, line);
|
||||||
|
|
||||||
// HACK: prepare fields in case data are missing
|
if (!io || (fgets(line, sizeof (line), io) == NULL))
|
||||||
for(int i = 0; i < max_achievements; ++i)
|
snprintf(line, sizeof (line), "[Description of Achievement #%d is missing!]", (int) i);
|
||||||
{
|
else
|
||||||
g_rgAchievements[i].iconImage = 0;
|
{
|
||||||
g_rgAchievements[i].name[sizeof (g_rgAchievements[i].name) - 1] = '\0'; // just in case.
|
for (char *ptr = (line + strlen(line)) - 1; (ptr >= line) && ((*ptr == '\r') || (*ptr == '\n')); ptr--)
|
||||||
g_rgAchievements[i].desc[sizeof (g_rgAchievements[i].desc) - 1] = '\0';
|
*ptr = '\0';
|
||||||
snprintf(g_rgAchievements[i].name, sizeof(g_rgAchievements[i].name), "Achievement #%d", i);
|
}
|
||||||
snprintf(g_rgAchievements[i].desc, sizeof(g_rgAchievements[i].desc), "[Description of Achievement #%d is missing!]", i);
|
line[sizeof (g_rgAchievements[i].desc) - 1] = '\0'; // just in case.
|
||||||
}
|
strcpy(g_rgAchievements[i].desc, line);
|
||||||
|
|
||||||
// read 2 lines per achievement
|
// unsupported at the moment.
|
||||||
int x = 0;
|
g_rgAchievements[i].iconImage = 0;
|
||||||
int ach = 0;
|
}
|
||||||
while(std::getline(in, line))
|
|
||||||
{
|
|
||||||
for (char *ptr = const_cast<char*>(line.c_str() + line.length()) - 1; (ptr >= line) && ((*ptr == '\r') || (*ptr == '\n')); ptr--)
|
|
||||||
*ptr = '\0';
|
|
||||||
|
|
||||||
switch(x)
|
if (io != NULL)
|
||||||
{
|
fclose(io);
|
||||||
case 0:
|
|
||||||
strncpy(g_rgAchievements[ach].name, line.c_str(), sizeof(g_rgAchievements[ach].name) - 1);
|
|
||||||
++x;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
strncpy(g_rgAchievements[ach].desc, line.c_str(), sizeof(g_rgAchievements[ach].desc) - 1);
|
|
||||||
x = 0;
|
|
||||||
++ach;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// See what this specific player has achieved...
|
// See what this specific player has achieved...
|
||||||
// FG: TODO: use VFS here!
|
|
||||||
|
|
||||||
unsigned char *buf = new unsigned char[max_achievements];
|
unsigned char *buf = new unsigned char[max_achievements];
|
||||||
size_t br = 0;
|
size_t br = 0;
|
||||||
const std::string fname(core->getUserDataFolder() + "/achievements.bin");
|
const std::string fname(core->getUserDataFolder() + "/achievements.bin");
|
||||||
FILE *io = fopen(fname.c_str(), "rb");
|
io = fopen(fname.c_str(), "rb");
|
||||||
if (io == NULL)
|
if (io == NULL)
|
||||||
statsValid = true; // nothing to report.
|
statsValid = true; // nothing to report.
|
||||||
else
|
else
|
||||||
|
|
|
@ -29,7 +29,7 @@ void StringBank::load(const std::string &file)
|
||||||
//debugLog("StringBank::load("+file+")");
|
//debugLog("StringBank::load("+file+")");
|
||||||
stringMap.clear();
|
stringMap.clear();
|
||||||
|
|
||||||
VFSTextStdStreamIn in(file.c_str());
|
std::ifstream in(file.c_str());
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
int idx;
|
int idx;
|
||||||
|
|
|
@ -61,7 +61,7 @@ void SubtitlePlayer::go(const std::string &subs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VFSTextStdStreamIn in(f.c_str());
|
std::ifstream in(f.c_str());
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(in, line))
|
while (std::getline(in, line))
|
||||||
{
|
{
|
||||||
|
|
|
@ -246,7 +246,7 @@ void WorldMap::load(const std::string &file)
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
|
|
||||||
VFSTextStdStreamIn in(file.c_str());
|
std::ifstream in(file.c_str());
|
||||||
|
|
||||||
while (std::getline(in, line))
|
while (std::getline(in, line))
|
||||||
{
|
{
|
||||||
|
@ -261,7 +261,6 @@ void WorldMap::load(const std::string &file)
|
||||||
|
|
||||||
void WorldMap::save(const std::string &file)
|
void WorldMap::save(const std::string &file)
|
||||||
{
|
{
|
||||||
// FG: TODO: use VFS here!
|
|
||||||
std::ofstream out(file.c_str());
|
std::ofstream out(file.c_str());
|
||||||
|
|
||||||
for (int i = 0; i < worldMapTiles.size(); i++)
|
for (int i = 0; i < worldMapTiles.size(); i++)
|
||||||
|
|
328
BBGE/Base.cpp
328
BBGE/Base.cpp
|
@ -20,7 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
#include "Core.h"
|
#include "Core.h"
|
||||||
#include "VFSDir.h"
|
|
||||||
|
|
||||||
#ifdef BBGE_BUILD_WINDOWS
|
#ifdef BBGE_BUILD_WINDOWS
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
@ -273,28 +272,30 @@ std::string upperCase(const std::string &s1)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool exists(const std::string &f, bool makeFatal /* = false */, bool skipVFS /* = false */)
|
bool exists(const std::string &f, bool makeFatal)
|
||||||
{
|
{
|
||||||
if (f.empty())
|
/*
|
||||||
return false;
|
if (!PHYSFS_exists(f.c_str()))
|
||||||
|
|
||||||
if(!skipVFS)
|
|
||||||
{
|
|
||||||
if(core->vfs.GetFile(core->adjustFilenameCase(f).c_str()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *file = fopen(core->adjustFilenameCase(f).c_str(), "rb");
|
|
||||||
if (!file)
|
|
||||||
{
|
{
|
||||||
if (makeFatal)
|
*/
|
||||||
|
/*
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "checking to see if [" << f << "] exists";
|
||||||
|
debugLog(os.str());
|
||||||
|
*/
|
||||||
|
|
||||||
|
FILE *file = fopen(core->adjustFilenameCase(f).c_str(), "rb");
|
||||||
|
if (!file)
|
||||||
{
|
{
|
||||||
errorLog(std::string("Could not open [" + f + "]"));
|
if (makeFatal)
|
||||||
exit(0);
|
{
|
||||||
|
errorLog(std::string("Could not open [" + f + "]"));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
fclose(file);
|
||||||
}
|
//}
|
||||||
fclose(file);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,20 +448,107 @@ void debugLog(const std::string &s)
|
||||||
// delete[] when no longer needed.
|
// delete[] when no longer needed.
|
||||||
char *readFile(std::string path, unsigned long *size_ret)
|
char *readFile(std::string path, unsigned long *size_ret)
|
||||||
{
|
{
|
||||||
ttvfs::VFSFile *vf = core->vfs.GetFile(path.c_str());
|
FILE *f = fopen(path.c_str(), "rb");
|
||||||
if(!vf)
|
if (!f)
|
||||||
return NULL;
|
return NULL;
|
||||||
vf->getBuf(); // force size calc early
|
|
||||||
// we can never know how the memory was allocated;
|
long fileSize;
|
||||||
// because the buffer is expected to be deleted with delete[],
|
if (fseek(f, 0, SEEK_END) != 0
|
||||||
// it has to be explicitly copied to memory allocated with new[].
|
|| (fileSize = ftell(f)) < 0
|
||||||
unsigned long s = vf->size();
|
|| fseek(f, 0, SEEK_SET) != 0)
|
||||||
char *buf = new char[s + 1];
|
{
|
||||||
memcpy(buf, vf->getBuf(), s + 1);
|
debugLog(path + ": Failed to get file size");
|
||||||
core->addVFSFileForDrop(vf);
|
fclose(f);
|
||||||
if(size_ret)
|
return NULL;
|
||||||
*size_ret = s;
|
}
|
||||||
return buf;
|
|
||||||
|
char *buffer = new char[fileSize + 1];
|
||||||
|
if (!buffer)
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << path << ": Not enough memory for file ("
|
||||||
|
<< (fileSize+1) << " bytes)";
|
||||||
|
debugLog(os.str());
|
||||||
|
fclose(f);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
long bytesRead = fread(buffer, 1, fileSize, f);
|
||||||
|
if (bytesRead != fileSize)
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << path << ": Failed to read file (only got "
|
||||||
|
<< bytesRead << " of " << fileSize << " bytes)";
|
||||||
|
debugLog(os.str());
|
||||||
|
fclose(f);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
if (size_ret)
|
||||||
|
*size_ret = fileSize;
|
||||||
|
buffer[fileSize] = 0;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void pForEachFile(std::string path, std::string type, void callback(const std::string &filename, int param), int param)
|
||||||
|
{
|
||||||
|
char **rc = PHYSFS_enumerateFiles(path.c_str());
|
||||||
|
char **i;
|
||||||
|
|
||||||
|
for (i = rc; *i != NULL; i++)
|
||||||
|
{
|
||||||
|
std::string s(*i);
|
||||||
|
int p=0;
|
||||||
|
if ((p=s.find('.'))!=std::string::npos)
|
||||||
|
{
|
||||||
|
std::string ext = s.susbtr(p, s.getLength2D());
|
||||||
|
if (ext == type)
|
||||||
|
{
|
||||||
|
callback(fielnameafhghaha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PHYSFS_freeList(rc);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void doSingleFile(const std::string &path, const std::string &type, std::string filename, void callback(const std::string &filename, int param), int param)
|
||||||
|
{
|
||||||
|
if (filename.size()>4)
|
||||||
|
{
|
||||||
|
std::string search = filename;
|
||||||
|
stringToLower(search);
|
||||||
|
std::string filetype = filename.substr(search.size()-4, search.size());
|
||||||
|
//stringToUpper(filetype);
|
||||||
|
//debugLog("comparing: " + filetype + " and: " + type);
|
||||||
|
//if (filetype==type)
|
||||||
|
debugLog("checking:" + search + " for type:" + type);
|
||||||
|
if (search.find(type)!=std::string::npos)
|
||||||
|
{
|
||||||
|
debugLog("callback");
|
||||||
|
callback(path+filename, param);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debugLog("not the same");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string stripEndlineForUnix(const std::string &in)
|
||||||
|
{
|
||||||
|
std::string out;
|
||||||
|
for (int i = 0; i < in.size(); i++)
|
||||||
|
{
|
||||||
|
if (int(in[i]) != 13)
|
||||||
|
{
|
||||||
|
out+= in[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void forEachFile(std::string path, std::string type, void callback(const std::string &filename, intptr_t param), intptr_t param)
|
void forEachFile(std::string path, std::string type, void callback(const std::string &filename, intptr_t param), intptr_t param)
|
||||||
|
@ -472,29 +560,167 @@ void forEachFile(std::string path, std::string type, void callback(const std::st
|
||||||
//HACK: MAC:
|
//HACK: MAC:
|
||||||
debugLog("forEachFile - path: " + path + " type: " + type);
|
debugLog("forEachFile - path: " + path + " type: " + type);
|
||||||
|
|
||||||
ttvfs::VFSDir *vd = core->vfs.GetDir(path.c_str(), false);
|
#if defined(BBGE_BUILD_UNIX)
|
||||||
if(!vd)
|
DIR *dir=0;
|
||||||
{
|
dir = opendir(path.c_str());
|
||||||
debugLog("Path '" + path + "' does not exist");
|
if (dir)
|
||||||
return;
|
{
|
||||||
}
|
dirent *file=0;
|
||||||
|
while ( (file=readdir(dir)) != NULL )
|
||||||
|
{
|
||||||
|
if (file->d_name && strlen(file->d_name) > 4)
|
||||||
|
{
|
||||||
|
debugLog(file->d_name);
|
||||||
|
char *extension=strrchr(file->d_name,'.');
|
||||||
|
if (extension)
|
||||||
|
{
|
||||||
|
debugLog(extension);
|
||||||
|
if (extension!=NULL)
|
||||||
|
{
|
||||||
|
if (strcasecmp(extension,type.c_str())==0)
|
||||||
|
{
|
||||||
|
callback(path + std::string(file->d_name), param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debugLog("FAILED TO OPEN DIR");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for(ttvfs::ConstFileIter it = vd->fileIter(); it != vd->fileIterEnd(); ++it)
|
#ifdef BBGE_BUILD_WINDOWS
|
||||||
|
BOOL fFinished;
|
||||||
|
HANDLE hList;
|
||||||
|
TCHAR szDir[MAX_PATH+1];
|
||||||
|
WIN32_FIND_DATA FileData;
|
||||||
|
|
||||||
|
int end = path.size()-1;
|
||||||
|
if (path[end] != '/')
|
||||||
|
path[end] += '/';
|
||||||
|
|
||||||
|
// Get the proper directory path
|
||||||
|
// \\ %s\\*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (type.find('.')==std::string::npos)
|
||||||
|
{
|
||||||
|
type = "." + type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//std::string add = "%s*" + type;
|
||||||
|
|
||||||
|
//sprintf(szDir, "%s*", path.c_str());
|
||||||
|
sprintf(szDir, "%s\\*", path.c_str());
|
||||||
|
|
||||||
|
stringToUpper(type);
|
||||||
|
|
||||||
|
// Get the first file
|
||||||
|
hList = FindFirstFile(szDir, &FileData);
|
||||||
|
if (hList == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
const ttvfs::VFSFile *f = it->second;
|
//printf("No files found\n\n");
|
||||||
const char *e = strrchr(f->name(), '.');
|
debugLog("No files of type " + type + " found in path " + path);
|
||||||
if (e)
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Traverse through the directory structure
|
||||||
|
fFinished = FALSE;
|
||||||
|
while (!fFinished)
|
||||||
{
|
{
|
||||||
std::string exs(e);
|
// Check the object is a directory or not
|
||||||
stringToLower(exs);
|
//printf("%*s%s\n", indent, "", FileData.cFileName);
|
||||||
if(exs != type)
|
std::string filename = FileData.cFileName;
|
||||||
continue;
|
//debugLog("found: " + filename);
|
||||||
}
|
if (filename.size()>4)
|
||||||
else if(type.size())
|
{
|
||||||
continue;
|
|
||||||
|
|
||||||
callback(path + f->name(), param);
|
std::string filetype = filename.substr(filename.size()-4, filename.size());
|
||||||
|
stringToUpper(filetype);
|
||||||
|
//debugLog("comparing: " + filetype + " and: " + type);
|
||||||
|
if (filetype==type)
|
||||||
|
{
|
||||||
|
callback(path+filename, param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!FindNextFile(hList, &FileData))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if (GetLastError() == ERROR_NO_MORE_FILES)
|
||||||
|
{
|
||||||
|
fFinished = TRUE;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
fFinished = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FindClose(hList);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> getFileList(std::string path, std::string type, int param)
|
||||||
|
{
|
||||||
|
std::vector<std::string> list;
|
||||||
|
|
||||||
|
#ifdef BBGE_BUILD_WINDOWS
|
||||||
|
BOOL fFinished;
|
||||||
|
HANDLE hList;
|
||||||
|
TCHAR szDir[MAX_PATH+1];
|
||||||
|
WIN32_FIND_DATA FileData;
|
||||||
|
|
||||||
|
// Get the proper directory path
|
||||||
|
sprintf(szDir, "%s\\*", path.c_str());
|
||||||
|
|
||||||
|
|
||||||
|
// Get the first file
|
||||||
|
hList = FindFirstFile(szDir, &FileData);
|
||||||
|
if (hList == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
printf("No files found\n\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Traverse through the directory structure
|
||||||
|
fFinished = FALSE;
|
||||||
|
while (!fFinished)
|
||||||
|
{
|
||||||
|
// Check the object is a directory or not
|
||||||
|
//printf("%*s%s\n", indent, "", FileData.cFileName);
|
||||||
|
std::string filename = FileData.cFileName;
|
||||||
|
if (filename.size()>4 && filename.substr(filename.size()-4, filename.size())==type)
|
||||||
|
{
|
||||||
|
//callback(path+filename, param);
|
||||||
|
list.push_back (filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!FindNextFile(hList, &FileData))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if (GetLastError() == ERROR_NO_MORE_FILES)
|
||||||
|
{
|
||||||
|
fFinished = TRUE;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
fFinished = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FindClose(hList);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string msg(const std::string &message)
|
std::string msg(const std::string &message)
|
||||||
|
|
17
BBGE/Base.h
17
BBGE/Base.h
|
@ -192,11 +192,13 @@ void stringToLower(std::string &s);
|
||||||
void stringToLowerUserData(std::string &s);
|
void stringToLowerUserData(std::string &s);
|
||||||
void glColor3_256(int r, int g, int b);
|
void glColor3_256(int r, int g, int b);
|
||||||
float sqr(float x);
|
float sqr(float x);
|
||||||
bool exists(const std::string &f, bool makeFatal = false, bool skipVFS = false);
|
bool exists(const std::string &f, bool makeFatal = false);
|
||||||
void errorLog(const std::string &s);
|
void errorLog(const std::string &s);
|
||||||
void debugLog(const std::string &s);
|
void debugLog(const std::string &s);
|
||||||
char *readFile(std::string path, unsigned long *size_ret = 0);
|
char *readFile(std::string path, unsigned long *size_ret = 0);
|
||||||
void forEachFile(std::string path, std::string type, void callback(const std::string &filename, intptr_t param), intptr_t param);
|
void forEachFile(std::string path, std::string type, void callback(const std::string &filename, intptr_t param), intptr_t param);
|
||||||
|
std::string stripEndlineForUnix(const std::string &in);
|
||||||
|
std::vector<std::string> getFileList(std::string path, std::string type, int param);
|
||||||
#ifdef HAVE_STRCASECMP
|
#ifdef HAVE_STRCASECMP
|
||||||
static inline int nocasecmp(const std::string &s1, const std::string &s2)
|
static inline int nocasecmp(const std::string &s1, const std::string &s2)
|
||||||
{ return strcasecmp(s1.c_str(), s2.c_str()); }
|
{ return strcasecmp(s1.c_str(), s2.c_str()); }
|
||||||
|
@ -223,6 +225,19 @@ Vector colorRGB(int r, int g, int b);
|
||||||
#endif
|
#endif
|
||||||
GLuint generateEmptyTexture(int res);
|
GLuint generateEmptyTexture(int res);
|
||||||
|
|
||||||
|
//void pForEachFile(std::string path, std::string type, void callback(const std::string &filename, int param), int param);
|
||||||
|
|
||||||
|
/*
|
||||||
|
void pfread(void *buffer, PHYSFS_uint32 size, PHYSFS_uint32 objs, PHYSFS_file *handle);
|
||||||
|
void pfseek(PHYSFS_file *handle,PHYSFS_uint64 byte,int origin);
|
||||||
|
void pfclose(PHYSFS_file *handle);
|
||||||
|
|
||||||
|
|
||||||
|
PHYSFS_file *openRead(const std::string &f);
|
||||||
|
std::string pLoadStream(const std::string &filename);
|
||||||
|
void pSaveStream(const std::string &filename, std::ostringstream &os);
|
||||||
|
*/
|
||||||
|
|
||||||
void drawCircle(float radius, int steps=1);
|
void drawCircle(float radius, int steps=1);
|
||||||
bool isVectorInRect(const Vector &vec, const Vector &coord1, const Vector &coord2);
|
bool isVectorInRect(const Vector &vec, const Vector &coord1, const Vector &coord2);
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,7 @@ void BitmapText::autoKern()
|
||||||
void BitmapText::loadSpacingMap(const std::string &file)
|
void BitmapText::loadSpacingMap(const std::string &file)
|
||||||
{
|
{
|
||||||
spacingMap.clear();
|
spacingMap.clear();
|
||||||
VFSTextStdStreamIn inFile(file.c_str());
|
std::ifstream inFile(file.c_str());
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(inFile, line))
|
while (std::getline(inFile, line))
|
||||||
{
|
{
|
||||||
|
|
|
@ -4193,10 +4193,6 @@ void Core::shutdown()
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
debugLog("OK");
|
debugLog("OK");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
debugLog("Unloading VFS...");
|
|
||||||
vfs.Clear();
|
|
||||||
debugLog("OK");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//util funcs
|
//util funcs
|
||||||
|
@ -4532,33 +4528,6 @@ void Core::clearGarbage()
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete leftover buffers from VFS
|
|
||||||
// FG: TODO: better do that periodically, and not every loop?
|
|
||||||
for(std::set<ttvfs::VFSFile*>::iterator it = vfsFilesToClear.begin(); it != vfsFilesToClear.end(); ++it)
|
|
||||||
{
|
|
||||||
(*it)->dropBuf(true);
|
|
||||||
(*it)->ref--;
|
|
||||||
}
|
|
||||||
vfsFilesToClear.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::addVFSFileForDrop(ttvfs::VFSFile *vf)
|
|
||||||
{
|
|
||||||
// HACK: because of save/poot.tmp caching and other stuff, we have to clear this always
|
|
||||||
// TODO: after getting rid of pack/unpackFile, this will be safer and can be done properly
|
|
||||||
if(strstr(vf->name(), "poot") || strstr(vf->name(), ".tmp"))
|
|
||||||
{
|
|
||||||
vf->dropBuf(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<ttvfs::VFSFile*>::iterator it = vfsFilesToClear.find(vf);
|
|
||||||
if(it == vfsFilesToClear.end())
|
|
||||||
{
|
|
||||||
vf->ref++;
|
|
||||||
vfsFilesToClear.insert(vf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::canChangeState()
|
bool Core::canChangeState()
|
||||||
|
@ -4889,69 +4858,3 @@ int Core::tgaSaveSeries(char *filename,
|
||||||
// ilutGLScreenie();
|
// ilutGLScreenie();
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "VFSTools.h"
|
|
||||||
|
|
||||||
static void _DumpVFS(const std::string a)
|
|
||||||
{
|
|
||||||
std::string fn = "vfsdump-" + a + ".txt";
|
|
||||||
std::ofstream out(fn.c_str());
|
|
||||||
core->vfs.debugDumpTree(out);
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::setupVFS(const char *extradir /* = NULL */)
|
|
||||||
{
|
|
||||||
debugLog("Init VFS...");
|
|
||||||
if(!ttvfs::checkCompat())
|
|
||||||
{
|
|
||||||
errorLog("VFS incompatible!");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
vfs.LoadFileSysRoot();
|
|
||||||
vfs.Prepare();
|
|
||||||
|
|
||||||
//#ifdef _DEBUG
|
|
||||||
// _DumpVFS("begin");
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef BBGE_BUILD_UNIX
|
|
||||||
// Load _mods dir from home folder into the data of the existing _mods dir, additionally.
|
|
||||||
// This does also change the internal path, so that files created using this dir's fullname() will
|
|
||||||
// automatically be created in the home directory.
|
|
||||||
ttvfs::VFSDir *moddir = vfs.GetDir("_mods", true);
|
|
||||||
std::string umods = getUserDataFolder() + "/_mods";
|
|
||||||
moddir->load(umods.c_str());
|
|
||||||
|
|
||||||
std::ostringstream os;
|
|
||||||
os << "VFS: Mounted _mods as: '" << vfs.GetDir("_mods")->fullname() << "'";
|
|
||||||
debugLog(os.str());
|
|
||||||
|
|
||||||
// Note: the original code to load/save mods is not yet changed.
|
|
||||||
// This will happen in a later patch.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(extradir)
|
|
||||||
{
|
|
||||||
std::string msg("VFS extra dir: ");
|
|
||||||
msg += extradir;
|
|
||||||
debugLog(msg);
|
|
||||||
if(vfs.GetDir(extradir))
|
|
||||||
vfs.Mount(extradir, "");
|
|
||||||
else
|
|
||||||
vfs.MountExternalPath(extradir, "");
|
|
||||||
debugLog("extra dir added.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Example: everything in _patch dir will be mounted in the game's root dir
|
|
||||||
// -- place any files/folders there to override those the game uses.
|
|
||||||
// TODO: remove this later! - When the community datafile update is organized and everything.
|
|
||||||
vfs.Mount("_patch", "", true);
|
|
||||||
|
|
||||||
|
|
||||||
debugLog("VFS init done!");
|
|
||||||
|
|
||||||
//#ifdef _DEBUG
|
|
||||||
// _DumpVFS("done");
|
|
||||||
//#endif
|
|
||||||
}
|
|
||||||
|
|
10
BBGE/Core.h
10
BBGE/Core.h
|
@ -51,8 +51,6 @@ BUILD_LINUX
|
||||||
#include "FrameBuffer.h"
|
#include "FrameBuffer.h"
|
||||||
#include "Shader.h"
|
#include "Shader.h"
|
||||||
|
|
||||||
#include "VFSIncludes.h"
|
|
||||||
|
|
||||||
class ParticleEffect;
|
class ParticleEffect;
|
||||||
|
|
||||||
class ParticleManager;
|
class ParticleManager;
|
||||||
|
@ -1402,14 +1400,6 @@ protected:
|
||||||
int tgaSave(const char *filename, short int width, short int height, unsigned char pixelDepth, unsigned char *imageData);
|
int tgaSave(const char *filename, short int width, short int height, unsigned char pixelDepth, unsigned char *imageData);
|
||||||
virtual void onUpdate(float dt);
|
virtual void onUpdate(float dt);
|
||||||
virtual void onRender(){}
|
virtual void onRender(){}
|
||||||
|
|
||||||
// VFS related
|
|
||||||
private:
|
|
||||||
std::set<ttvfs::VFSFile*> vfsFilesToClear; // used for dropBuf() delaying
|
|
||||||
public:
|
|
||||||
ttvfs::VFSHelper vfs;
|
|
||||||
void setupVFS(const char *extradir = NULL);
|
|
||||||
void addVFSFileForDrop(ttvfs::VFSFile *vf);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Core *core;
|
extern Core *core;
|
||||||
|
|
|
@ -34,8 +34,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
#include "Core.h"
|
#include "Core.h"
|
||||||
|
|
||||||
#include "VFSFile.h"
|
|
||||||
|
|
||||||
#include "FmodOpenALBridge.h"
|
#include "FmodOpenALBridge.h"
|
||||||
|
|
||||||
#include "al.h"
|
#include "al.h"
|
||||||
|
@ -55,7 +53,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
class OggDecoder {
|
class OggDecoder {
|
||||||
public:
|
public:
|
||||||
// Create a decoder that streams from a file.
|
// Create a decoder that streams from a file.
|
||||||
OggDecoder(ttvfs::VFSFile *fp);
|
OggDecoder(FILE *fp);
|
||||||
|
|
||||||
// Create a decoder that streams from a memory buffer.
|
// Create a decoder that streams from a memory buffer.
|
||||||
OggDecoder(const void *data, long data_size);
|
OggDecoder(const void *data, long data_size);
|
||||||
|
@ -100,7 +98,7 @@ private:
|
||||||
|
|
||||||
// Data source. If fp != NULL, the source is that file; otherwise, the
|
// Data source. If fp != NULL, the source is that file; otherwise, the
|
||||||
// source is the buffer pointed to by "data" with size "data_size" bytes.
|
// source is the buffer pointed to by "data" with size "data_size" bytes.
|
||||||
ttvfs::VFSFile *fp;
|
FILE *fp;
|
||||||
const char *data;
|
const char *data;
|
||||||
long data_size;
|
long data_size;
|
||||||
long data_pos; // Current read position for memory buffers
|
long data_pos; // Current read position for memory buffers
|
||||||
|
@ -131,38 +129,22 @@ private:
|
||||||
// ov_open_callbacks() call. Note that we rename the fseek() wrapper
|
// ov_open_callbacks() call. Note that we rename the fseek() wrapper
|
||||||
// to avoid an identifier collision when building with more recent
|
// to avoid an identifier collision when building with more recent
|
||||||
// versions of libvorbis.
|
// versions of libvorbis.
|
||||||
static int BBGE_ov_header_fseek_wrap(void *f,ogg_int64_t off,int whence){
|
static int BBGE_ov_header_fseek_wrap(FILE *f,ogg_int64_t off,int whence){
|
||||||
if(f==NULL)return(-1);
|
if(f==NULL)return(-1);
|
||||||
ttvfs::VFSFile *vf = (ttvfs::VFSFile*)f;
|
#ifdef __MINGW32__
|
||||||
switch(whence)
|
return fseeko64(f,off,whence);
|
||||||
{
|
#elif defined (_WIN32)
|
||||||
case SEEK_SET: return vf->seek(off);
|
return _fseeki64(f,off,whence);
|
||||||
case SEEK_CUR: return vf->seekRel(off);
|
#else
|
||||||
case SEEK_END: return vf->seek(vf->size() - off);
|
return fseek(f,off,whence);
|
||||||
}
|
#endif
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
static size_t BBGE_ov_fread_wrap(void *ptr, size_t s, size_t count, void *f)
|
static int noclose(FILE *f) {return 0;}
|
||||||
{
|
|
||||||
if(f==NULL)return(-1);
|
|
||||||
ttvfs::VFSFile *vf = (ttvfs::VFSFile*)f;
|
|
||||||
size_t done = vf->read(ptr, s * count);
|
|
||||||
return done / s;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long BBGE_ov_ftell_wrap(void *f)
|
|
||||||
{
|
|
||||||
if(f==NULL)return(-1);
|
|
||||||
ttvfs::VFSFile *vf = (ttvfs::VFSFile*)f;
|
|
||||||
return vf->getpos();
|
|
||||||
}
|
|
||||||
|
|
||||||
static int noclose(void *f) {return 0;}
|
|
||||||
static const ov_callbacks local_OV_CALLBACKS_NOCLOSE = {
|
static const ov_callbacks local_OV_CALLBACKS_NOCLOSE = {
|
||||||
(size_t (*)(void *, size_t, size_t, void *)) BBGE_ov_fread_wrap,
|
(size_t (*)(void *, size_t, size_t, void *)) fread,
|
||||||
(int (*)(void *, ogg_int64_t, int)) BBGE_ov_header_fseek_wrap,
|
(int (*)(void *, ogg_int64_t, int)) BBGE_ov_header_fseek_wrap,
|
||||||
(int (*)(void *)) noclose, // NULL doesn't work in libvorbis-1.1.2
|
(int (*)(void *)) noclose, // NULL doesn't work in libvorbis-1.1.2
|
||||||
(long (*)(void *)) BBGE_ov_ftell_wrap
|
(long (*)(void *)) ftell
|
||||||
};
|
};
|
||||||
|
|
||||||
// Memory I/O callback set.
|
// Memory I/O callback set.
|
||||||
|
@ -174,7 +156,7 @@ static const ov_callbacks ogg_memory_callbacks = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
OggDecoder::OggDecoder(ttvfs::VFSFile *fp)
|
OggDecoder::OggDecoder(FILE *fp)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NUM_BUFFERS; i++)
|
for (int i = 0; i < NUM_BUFFERS; i++)
|
||||||
{
|
{
|
||||||
|
@ -535,9 +517,9 @@ static ALenum GVorbisFormat = AL_NONE;
|
||||||
class OpenALSound
|
class OpenALSound
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OpenALSound(ttvfs::VFSFile *_fp, const bool _looping);
|
OpenALSound(FILE *_fp, const bool _looping);
|
||||||
OpenALSound(void *_data, long _size, const bool _looping);
|
OpenALSound(void *_data, long _size, const bool _looping);
|
||||||
ttvfs::VFSFile *getFile() const { return fp; }
|
FILE *getFile() const { return fp; }
|
||||||
const void *getData() const { return data; }
|
const void *getData() const { return data; }
|
||||||
long getSize() const { return size; }
|
long getSize() const { return size; }
|
||||||
bool isLooping() const { return looping; }
|
bool isLooping() const { return looping; }
|
||||||
|
@ -545,21 +527,20 @@ public:
|
||||||
void reference() { refcount++; }
|
void reference() { refcount++; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ttvfs::VFSFile * const fp;
|
FILE * const fp;
|
||||||
void * const data; // Only used if fp==NULL
|
void * const data; // Only used if fp==NULL
|
||||||
const long size; // Only used if fp==NULL
|
const long size; // Only used if fp==NULL
|
||||||
const bool looping;
|
const bool looping;
|
||||||
int refcount;
|
int refcount;
|
||||||
};
|
};
|
||||||
|
|
||||||
OpenALSound::OpenALSound(ttvfs::VFSFile *_fp, const bool _looping)
|
OpenALSound::OpenALSound(FILE *_fp, const bool _looping)
|
||||||
: fp(_fp)
|
: fp(_fp)
|
||||||
, data(NULL)
|
, data(NULL)
|
||||||
, size(0)
|
, size(0)
|
||||||
, looping(_looping)
|
, looping(_looping)
|
||||||
, refcount(1)
|
, refcount(1)
|
||||||
{
|
{
|
||||||
fp->ref++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenALSound::OpenALSound(void *_data, long _size, const bool _looping)
|
OpenALSound::OpenALSound(void *_data, long _size, const bool _looping)
|
||||||
|
@ -578,11 +559,7 @@ FMOD_RESULT OpenALSound::release()
|
||||||
if (refcount <= 0)
|
if (refcount <= 0)
|
||||||
{
|
{
|
||||||
if (fp)
|
if (fp)
|
||||||
{
|
fclose(fp);
|
||||||
fp->close();
|
|
||||||
fp->dropBuf(true); // just in case there is a buffer...
|
|
||||||
fp->ref--;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
free(data);
|
free(data);
|
||||||
delete this;
|
delete this;
|
||||||
|
@ -1067,6 +1044,8 @@ FMOD_RESULT OpenALSystem::createSound(const char *name_or_data, const FMOD_MODE
|
||||||
{
|
{
|
||||||
assert(!exinfo);
|
assert(!exinfo);
|
||||||
|
|
||||||
|
FMOD_RESULT retval = FMOD_ERR_INTERNAL;
|
||||||
|
|
||||||
// !!! FIXME: if it's not Ogg, we don't have a decoder. I'm lazy. :/
|
// !!! FIXME: if it's not Ogg, we don't have a decoder. I'm lazy. :/
|
||||||
char *fname = (char *) alloca(strlen(name_or_data) + 16);
|
char *fname = (char *) alloca(strlen(name_or_data) + 16);
|
||||||
strcpy(fname, name_or_data);
|
strcpy(fname, name_or_data);
|
||||||
|
@ -1074,39 +1053,50 @@ FMOD_RESULT OpenALSystem::createSound(const char *name_or_data, const FMOD_MODE
|
||||||
if (ptr) *ptr = '\0';
|
if (ptr) *ptr = '\0';
|
||||||
strcat(fname, ".ogg");
|
strcat(fname, ".ogg");
|
||||||
|
|
||||||
ttvfs::VFSFile *vf = core->vfs.GetFile(fname);
|
// just in case...
|
||||||
if(!vf)
|
#undef fopen
|
||||||
|
FILE *io = fopen(core->adjustFilenameCase(fname).c_str(), "rb");
|
||||||
|
if (io == NULL)
|
||||||
return FMOD_ERR_INTERNAL;
|
return FMOD_ERR_INTERNAL;
|
||||||
|
|
||||||
if(mode & FMOD_CREATESTREAM)
|
if (mode & FMOD_CREATESTREAM)
|
||||||
{
|
{
|
||||||
// does it make sense to try to stream from anything else than an actual file on disk?
|
*sound = (Sound *) new OpenALSound(io, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL)));
|
||||||
// Files inside containers are always loaded into memory, unless on-the-fly partial decompression is implemented...
|
retval = FMOD_OK;
|
||||||
// A typical ogg is < 3 MB in size, if that is preloaded and then decoded over time it should still be a big gain.
|
}
|
||||||
if(!vf->isopen())
|
else
|
||||||
vf->open(NULL, "rb");
|
{
|
||||||
else
|
fseek(io, 0, SEEK_END);
|
||||||
vf->seek(0);
|
long size = ftell(io);
|
||||||
|
if (fseek(io, 0, SEEK_SET) != 0)
|
||||||
|
{
|
||||||
|
debugLog("Seek error on " + std::string(fname));
|
||||||
|
fclose(io);
|
||||||
|
return FMOD_ERR_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
*sound = (Sound *) new OpenALSound(vf, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL)));
|
void *data = malloc(size);
|
||||||
return FMOD_OK;
|
if (data == NULL)
|
||||||
|
{
|
||||||
|
debugLog("Out of memory for " + std::string(fname));
|
||||||
|
fclose(io);
|
||||||
|
return FMOD_ERR_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
long nread = fread(data, 1, size, io);
|
||||||
|
fclose(io);
|
||||||
|
if (nread != size)
|
||||||
|
{
|
||||||
|
debugLog("Failed to read data from " + std::string(fname));
|
||||||
|
free(data);
|
||||||
|
return FMOD_ERR_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*sound = (Sound *) new OpenALSound(data, size, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL)));
|
||||||
|
retval = FMOD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we are here, create & preload & pre-decode full buffer
|
return retval;
|
||||||
vf->getBuf(); // force early size detection
|
|
||||||
void *data = malloc(vf->size()); // because release() will use free() ...
|
|
||||||
if (!(data && vf->getBuf()))
|
|
||||||
{
|
|
||||||
debugLog("Out of memory for " + std::string(fname));
|
|
||||||
vf->close();
|
|
||||||
vf->dropBuf(true);
|
|
||||||
return FMOD_ERR_INTERNAL;
|
|
||||||
}
|
|
||||||
memcpy(data, vf->getBuf(), vf->size());
|
|
||||||
core->addVFSFileForDrop(vf);
|
|
||||||
*sound = (Sound *) new OpenALSound(data, vf->size(), (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL)));
|
|
||||||
|
|
||||||
return FMOD_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ALBRIDGE(System,createStream,(const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound),(name_or_data,mode,exinfo,sound))
|
ALBRIDGE(System,createStream,(const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound),(name_or_data,mode,exinfo,sound))
|
||||||
|
|
|
@ -123,7 +123,7 @@ void Precacher::precacheTex(const std::string &tex)
|
||||||
void Precacher::precacheList(const std::string &list, void progressCallback())
|
void Precacher::precacheList(const std::string &list, void progressCallback())
|
||||||
{
|
{
|
||||||
loadProgressCallback = progressCallback;
|
loadProgressCallback = progressCallback;
|
||||||
VFSTextStdStreamIn in(list.c_str());
|
std::ifstream in(list.c_str());
|
||||||
std::string t;
|
std::string t;
|
||||||
while (std::getline(in, t))
|
while (std::getline(in, t))
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,8 +18,10 @@ You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
#include "Core.h"
|
|
||||||
#include "Shader.h"
|
#include "Shader.h"
|
||||||
|
#ifdef BBGE_BUILD_WINDOWS
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef BBGE_BUILD_SHADERS
|
#ifdef BBGE_BUILD_SHADERS
|
||||||
// GL_ARB_shader_objects
|
// GL_ARB_shader_objects
|
||||||
|
@ -86,16 +88,40 @@ void Shader::setValue(float x, float y, float z, float w)
|
||||||
unsigned char *readShaderFile( const char *fileName )
|
unsigned char *readShaderFile( const char *fileName )
|
||||||
{
|
{
|
||||||
debugLog("readShaderFile()");
|
debugLog("readShaderFile()");
|
||||||
|
#ifdef BBGE_BUILD_WINDOWS
|
||||||
|
FILE *file = fopen( fileName, "r" );
|
||||||
|
|
||||||
ttvfs::VFSFile *vf = core->vfs.GetFile(fileName);
|
if( file == NULL )
|
||||||
if(!vf)
|
{
|
||||||
return NULL;
|
errorLog("Cannot open shader file!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
vf->getBuf();
|
struct _stat fileStats;
|
||||||
unsigned char *buf = new unsigned char[vf->size() + 1];
|
|
||||||
memcpy(buf, vf->getBuf(), vf->size() + 1);
|
if( _stat( fileName, &fileStats ) != 0 )
|
||||||
core->addVFSFileForDrop(vf);
|
{
|
||||||
return buf;
|
errorLog("Cannot get file stats for shader file!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned char *buffer = new unsigned char[fileStats.st_size];
|
||||||
|
|
||||||
|
int bytes = fread( buffer, 1, fileStats.st_size, file );
|
||||||
|
|
||||||
|
buffer[bytes] = 0;
|
||||||
|
|
||||||
|
fclose( file );
|
||||||
|
|
||||||
|
debugLog("End readShaderFile()");
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
|
||||||
|
#else
|
||||||
|
debugLog("End readShaderFile()");
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::reload()
|
void Shader::reload()
|
||||||
|
|
|
@ -93,7 +93,7 @@ class SimpleIStringStream {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* Reuse flag passed to StringStream(char *,int). */
|
/* Reuse flag passed to StringStream(char *,int). */
|
||||||
enum Mode {
|
enum {
|
||||||
/* Make a copy of the buffer (default action). */
|
/* Make a copy of the buffer (default action). */
|
||||||
COPY,
|
COPY,
|
||||||
/* Use the passed-in string pointer as is. Requires the string
|
/* Use the passed-in string pointer as is. Requires the string
|
||||||
|
@ -212,7 +212,7 @@ class SimpleIStringStream {
|
||||||
|
|
||||||
/*-------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------*/
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
char *buffer; // The buffer we're parsing.
|
char *buffer; // The buffer we're parsing.
|
||||||
char *position; // Our current position in the buffer.
|
char *position; // Our current position in the buffer.
|
||||||
bool freeOnDestroy; // Should we free the buffer when we're destroyed?
|
bool freeOnDestroy; // Should we free the buffer when we're destroyed?
|
||||||
|
|
|
@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include "SoundManager.h"
|
#include "SoundManager.h"
|
||||||
#include "Core.h"
|
#include "Core.h"
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
|
#include "PackRead.h"
|
||||||
|
|
||||||
#if defined(BBGE_BUILD_FMODEX)
|
#if defined(BBGE_BUILD_FMODEX)
|
||||||
#ifdef BBGE_BUILD_FMOD_OPENAL_BRIDGE
|
#ifdef BBGE_BUILD_FMOD_OPENAL_BRIDGE
|
||||||
|
@ -133,14 +134,20 @@ FMOD_RESULT F_CALLBACK myopen(const char *name, int unicode, unsigned int *files
|
||||||
{
|
{
|
||||||
if (name)
|
if (name)
|
||||||
{
|
{
|
||||||
ttvfs::VFSFile *vf = core->vfs.GetFile(name);
|
FILE *fp;
|
||||||
if(!vf)
|
|
||||||
return FMOD_ERR_FILE_NOTFOUND;
|
fp = fopen(name, "rb");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
return FMOD_ERR_FILE_NOTFOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
*filesize = ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
|
||||||
vf->open();
|
|
||||||
*filesize = vf->size();
|
|
||||||
*handle = (void*)vf;
|
|
||||||
*userdata = (void *)0x12345678;
|
*userdata = (void *)0x12345678;
|
||||||
|
*handle = fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FMOD_OK;
|
return FMOD_OK;
|
||||||
|
@ -153,9 +160,7 @@ FMOD_RESULT F_CALLBACK myclose(void *handle, void *userdata)
|
||||||
return FMOD_ERR_INVALID_PARAM;
|
return FMOD_ERR_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ttvfs::VFSFile *vf = (ttvfs::VFSFile*)handle;
|
fclose((FILE *)handle);
|
||||||
vf->close();
|
|
||||||
core->addVFSFileForDrop(vf);
|
|
||||||
|
|
||||||
return FMOD_OK;
|
return FMOD_OK;
|
||||||
}
|
}
|
||||||
|
@ -169,8 +174,7 @@ FMOD_RESULT F_CALLBACK myread(void *handle, void *buffer, unsigned int sizebytes
|
||||||
|
|
||||||
if (bytesread)
|
if (bytesread)
|
||||||
{
|
{
|
||||||
ttvfs::VFSFile *vf = (ttvfs::VFSFile*)handle;
|
*bytesread = (int)fread(buffer, 1, sizebytes, (FILE *)handle);
|
||||||
*bytesread = vf->read((char*)buffer, sizebytes);
|
|
||||||
|
|
||||||
if (*bytesread < sizebytes)
|
if (*bytesread < sizebytes)
|
||||||
{
|
{
|
||||||
|
@ -188,8 +192,7 @@ FMOD_RESULT F_CALLBACK myseek(void *handle, unsigned int pos, void *userdata)
|
||||||
return FMOD_ERR_INVALID_PARAM;
|
return FMOD_ERR_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ttvfs::VFSFile *vf = (ttvfs::VFSFile*)handle;
|
fseek((FILE *)handle, pos, SEEK_SET);
|
||||||
vf->seek(pos);
|
|
||||||
|
|
||||||
return FMOD_OK;
|
return FMOD_OK;
|
||||||
}
|
}
|
||||||
|
@ -329,7 +332,7 @@ SoundManager::SoundManager(const std::string &defaultDevice)
|
||||||
debugLog("err_output_createbuffer, speaker mode");
|
debugLog("err_output_createbuffer, speaker mode");
|
||||||
result = SoundCore::system->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
|
result = SoundCore::system->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
|
||||||
if (checkError()) goto get_out;
|
if (checkError()) goto get_out;
|
||||||
|
|
||||||
debugLog("init 2");
|
debugLog("init 2");
|
||||||
result = SoundCore::system->init(channels, FMOD_INIT_NORMAL, 0, defaultDevice); /* Replace with whatever channel count and flags you use! */
|
result = SoundCore::system->init(channels, FMOD_INIT_NORMAL, 0, defaultDevice); /* Replace with whatever channel count and flags you use! */
|
||||||
if (checkError()) goto get_out;
|
if (checkError()) goto get_out;
|
||||||
|
|
|
@ -18,7 +18,6 @@ You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
#include "Core.h"
|
|
||||||
#include "TTFFont.h"
|
#include "TTFFont.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,17 +46,8 @@ void TTFFont::destroy()
|
||||||
|
|
||||||
void TTFFont::load(const std::string &str, int sz)
|
void TTFFont::load(const std::string &str, int sz)
|
||||||
{
|
{
|
||||||
ttvfs::VFSFile *vf = core->vfs.GetFile(str.c_str());
|
font = new FTGLTextureFont(str.c_str());
|
||||||
if(!vf)
|
font->FaceSize(sz);
|
||||||
{
|
|
||||||
font = new FTGLTextureFont(str.c_str()); // file not in VFS, just pretend nothing happened
|
|
||||||
font->FaceSize(sz);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned char *buf = (const unsigned char*)vf->getBuf();
|
|
||||||
create(buf, vf->size(), sz); // this copies the buffer internally
|
|
||||||
core->addVFSFileForDrop(vf); // so we can delete our own
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TTFFont::create(const unsigned char *data, unsigned long datalen, int sz)
|
void TTFFont::create(const unsigned char *data, unsigned long datalen, int sz)
|
||||||
|
|
|
@ -468,20 +468,6 @@ void Texture::loadPNG(const std::string &file)
|
||||||
{
|
{
|
||||||
if (file.empty()) return;
|
if (file.empty()) return;
|
||||||
|
|
||||||
ttvfs::VFSFile *vf = core->vfs.GetFile(file.c_str());
|
|
||||||
const char *memptr = vf ? (const char*)vf->getBuf() : NULL;
|
|
||||||
if(!memptr)
|
|
||||||
{
|
|
||||||
debugLog("Can't load PNG file: " + file);
|
|
||||||
width = 64;
|
|
||||||
height = 64;
|
|
||||||
Texture::textureError = TEXERR_FILENOTFOUND;
|
|
||||||
//exit(1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int memsize = vf->size();
|
|
||||||
|
|
||||||
#ifdef BBGE_BUILD_OPENGL
|
#ifdef BBGE_BUILD_OPENGL
|
||||||
|
|
||||||
|
|
||||||
|
@ -497,11 +483,11 @@ void Texture::loadPNG(const std::string &file)
|
||||||
|
|
||||||
if (filter == GL_NEAREST)
|
if (filter == GL_NEAREST)
|
||||||
{
|
{
|
||||||
textures[0] = pngBindMem(memptr, memsize, PNG_NOMIPMAPS, pngType, &info, GL_CLAMP_TO_EDGE, filter, filter);
|
textures[0] = pngBind(file.c_str(), PNG_NOMIPMAPS, pngType, &info, GL_CLAMP_TO_EDGE, filter, filter);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
textures[0] = pngBindMem(memptr, memsize, PNG_BUILDMIPMAPS, pngType, &info, GL_CLAMP_TO_EDGE, GL_LINEAR_MIPMAP_LINEAR, filter);
|
textures[0] = pngBind(file.c_str(), PNG_BUILDMIPMAPS, pngType, &info, GL_CLAMP_TO_EDGE, GL_LINEAR_MIPMAP_LINEAR, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -529,9 +515,9 @@ void Texture::loadPNG(const std::string &file)
|
||||||
Texture::textureError = TEXERR_FILENOTFOUND;
|
Texture::textureError = TEXERR_FILENOTFOUND;
|
||||||
//exit(1);
|
//exit(1);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
core->addVFSFileForDrop(vf);
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal load functions
|
// internal load functions
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
#include "Core.h"
|
|
||||||
#include "VFSFileStream.h"
|
|
||||||
|
|
||||||
VFSTextStreamIn::VFSTextStreamIn(const std::string& fn, SimpleIStringStream::Mode strmode /* = TAKE_OVER*/)
|
|
||||||
: SimpleIStringStream()
|
|
||||||
{
|
|
||||||
_init(fn.c_str(), strmode);
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSTextStreamIn::VFSTextStreamIn(const char *fn, SimpleIStringStream::Mode strmode /* = TAKE_OVER*/)
|
|
||||||
: SimpleIStringStream()
|
|
||||||
{
|
|
||||||
_init(fn, strmode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFSTextStreamIn::_init(const char *fn, SimpleIStringStream::Mode strmode)
|
|
||||||
{
|
|
||||||
ttvfs::VFSFile *vf = core->vfs.GetFile(fn);
|
|
||||||
if(vf)
|
|
||||||
{
|
|
||||||
vf->open(NULL, "r");
|
|
||||||
setString((char*)vf->getBuf(), strmode);
|
|
||||||
vf->close();
|
|
||||||
if(strmode == TAKE_OVER)
|
|
||||||
vf->dropBuf(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VFSTextStdStreamIn::VFSTextStdStreamIn(const std::string& fn, SimpleIStringStream::Mode strmode /* = TAKE_OVER*/)
|
|
||||||
: std::istringstream()
|
|
||||||
{
|
|
||||||
_init(fn.c_str(), strmode);
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSTextStdStreamIn::VFSTextStdStreamIn(const char *fn, SimpleIStringStream::Mode strmode /* = TAKE_OVER*/)
|
|
||||||
: std::istringstream()
|
|
||||||
{
|
|
||||||
_init(fn, strmode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFSTextStdStreamIn::_init(const char *fn, SimpleIStringStream::Mode strmode)
|
|
||||||
{
|
|
||||||
ttvfs::VFSFile *vf = core->vfs.GetFile(fn);
|
|
||||||
if(vf)
|
|
||||||
{
|
|
||||||
vf->open(NULL, "r");
|
|
||||||
str((char*)vf->getBuf()); // stringstream will always make a copy
|
|
||||||
vf->close();
|
|
||||||
if(strmode == SimpleIStringStream::TAKE_OVER)
|
|
||||||
core->addVFSFileForDrop(vf);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
this->setstate(std::ios_base::failbit);
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
#ifndef VFS_FILE_STREAM_H
|
|
||||||
#define VFS_FILE_STREAM_H
|
|
||||||
|
|
||||||
#include "SimpleIStringStream.h"
|
|
||||||
|
|
||||||
class VFSTextStreamIn : public SimpleIStringStream
|
|
||||||
{
|
|
||||||
/* This class is an adapter to support STL-like read-only file streams for VFS files,
|
|
||||||
* using the SimpleIStringStream for performance reasons.
|
|
||||||
*
|
|
||||||
* strmode: one of COPY, REUSE, TAKE_OVER, see SimpleIStringStream.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
public:
|
|
||||||
VFSTextStreamIn(const char *fn, SimpleIStringStream::Mode strmode = TAKE_OVER);
|
|
||||||
VFSTextStreamIn(const std::string& fn, SimpleIStringStream::Mode strmode = TAKE_OVER);
|
|
||||||
void close() {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void _init(const char *fn, SimpleIStringStream::Mode strmode);
|
|
||||||
};
|
|
||||||
|
|
||||||
class VFSTextStdStreamIn : public std::istringstream
|
|
||||||
{
|
|
||||||
/* This class is an adapter to support STL-like read-only file streams for VFS files,
|
|
||||||
* using std::istringstream.
|
|
||||||
*
|
|
||||||
* strmode: one of COPY, REUSE, TAKE_OVER, see SimpleIStringStream.h
|
|
||||||
* - Note: The file's content will always be copied, regardless of strmode setting.
|
|
||||||
* However, TAKE_OVER will drop the internal buffer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public:
|
|
||||||
VFSTextStdStreamIn(const char *fn, SimpleIStringStream::Mode strmode = SimpleIStringStream::TAKE_OVER);
|
|
||||||
VFSTextStdStreamIn(const std::string& fn, SimpleIStringStream::Mode strmode = SimpleIStringStream::TAKE_OVER);
|
|
||||||
void close() {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void _init(const char *fn, SimpleIStringStream::Mode strmode);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,9 +0,0 @@
|
||||||
#ifndef CUSTOM_VFS_INCLUDES_H
|
|
||||||
#define CUSTOM_VFS_INCLUDES_H
|
|
||||||
|
|
||||||
#include "VFS.h"
|
|
||||||
#include "VFSFileStream.h"
|
|
||||||
|
|
||||||
#include "VFSFile.h"
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -20,13 +20,33 @@ using namespace std;
|
||||||
#include <OpenGL/gl.h>
|
#include <OpenGL/gl.h>
|
||||||
*/
|
*/
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
#include "Core.h"
|
|
||||||
#include "lvpa/ByteBuffer.h"
|
#include "SDL_endian.h"
|
||||||
|
|
||||||
//glFont header
|
//glFont header
|
||||||
#include "glfont2.h"
|
#include "glfont2.h"
|
||||||
using namespace glfont;
|
using namespace glfont;
|
||||||
|
|
||||||
|
static int read_int(ifstream &input)
|
||||||
|
{
|
||||||
|
int buffer;
|
||||||
|
|
||||||
|
input.read((char *)&buffer, 4);
|
||||||
|
return SDL_SwapLE32(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float read_float(ifstream &input)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
float f;
|
||||||
|
} buffer;
|
||||||
|
|
||||||
|
input.read((char *)&buffer.i, 4);
|
||||||
|
buffer.i = SDL_SwapLE32(buffer.i);
|
||||||
|
return buffer.f;
|
||||||
|
}
|
||||||
|
|
||||||
//*******************************************************************
|
//*******************************************************************
|
||||||
//GLFont Class Implementation
|
//GLFont Class Implementation
|
||||||
|
@ -50,6 +70,7 @@ GLFont::~GLFont ()
|
||||||
//*******************************************************************
|
//*******************************************************************
|
||||||
bool GLFont::Create (const char *file_name, int tex, bool loadTexture)
|
bool GLFont::Create (const char *file_name, int tex, bool loadTexture)
|
||||||
{
|
{
|
||||||
|
ifstream input;
|
||||||
int num_chars, num_tex_bytes;
|
int num_chars, num_tex_bytes;
|
||||||
char *tex_bytes;
|
char *tex_bytes;
|
||||||
|
|
||||||
|
@ -57,24 +78,19 @@ bool GLFont::Create (const char *file_name, int tex, bool loadTexture)
|
||||||
Destroy();
|
Destroy();
|
||||||
|
|
||||||
//Open input file
|
//Open input file
|
||||||
ttvfs::VFSFile *vf = core->vfs.GetFile(file_name);
|
input.open(file_name, ios::in | ios::binary);
|
||||||
if(!vf)
|
if (!input)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
lvpa::ByteBuffer bb;
|
|
||||||
bb.append(vf->getBuf(), vf->size());
|
|
||||||
core->addVFSFileForDrop(vf);
|
|
||||||
lvpa::uint32 dummy;
|
|
||||||
|
|
||||||
// Read the header from file
|
|
||||||
header.tex = tex;
|
|
||||||
bb >> dummy; // skip tex field
|
|
||||||
bb >> header.tex_width;
|
|
||||||
bb >> header.tex_height;
|
|
||||||
bb >> header.start_char;
|
|
||||||
bb >> header.end_char;
|
|
||||||
bb >> dummy; // skip chars field
|
|
||||||
|
|
||||||
|
// Read the header from file
|
||||||
|
header.tex = tex;
|
||||||
|
input.seekg(4, ios::cur); // skip tex field
|
||||||
|
header.tex_width = read_int(input);
|
||||||
|
header.tex_height = read_int(input);
|
||||||
|
header.start_char = read_int(input);
|
||||||
|
header.end_char = read_int(input);
|
||||||
|
input.seekg(4, ios::cur); // skip chars field
|
||||||
|
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << "tex_width: " << header.tex_width << " tex_height: " << header.tex_height;
|
os << "tex_width: " << header.tex_width << " tex_height: " << header.tex_height;
|
||||||
debugLog(os.str());
|
debugLog(os.str());
|
||||||
|
@ -87,19 +103,18 @@ bool GLFont::Create (const char *file_name, int tex, bool loadTexture)
|
||||||
//Read character array
|
//Read character array
|
||||||
for (int i = 0; i < num_chars; i++)
|
for (int i = 0; i < num_chars; i++)
|
||||||
{
|
{
|
||||||
bb >> header.chars[i].dx;
|
header.chars[i].dx = read_float(input);
|
||||||
bb >> header.chars[i].dy;
|
header.chars[i].dy = read_float(input);
|
||||||
bb >> header.chars[i].tx1;
|
header.chars[i].tx1 = read_float(input);
|
||||||
bb >> header.chars[i].ty1;
|
header.chars[i].ty1 = read_float(input);
|
||||||
bb >> header.chars[i].tx2;
|
header.chars[i].tx2 = read_float(input);
|
||||||
bb >> header.chars[i].ty2;
|
header.chars[i].ty2 = read_float(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Read texture pixel data
|
//Read texture pixel data
|
||||||
num_tex_bytes = header.tex_width * header.tex_height * 2;
|
num_tex_bytes = header.tex_width * header.tex_height * 2;
|
||||||
tex_bytes = new char[num_tex_bytes];
|
tex_bytes = new char[num_tex_bytes];
|
||||||
//input.read(tex_bytes, num_tex_bytes);
|
input.read(tex_bytes, num_tex_bytes);
|
||||||
bb.read(tex_bytes, num_tex_bytes);
|
|
||||||
|
|
||||||
|
|
||||||
//Build2DMipmaps(3, header.tex_width, header.tex_height, GL_UNSIGNED_BYTE, tex_bytes, 1);
|
//Build2DMipmaps(3, header.tex_width, header.tex_height, GL_UNSIGNED_BYTE, tex_bytes, 1);
|
||||||
|
@ -135,6 +150,9 @@ bool GLFont::Create (const char *file_name, int tex, bool loadTexture)
|
||||||
//Free texture pixels memory
|
//Free texture pixels memory
|
||||||
delete[] tex_bytes;
|
delete[] tex_bytes;
|
||||||
|
|
||||||
|
//Close input file
|
||||||
|
input.close();
|
||||||
|
|
||||||
//Return successfully
|
//Return successfully
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,6 @@ must not be misrepresented as being the original software.
|
||||||
distribution.
|
distribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// hacked VFS support into this version.
|
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#ifdef TIXML_USE_STL
|
#ifdef TIXML_USE_STL
|
||||||
|
@ -33,8 +31,6 @@ distribution.
|
||||||
|
|
||||||
#include "tinyxml.h"
|
#include "tinyxml.h"
|
||||||
|
|
||||||
#include "Core.h"
|
|
||||||
|
|
||||||
FILE* TiXmlFOpen( const char* filename, const char* mode );
|
FILE* TiXmlFOpen( const char* filename, const char* mode );
|
||||||
|
|
||||||
bool TiXmlBase::condenseWhiteSpace = true;
|
bool TiXmlBase::condenseWhiteSpace = true;
|
||||||
|
@ -927,11 +923,12 @@ bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )
|
||||||
value = filename;
|
value = filename;
|
||||||
|
|
||||||
// reading in binary mode so that tinyxml can normalize the EOL
|
// reading in binary mode so that tinyxml can normalize the EOL
|
||||||
ttvfs::VFSFile* file = core->vfs.GetFile(value.c_str());
|
FILE* file = TiXmlFOpen( value.c_str (), "rb" );
|
||||||
|
|
||||||
if ( file )
|
if ( file )
|
||||||
{
|
{
|
||||||
bool result = LoadFile( file, encoding );
|
bool result = LoadFile( file, encoding );
|
||||||
|
fclose( file );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -941,7 +938,7 @@ bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TiXmlDocument::LoadFile( ttvfs::VFSFile* file, TiXmlEncoding encoding )
|
bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding )
|
||||||
{
|
{
|
||||||
if ( !file )
|
if ( !file )
|
||||||
{
|
{
|
||||||
|
@ -954,15 +951,10 @@ bool TiXmlDocument::LoadFile( ttvfs::VFSFile* file, TiXmlEncoding encoding )
|
||||||
location.Clear();
|
location.Clear();
|
||||||
|
|
||||||
// Get the file size, so we can pre-allocate the string. HUGE speed impact.
|
// Get the file size, so we can pre-allocate the string. HUGE speed impact.
|
||||||
char* buf = (char*)file->getBuf();
|
long length = 0;
|
||||||
|
fseek( file, 0, SEEK_END );
|
||||||
if ( !buf )
|
length = ftell( file );
|
||||||
{
|
fseek( file, 0, SEEK_SET );
|
||||||
SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
long length = file->size();
|
|
||||||
|
|
||||||
// Strange case, but good to handle up front.
|
// Strange case, but good to handle up front.
|
||||||
if ( length <= 0 )
|
if ( length <= 0 )
|
||||||
|
@ -992,6 +984,15 @@ bool TiXmlDocument::LoadFile( ttvfs::VFSFile* file, TiXmlEncoding encoding )
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
char* buf = new char[ length+1 ];
|
||||||
|
buf[0] = 0;
|
||||||
|
|
||||||
|
if ( fread( buf, length, 1, file ) != 1 ) {
|
||||||
|
delete [] buf;
|
||||||
|
SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Process the buffer in place to normalize new lines. (See comment above.)
|
// Process the buffer in place to normalize new lines. (See comment above.)
|
||||||
// Copies from the 'p' to 'q' pointer, where p can advance faster if
|
// Copies from the 'p' to 'q' pointer, where p can advance faster if
|
||||||
// a newline-carriage return is hit.
|
// a newline-carriage return is hit.
|
||||||
|
@ -1030,16 +1031,13 @@ bool TiXmlDocument::LoadFile( ttvfs::VFSFile* file, TiXmlEncoding encoding )
|
||||||
|
|
||||||
Parse( buf, 0, encoding );
|
Parse( buf, 0, encoding );
|
||||||
|
|
||||||
core->addVFSFileForDrop(file);
|
delete [] buf;
|
||||||
|
|
||||||
return !Error();
|
return !Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool TiXmlDocument::SaveFile( const char * filename ) const
|
bool TiXmlDocument::SaveFile( const char * filename ) const
|
||||||
{
|
{
|
||||||
// FG: TODO: use VFS stuff here as well
|
|
||||||
|
|
||||||
// The old c stuff lives on...
|
// The old c stuff lives on...
|
||||||
FILE* fp = TiXmlFOpen( filename, "w" );
|
FILE* fp = TiXmlFOpen( filename, "w" );
|
||||||
if ( fp )
|
if ( fp )
|
||||||
|
|
|
@ -53,11 +53,6 @@ distribution.
|
||||||
#define TIXML_STRING TiXmlString
|
#define TIXML_STRING TiXmlString
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace ttvfs
|
|
||||||
{
|
|
||||||
class VFSFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated library function hell. Compilers want to use the
|
// Deprecated library function hell. Compilers want to use the
|
||||||
// new safe versions. This probably doesn't fully address the problem,
|
// new safe versions. This probably doesn't fully address the problem,
|
||||||
// but it gets closer. There are too many compilers for me to fully
|
// but it gets closer. There are too many compilers for me to fully
|
||||||
|
@ -1422,7 +1417,7 @@ public:
|
||||||
will be interpreted as an XML file. TinyXML doesn't stream in XML from the current
|
will be interpreted as an XML file. TinyXML doesn't stream in XML from the current
|
||||||
file location. Streaming may be added in the future.
|
file location. Streaming may be added in the future.
|
||||||
*/
|
*/
|
||||||
bool LoadFile( ttvfs::VFSFile*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
|
bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
|
||||||
/// Save a file using the given FILE*. Returns true if successful.
|
/// Save a file using the given FILE*. Returns true if successful.
|
||||||
bool SaveFile( FILE* ) const;
|
bool SaveFile( FILE* ) const;
|
||||||
|
|
||||||
|
|
|
@ -170,8 +170,6 @@ INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR})
|
||||||
INCLUDE_DIRECTORIES(${OGGVORBIS_INCLUDE_DIRS})
|
INCLUDE_DIRECTORIES(${OGGVORBIS_INCLUDE_DIRS})
|
||||||
INCLUDE_DIRECTORIES(${SDL_INCLUDE_DIR})
|
INCLUDE_DIRECTORIES(${SDL_INCLUDE_DIR})
|
||||||
INCLUDE_DIRECTORIES(${OPENAL_INCLUDE_DIR})
|
INCLUDE_DIRECTORIES(${OPENAL_INCLUDE_DIR})
|
||||||
INCLUDE_DIRECTORIES(${EXTLIBDIR}/ttvfs)
|
|
||||||
INCLUDE_DIRECTORIES(${EXTLIBDIR}/lvpa)
|
|
||||||
|
|
||||||
|
|
||||||
# Custom build ID: e.g. "-custom", " (my very own build)"
|
# Custom build ID: e.g. "-custom", " (my very own build)"
|
||||||
|
@ -380,7 +378,6 @@ SET(BBGE_SRCS
|
||||||
${BBGEDIR}/tinyxmlerror.cpp
|
${BBGEDIR}/tinyxmlerror.cpp
|
||||||
${BBGEDIR}/tinyxmlparser.cpp
|
${BBGEDIR}/tinyxmlparser.cpp
|
||||||
${BBGEDIR}/glfont2.cpp
|
${BBGEDIR}/glfont2.cpp
|
||||||
${BBGEDIR}/VFSFileStream.cpp
|
|
||||||
${COCOA_SRCS}
|
${COCOA_SRCS}
|
||||||
${EXTLIBDIR}/glpng/glpng.c
|
${EXTLIBDIR}/glpng/glpng.c
|
||||||
${EXTLIBDIR}/glpng/png/png.c
|
${EXTLIBDIR}/glpng/png/png.c
|
||||||
|
@ -560,9 +557,6 @@ SET(LUA_SRCS
|
||||||
${LUASRCDIR}/lmathlib.c
|
${LUASRCDIR}/lmathlib.c
|
||||||
)
|
)
|
||||||
|
|
||||||
ADD_SUBDIRECTORY(ExternalLibs/ttvfs)
|
|
||||||
|
|
||||||
SET(OPTIONAL_LIBS ${OPTIONAL_LIBS} ttvfs)
|
|
||||||
|
|
||||||
IF(MACOSX)
|
IF(MACOSX)
|
||||||
SET(OPTIONAL_LIBS ${OPTIONAL_LIBS} "-framework Carbon")
|
SET(OPTIONAL_LIBS ${OPTIONAL_LIBS} "-framework Carbon")
|
||||||
|
|
|
@ -97,11 +97,9 @@ extern int APIENTRY pngLoadRawF(FILE *file, pngRawInfo *rawinfo);
|
||||||
|
|
||||||
extern int APIENTRY pngLoad(const char *filename, int mipmap, int trans, pngInfo *info);
|
extern int APIENTRY pngLoad(const char *filename, int mipmap, int trans, pngInfo *info);
|
||||||
extern int APIENTRY pngLoadF(FILE *file, int mipmap, int trans, pngInfo *info);
|
extern int APIENTRY pngLoadF(FILE *file, int mipmap, int trans, pngInfo *info);
|
||||||
extern int APIENTRY pngLoadMem(const char *mem, int size, int mipmap, int trans, pngInfo *info);
|
|
||||||
|
|
||||||
extern unsigned int APIENTRY pngBind(const char *filename, int mipmap, int trans, pngInfo *info, int wrapst, int minfilter, int magfilter);
|
extern unsigned int APIENTRY pngBind(const char *filename, int mipmap, int trans, pngInfo *info, int wrapst, int minfilter, int magfilter);
|
||||||
extern unsigned int APIENTRY pngBindF(FILE *file, int mipmap, int trans, pngInfo *info, int wrapst, int minfilter, int magfilter);
|
extern unsigned int APIENTRY pngBindF(FILE *file, int mipmap, int trans, pngInfo *info, int wrapst, int minfilter, int magfilter);
|
||||||
extern unsigned int APIENTRY pngBindMem(const char *mem, int size, int mipmap, int trans, pngInfo *info, int wrapst, int minfilter, int magfilter);
|
|
||||||
|
|
||||||
extern void APIENTRY pngSetStencil(unsigned char red, unsigned char green, unsigned char blue);
|
extern void APIENTRY pngSetStencil(unsigned char red, unsigned char green, unsigned char blue);
|
||||||
extern void APIENTRY pngSetAlphaCallback(unsigned char (*callback)(unsigned char red, unsigned char green, unsigned char blue));
|
extern void APIENTRY pngSetAlphaCallback(unsigned char (*callback)(unsigned char red, unsigned char green, unsigned char blue));
|
||||||
|
|
|
@ -691,14 +691,6 @@ unsigned int APIENTRY pngBindF(FILE *file, int mipmap, int trans, pngInfo *info,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int APIENTRY pngBindMem(const char *mem, int size, int mipmap, int trans, pngInfo *info, int wrapst, int minfilter, int magfilter) {
|
|
||||||
unsigned int id = SetParams(wrapst, magfilter, minfilter);
|
|
||||||
|
|
||||||
if (id != 0 && pngLoadMem(mem, size, mipmap, trans, info))
|
|
||||||
return id;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void APIENTRY pngSetStencil(unsigned char red, unsigned char green, unsigned char blue) {
|
void APIENTRY pngSetStencil(unsigned char red, unsigned char green, unsigned char blue) {
|
||||||
StencilRed = red, StencilGreen = green, StencilBlue = blue;
|
StencilRed = red, StencilGreen = green, StencilBlue = blue;
|
||||||
}
|
}
|
||||||
|
@ -725,332 +717,3 @@ void APIENTRY pngSetStandardOrientation(int standardorientation) {
|
||||||
StandardOrientation = standardorientation;
|
StandardOrientation = standardorientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -- added memory read functions --
|
|
||||||
|
|
||||||
/*pointer to a new input function that takes as its
|
|
||||||
arguments a pointer to a png_struct, a pointer to
|
|
||||||
a location where input data can be stored, and a 32-bit
|
|
||||||
unsigned int that is the number of bytes to be read.
|
|
||||||
To exit and output any fatal error messages the new write
|
|
||||||
function should call png_error(png_ptr, "Error msg"). */
|
|
||||||
|
|
||||||
typedef struct glpng_memread_struct
|
|
||||||
{
|
|
||||||
png_bytep mem;
|
|
||||||
png_size_t rpos;
|
|
||||||
} glpng_memread;
|
|
||||||
|
|
||||||
void glpng_read_mem(png_structp png, png_bytep dst, png_size_t size)
|
|
||||||
{
|
|
||||||
glpng_memread *mr = (glpng_memread*)png->io_ptr;
|
|
||||||
memcpy(dst, mr->mem + mr->rpos, size);
|
|
||||||
mr->rpos += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int APIENTRY pngLoadMem(const char *mem, int size, int mipmap, int trans, pngInfo *pinfo) {
|
|
||||||
GLint pack, unpack;
|
|
||||||
unsigned char header[8];
|
|
||||||
png_structp png;
|
|
||||||
png_infop info;
|
|
||||||
png_infop endinfo;
|
|
||||||
png_bytep data, data2;
|
|
||||||
png_bytep *row_p;
|
|
||||||
double fileGamma;
|
|
||||||
|
|
||||||
png_uint_32 width, height, rw, rh;
|
|
||||||
int depth, color;
|
|
||||||
|
|
||||||
png_uint_32 i;
|
|
||||||
glpng_memread memread;
|
|
||||||
|
|
||||||
if(size < 8)
|
|
||||||
return 0; // error
|
|
||||||
|
|
||||||
memcpy(header, mem, 8);
|
|
||||||
|
|
||||||
if (!png_check_sig(header, 8))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
||||||
info = png_create_info_struct(png);
|
|
||||||
endinfo = png_create_info_struct(png);
|
|
||||||
|
|
||||||
// DH: added following lines
|
|
||||||
if (setjmp(png->jmpbuf))
|
|
||||||
{
|
|
||||||
png_destroy_read_struct(&png, &info, &endinfo);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// ~DH
|
|
||||||
|
|
||||||
memread.rpos = 0;
|
|
||||||
memread.mem = ((png_bytep)mem) + 8;
|
|
||||||
png_set_read_fn(png, (voidp)&memread, glpng_read_mem);
|
|
||||||
png_set_sig_bytes(png, 8);
|
|
||||||
png_read_info(png, info);
|
|
||||||
png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
if (pinfo != NULL) {
|
|
||||||
pinfo->Width = width;
|
|
||||||
pinfo->Height = height;
|
|
||||||
pinfo->Depth = depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MaxTextureSize == 0)
|
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxTextureSize);
|
|
||||||
|
|
||||||
#ifdef SUPPORTS_PALETTE_EXT
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (PalettedTextures == -1)
|
|
||||||
PalettedTextures = ExtSupported("GL_EXT_paletted_texture") && (strstr((const char *) glGetString(GL_VERSION), "1.1.0 3Dfx Beta") == NULL);
|
|
||||||
|
|
||||||
if (PalettedTextures) {
|
|
||||||
if (glColorTableEXT == NULL) {
|
|
||||||
glColorTableEXT = (PFNGLCOLORTABLEEXTPROC) wglGetProcAddress("glColorTableEXT");
|
|
||||||
if (glColorTableEXT == NULL)
|
|
||||||
PalettedTextures = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (PalettedTextures == -1)
|
|
||||||
PalettedTextures = 0;
|
|
||||||
|
|
||||||
if (color == PNG_COLOR_TYPE_GRAY || color == PNG_COLOR_TYPE_GRAY_ALPHA)
|
|
||||||
png_set_gray_to_rgb(png);
|
|
||||||
|
|
||||||
if (color&PNG_COLOR_MASK_ALPHA && trans != PNG_ALPHA) {
|
|
||||||
png_set_strip_alpha(png);
|
|
||||||
color &= ~PNG_COLOR_MASK_ALPHA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(PalettedTextures && mipmap >= 0 && trans == PNG_SOLID))
|
|
||||||
if (color == PNG_COLOR_TYPE_PALETTE)
|
|
||||||
png_set_expand(png);
|
|
||||||
|
|
||||||
/*--GAMMA--*/
|
|
||||||
checkForGammaEnv();
|
|
||||||
if (png_get_gAMA(png, info, &fileGamma))
|
|
||||||
png_set_gamma(png, screenGamma, fileGamma);
|
|
||||||
else
|
|
||||||
png_set_gamma(png, screenGamma, 1.0/2.2);
|
|
||||||
|
|
||||||
png_read_update_info(png, info);
|
|
||||||
|
|
||||||
data = (png_bytep) malloc(png_get_rowbytes(png, info)*height);
|
|
||||||
row_p = (png_bytep *) malloc(sizeof(png_bytep)*height);
|
|
||||||
|
|
||||||
for (i = 0; i < height; i++) {
|
|
||||||
if (StandardOrientation)
|
|
||||||
row_p[height - 1 - i] = &data[png_get_rowbytes(png, info)*i];
|
|
||||||
else
|
|
||||||
row_p[i] = &data[png_get_rowbytes(png, info)*i];
|
|
||||||
}
|
|
||||||
|
|
||||||
png_read_image(png, row_p);
|
|
||||||
free(row_p);
|
|
||||||
|
|
||||||
rw = SafeSize(width), rh = SafeSize(height);
|
|
||||||
|
|
||||||
if (rw != width || rh != height) {
|
|
||||||
const int channels = png_get_rowbytes(png, info)/width;
|
|
||||||
|
|
||||||
data2 = (png_bytep) malloc(rw*rh*channels);
|
|
||||||
|
|
||||||
/* Doesn't work on certain sizes */
|
|
||||||
/* if (gluScaleImage(glformat, width, height, GL_UNSIGNED_BYTE, data, rw, rh, GL_UNSIGNED_BYTE, data2) != 0)
|
|
||||||
return 0;
|
|
||||||
*/
|
|
||||||
Resize(channels, data, width, height, data2, rw, rh);
|
|
||||||
|
|
||||||
width = rw, height = rh;
|
|
||||||
free(data);
|
|
||||||
data = data2;
|
|
||||||
}
|
|
||||||
|
|
||||||
{ /* OpenGL stuff */
|
|
||||||
glGetIntegerv(GL_PACK_ALIGNMENT, &pack);
|
|
||||||
glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack);
|
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
||||||
|
|
||||||
#ifdef SUPPORTS_PALETTE_EXT
|
|
||||||
if (PalettedTextures && mipmap >= 0 && trans == PNG_SOLID && color == PNG_COLOR_TYPE_PALETTE) {
|
|
||||||
png_colorp pal;
|
|
||||||
int cols;
|
|
||||||
GLint intf;
|
|
||||||
|
|
||||||
if (pinfo != NULL) pinfo->Alpha = 0;
|
|
||||||
png_get_PLTE(png, info, &pal, &cols);
|
|
||||||
|
|
||||||
switch (cols) {
|
|
||||||
case 1<<1: intf = GL_COLOR_INDEX1_EXT; break;
|
|
||||||
case 1<<2: intf = GL_COLOR_INDEX2_EXT; break;
|
|
||||||
case 1<<4: intf = GL_COLOR_INDEX4_EXT; break;
|
|
||||||
case 1<<8: intf = GL_COLOR_INDEX8_EXT; break;
|
|
||||||
case 1<<12: intf = GL_COLOR_INDEX12_EXT; break;
|
|
||||||
case 1<<16: intf = GL_COLOR_INDEX16_EXT; break;
|
|
||||||
default:
|
|
||||||
/*printf("Warning: Colour depth %i not recognised\n", cols);*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
glColorTableEXT(GL_TEXTURE_2D, GL_RGB8, cols, GL_RGB, GL_UNSIGNED_BYTE, pal);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, mipmap, intf, width, height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, data);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
if (trans == PNG_SOLID || trans == PNG_ALPHA || trans == PNG_LUMINANCEALPHA || color == PNG_COLOR_TYPE_RGB_ALPHA || color == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
|
||||||
GLenum glformat;
|
|
||||||
GLint glcomponent;
|
|
||||||
|
|
||||||
switch (color) {
|
|
||||||
case PNG_COLOR_TYPE_GRAY:
|
|
||||||
case PNG_COLOR_TYPE_RGB:
|
|
||||||
case PNG_COLOR_TYPE_PALETTE:
|
|
||||||
glformat = GL_RGB;
|
|
||||||
glcomponent = 3;
|
|
||||||
if (pinfo != NULL) pinfo->Alpha = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
|
||||||
case PNG_COLOR_TYPE_RGB_ALPHA:
|
|
||||||
glformat = GL_RGBA;
|
|
||||||
glcomponent = 4;
|
|
||||||
if (pinfo != NULL) pinfo->Alpha = 8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
/*puts("glformat not set");*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trans == PNG_LUMINANCEALPHA)
|
|
||||||
glformat = GL_LUMINANCE_ALPHA;
|
|
||||||
|
|
||||||
if (mipmap == PNG_BUILDMIPMAPS)
|
|
||||||
Build2DMipmaps(glcomponent, width, height, glformat, data, 1);
|
|
||||||
else if (mipmap == PNG_SIMPLEMIPMAPS)
|
|
||||||
Build2DMipmaps(glcomponent, width, height, glformat, data, 0);
|
|
||||||
else
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, mipmap, glcomponent, width, height, 0, glformat, GL_UNSIGNED_BYTE, data);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
png_bytep p, endp, q;
|
|
||||||
int r, g, b, a;
|
|
||||||
|
|
||||||
p = data, endp = p+width*height*3;
|
|
||||||
q = data2 = (png_bytep) malloc(sizeof(png_byte)*width*height*4);
|
|
||||||
|
|
||||||
if (pinfo != NULL) pinfo->Alpha = 8;
|
|
||||||
|
|
||||||
#define FORSTART \
|
|
||||||
do { \
|
|
||||||
r = *p++; /*red */ \
|
|
||||||
g = *p++; /*green*/ \
|
|
||||||
b = *p++; /*blue */ \
|
|
||||||
*q++ = r; \
|
|
||||||
*q++ = g; \
|
|
||||||
*q++ = b;
|
|
||||||
|
|
||||||
#define FOREND \
|
|
||||||
q++; \
|
|
||||||
} while (p != endp);
|
|
||||||
|
|
||||||
#define ALPHA *q
|
|
||||||
|
|
||||||
switch (trans) {
|
|
||||||
case PNG_CALLBACK:
|
|
||||||
FORSTART
|
|
||||||
ALPHA = AlphaCallback((unsigned char) r, (unsigned char) g, (unsigned char) b);
|
|
||||||
FOREND
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PNG_STENCIL:
|
|
||||||
FORSTART
|
|
||||||
if (r == StencilRed && g == StencilGreen && b == StencilBlue)
|
|
||||||
ALPHA = 0;
|
|
||||||
else
|
|
||||||
ALPHA = 255;
|
|
||||||
FOREND
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PNG_BLEND1:
|
|
||||||
FORSTART
|
|
||||||
a = r+g+b;
|
|
||||||
if (a > 255) ALPHA = 255; else ALPHA = a;
|
|
||||||
FOREND
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PNG_BLEND2:
|
|
||||||
FORSTART
|
|
||||||
a = r+g+b;
|
|
||||||
if (a > 255*2) ALPHA = 255; else ALPHA = a/2;
|
|
||||||
FOREND
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PNG_BLEND3:
|
|
||||||
FORSTART
|
|
||||||
ALPHA = (r+g+b)/3;
|
|
||||||
FOREND
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PNG_BLEND4:
|
|
||||||
FORSTART
|
|
||||||
a = r*r+g*g+b*b;
|
|
||||||
if (a > 255) ALPHA = 255; else ALPHA = a;
|
|
||||||
FOREND
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PNG_BLEND5:
|
|
||||||
FORSTART
|
|
||||||
a = r*r+g*g+b*b;
|
|
||||||
if (a > 255*2) ALPHA = 255; else ALPHA = a/2;
|
|
||||||
FOREND
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PNG_BLEND6:
|
|
||||||
FORSTART
|
|
||||||
a = r*r+g*g+b*b;
|
|
||||||
if (a > 255*3) ALPHA = 255; else ALPHA = a/3;
|
|
||||||
FOREND
|
|
||||||
break;
|
|
||||||
|
|
||||||
//HACK: disabling this for now
|
|
||||||
/*
|
|
||||||
case PNG_BLEND7:
|
|
||||||
FORSTART
|
|
||||||
a = r*r+g*g+b*b;
|
|
||||||
if (a > 255*255) ALPHA = 255; else ALPHA = (int) (sqrt(float(a)));
|
|
||||||
FOREND
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FORSTART
|
|
||||||
#undef FOREND
|
|
||||||
#undef ALPHA
|
|
||||||
|
|
||||||
if (mipmap == PNG_BUILDMIPMAPS)
|
|
||||||
Build2DMipmaps(4, width, height, GL_RGBA, data2, 1);
|
|
||||||
else if (mipmap == PNG_SIMPLEMIPMAPS)
|
|
||||||
Build2DMipmaps(4, width, height, GL_RGBA, data2, 0);
|
|
||||||
else
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, mipmap, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
|
|
||||||
|
|
||||||
free(data2);
|
|
||||||
}
|
|
||||||
|
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, pack);
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
|
|
||||||
} /* OpenGL end */
|
|
||||||
|
|
||||||
png_read_end(png, endinfo);
|
|
||||||
png_destroy_read_struct(&png, &info, &endinfo);
|
|
||||||
|
|
||||||
free(data);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,340 +0,0 @@
|
||||||
#ifndef BYTEBUFFER_H
|
|
||||||
#define BYTEBUFFER_H
|
|
||||||
|
|
||||||
#include "LVPACommon.h"
|
|
||||||
#include "ByteConverter.h"
|
|
||||||
|
|
||||||
#include <string.h> // for memcpy
|
|
||||||
|
|
||||||
|
|
||||||
LVPA_NAMESPACE_START
|
|
||||||
|
|
||||||
|
|
||||||
#define BB_MAKE_WRITE_OP(T) inline ByteBuffer& operator<<(T val) { append<T>(val); return *this; }
|
|
||||||
#define BB_MAKE_READ_OP(T) inline ByteBuffer& operator>>(T &val) { val = read<T>(); return *this; }
|
|
||||||
|
|
||||||
class ByteBuffer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef void (*delete_func)(void*);
|
|
||||||
enum Mode // for creation with existing pointers
|
|
||||||
{
|
|
||||||
COPY, //- Make a copy of the buffer (default action).
|
|
||||||
REUSE, //- Use the passed-in buffer as is. Requires the pointer
|
|
||||||
// to remain valid over the life of this object.
|
|
||||||
TAKE_OVER, //- Take over the passed-in buffer; it will be deleted on object destruction.
|
|
||||||
};
|
|
||||||
|
|
||||||
class Exception
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Exception(const ByteBuffer *bb, const char *act, uint32 sp = 0)
|
|
||||||
{
|
|
||||||
action = act;
|
|
||||||
rpos = bb->rpos();
|
|
||||||
wpos = bb->wpos();
|
|
||||||
sizeparam = sp;
|
|
||||||
cursize = bb->size();
|
|
||||||
}
|
|
||||||
uint32 rpos, wpos, sizeparam, cursize;
|
|
||||||
const char *action;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
delete_func _delfunc;
|
|
||||||
uint32 _rpos, // read position, [0 ... _size]
|
|
||||||
_wpos, // write position, [0 ... _size]
|
|
||||||
_res, // reserved buffer size, [0 ... _size ... _res]
|
|
||||||
_size; // used buffer size
|
|
||||||
|
|
||||||
uint8 *_buf; // the ptr to the buffer that holds all the bytes
|
|
||||||
bool _mybuf; // if true, destructor deletes buffer
|
|
||||||
bool _growable; // default true, if false, buffer will not re-allocate more space
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
|
|
||||||
ByteBuffer()
|
|
||||||
: _rpos(0), _wpos(0), _buf(NULL), _size(0), _growable(true)
|
|
||||||
{
|
|
||||||
_allocate(128);
|
|
||||||
}
|
|
||||||
ByteBuffer(uint32 res)
|
|
||||||
: _rpos(0), _wpos(0), _buf(NULL), _size(0), _growable(true)
|
|
||||||
{
|
|
||||||
_allocate(res);
|
|
||||||
}
|
|
||||||
ByteBuffer(const ByteBuffer &buf, uint32 extra = 0)
|
|
||||||
: _rpos(0), _wpos(0), _buf(NULL), _size(0), _growable(true)
|
|
||||||
{
|
|
||||||
_allocate(buf.size() + extra + 64);
|
|
||||||
append(buf);
|
|
||||||
}
|
|
||||||
ByteBuffer(void *buf, uint32 size, Mode mode = COPY, delete_func del = NULL, uint32 extra = 0)
|
|
||||||
: _rpos(0), _wpos(0), _size(size), _buf(NULL), _growable(true), _delfunc(del),
|
|
||||||
_mybuf(false) // for mode == REUSE
|
|
||||||
{
|
|
||||||
switch(mode)
|
|
||||||
{
|
|
||||||
case COPY:
|
|
||||||
_allocate(size + extra);
|
|
||||||
append(buf, size);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TAKE_OVER:
|
|
||||||
_mybuf = true; // fallthrough
|
|
||||||
case REUSE:
|
|
||||||
_buf = (uint8*)buf;
|
|
||||||
_res = size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~ByteBuffer()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear(void)
|
|
||||||
{
|
|
||||||
_delete();
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void reset(void)
|
|
||||||
{
|
|
||||||
_rpos = _wpos = _size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void resize(uint32 newsize)
|
|
||||||
{
|
|
||||||
reserve(newsize);
|
|
||||||
_rpos = 0;
|
|
||||||
_wpos = newsize;
|
|
||||||
_size = newsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserve(uint32 newsize)
|
|
||||||
{
|
|
||||||
if(_res < newsize)
|
|
||||||
_allocate(newsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------- Write methods -----------------------
|
|
||||||
|
|
||||||
BB_MAKE_WRITE_OP(uint8);
|
|
||||||
BB_MAKE_WRITE_OP(uint16);
|
|
||||||
BB_MAKE_WRITE_OP(uint32);
|
|
||||||
BB_MAKE_WRITE_OP(uint64);
|
|
||||||
BB_MAKE_WRITE_OP(float);
|
|
||||||
BB_MAKE_WRITE_OP(double);
|
|
||||||
BB_MAKE_WRITE_OP(int);
|
|
||||||
|
|
||||||
ByteBuffer &operator<<(bool value)
|
|
||||||
{
|
|
||||||
append<char>((char)value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer &operator<<(const char *str)
|
|
||||||
{
|
|
||||||
append((uint8 *)str, str ? strlen(str) : 0);
|
|
||||||
append((uint8)0);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer &operator<<(const std::string &value)
|
|
||||||
{
|
|
||||||
append((uint8 *)value.c_str(), value.length());
|
|
||||||
append((uint8)0);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------- Read methods --------------------
|
|
||||||
|
|
||||||
BB_MAKE_READ_OP(uint8);
|
|
||||||
BB_MAKE_READ_OP(uint16);
|
|
||||||
BB_MAKE_READ_OP(uint32);
|
|
||||||
BB_MAKE_READ_OP(uint64);
|
|
||||||
BB_MAKE_READ_OP(float);
|
|
||||||
BB_MAKE_READ_OP(double);
|
|
||||||
BB_MAKE_READ_OP(int);
|
|
||||||
|
|
||||||
ByteBuffer &operator>>(bool &value)
|
|
||||||
{
|
|
||||||
value = read<char>() > 0 ? true : false;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 operator[](uint32 pos)
|
|
||||||
{
|
|
||||||
return read<uint8>(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer &operator>>(std::string& value)
|
|
||||||
{
|
|
||||||
value.clear();
|
|
||||||
char c;
|
|
||||||
while(readable() && (c = read<char>()))
|
|
||||||
value += c;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------
|
|
||||||
|
|
||||||
uint32 rpos() const { return _rpos; }
|
|
||||||
uint32 rpos(uint32 rpos)
|
|
||||||
{
|
|
||||||
_rpos = rpos < size() ? rpos : size();
|
|
||||||
return _rpos;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 wpos() const { return _wpos; }
|
|
||||||
uint32 wpos(uint32 wpos)
|
|
||||||
{
|
|
||||||
_wpos = wpos < size() ? wpos : size();
|
|
||||||
return _wpos;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> T read()
|
|
||||||
{
|
|
||||||
T r = read<T>(_rpos);
|
|
||||||
_rpos += sizeof(T);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
template <typename T> T read(uint32 pos) const
|
|
||||||
{
|
|
||||||
if(pos + sizeof(T) > size())
|
|
||||||
throw Exception(this, "read", sizeof(T));
|
|
||||||
T val = *((T const*)(_buf + pos));
|
|
||||||
ToLittleEndian<T>(val);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void read(void *dest, uint32 len)
|
|
||||||
{
|
|
||||||
if (_rpos + len <= size())
|
|
||||||
memcpy(dest, &_buf[_rpos], len);
|
|
||||||
else
|
|
||||||
throw Exception(this, "read-into", len);
|
|
||||||
_rpos += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const uint8 *contents() const { return _buf; }
|
|
||||||
inline uint8 *contents() { return _buf; }
|
|
||||||
|
|
||||||
inline uint32 size() const { return _size; }
|
|
||||||
|
|
||||||
inline uint32 bytes() const { return size(); }
|
|
||||||
inline uint32 bits() const { return bytes() * 8; }
|
|
||||||
|
|
||||||
inline uint32 capacity() const { return _res; }
|
|
||||||
|
|
||||||
inline uint32 readable(void) const { return size() - rpos(); }
|
|
||||||
inline uint32 writable(void) const { return size() - wpos(); } // free space left before realloc will occur
|
|
||||||
|
|
||||||
template <typename T> void append(T value)
|
|
||||||
{
|
|
||||||
ToLittleEndian<T>(value);
|
|
||||||
_enlargeIfReq(_wpos + sizeof(T));
|
|
||||||
*((T*)(_buf + _wpos)) = value;
|
|
||||||
_wpos += sizeof(T);
|
|
||||||
if(_size < _wpos)
|
|
||||||
_size = _wpos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void append(const void *src, uint32 bytes)
|
|
||||||
{
|
|
||||||
if (!bytes) return;
|
|
||||||
_enlargeIfReq(_wpos + bytes);
|
|
||||||
memcpy(_buf + _wpos, src, bytes);
|
|
||||||
_wpos += bytes;
|
|
||||||
if(_size < _wpos)
|
|
||||||
_size = _wpos;
|
|
||||||
}
|
|
||||||
void append(const ByteBuffer& buffer)
|
|
||||||
{
|
|
||||||
if(buffer.size())
|
|
||||||
append(buffer.contents(), buffer.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void put(uint32 pos, const void *src, uint32 bytes)
|
|
||||||
{
|
|
||||||
memcpy(_buf + pos, src, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> void put(uint32 pos, T value)
|
|
||||||
{
|
|
||||||
if(pos >= size())
|
|
||||||
{
|
|
||||||
throw Exception(this, "put", sizeof(T));
|
|
||||||
}
|
|
||||||
ToLittleEndian<T>(value);
|
|
||||||
*((T*)(_buf + pos)) = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool growable(void) { return _growable; }
|
|
||||||
inline void growable(bool b) { _growable = b; }
|
|
||||||
|
|
||||||
// dangerous functions
|
|
||||||
|
|
||||||
void _setPtr(void *p)
|
|
||||||
{
|
|
||||||
_buf = (uint8*)p;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
void _delete(void)
|
|
||||||
{
|
|
||||||
if(_mybuf)
|
|
||||||
{
|
|
||||||
if(_delfunc)
|
|
||||||
_delfunc(_buf);
|
|
||||||
else
|
|
||||||
delete [] _buf;
|
|
||||||
_buf = NULL;
|
|
||||||
_res = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// allocate larger buffer and copy contents. if we own the current buffer, delete old, otherwise, leave it as it is.
|
|
||||||
void _allocate(uint32 s)
|
|
||||||
{
|
|
||||||
if(!_growable && _buf) // only throw if we already have a buf
|
|
||||||
throw Exception(this, "_alloc+locked", s);
|
|
||||||
|
|
||||||
uint8 *newbuf = (uint8*)malloc(s);
|
|
||||||
if(_buf)
|
|
||||||
{
|
|
||||||
memcpy(newbuf, _buf, _size);
|
|
||||||
_delete();
|
|
||||||
}
|
|
||||||
_delfunc = free;
|
|
||||||
_buf = newbuf;
|
|
||||||
_res = s;
|
|
||||||
_mybuf = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _enlargeIfReq(uint32 minSize)
|
|
||||||
{
|
|
||||||
if(_res < minSize)
|
|
||||||
{
|
|
||||||
uint32 a = _res * 2;
|
|
||||||
if(a < minSize) // fallback if doubling the space was not enough
|
|
||||||
a += minSize;
|
|
||||||
_allocate(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#undef BB_MAKE_WRITE_OP
|
|
||||||
#undef BB_MAKE_READ_OP
|
|
||||||
|
|
||||||
|
|
||||||
LVPA_NAMESPACE_END
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,46 +0,0 @@
|
||||||
#ifndef BYTECONVERTER_H
|
|
||||||
#define BYTECONVERTER_H
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include "LVPAInternal.h" // this is important to fix up any possible ***_ENDIAN misconfigurations
|
|
||||||
|
|
||||||
LVPA_NAMESPACE_START
|
|
||||||
|
|
||||||
namespace ByteConverter
|
|
||||||
{
|
|
||||||
template<size_t T>
|
|
||||||
inline void convert(char *val)
|
|
||||||
{
|
|
||||||
std::swap(*val, *(val + T - 1));
|
|
||||||
convert<T - 2>(val + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> inline void convert<0>(char *) {}
|
|
||||||
template<> inline void convert<1>(char *) {}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline void apply(T *val)
|
|
||||||
{
|
|
||||||
convert<sizeof(T)>((char *)(val));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if IS_BIG_ENDIAN
|
|
||||||
template<typename T> inline void ToLittleEndian(T& val) { ByteConverter::apply<T>(&val); }
|
|
||||||
template<typename T> inline void ToBigEndian(T&) { }
|
|
||||||
#else
|
|
||||||
template<typename T> inline void ToLittleEndian(T&) { }
|
|
||||||
template<typename T> inline void ToBigEndian(T& val) { ByteConverter::apply<T>(&val); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template<typename T> void ToLittleEndian(T*); // will generate link error
|
|
||||||
template<typename T> void ToBigEndian(T*); // will generate link error
|
|
||||||
|
|
||||||
inline void ToLittleEndian(uint8&) { }
|
|
||||||
inline void ToLittleEndian(int8&) { }
|
|
||||||
inline void ToBigEndian(uint8&) { }
|
|
||||||
inline void ToBigEndian( int8&) { }
|
|
||||||
|
|
||||||
LVPA_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,44 +0,0 @@
|
||||||
#ifndef LVPA_COMMON_H
|
|
||||||
#define LVPA_COMMON_H
|
|
||||||
|
|
||||||
#include "LVPACompileConfig.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
LVPA_NAMESPACE_START
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
typedef __int64 int64;
|
|
||||||
typedef long int32;
|
|
||||||
typedef short int16;
|
|
||||||
typedef char int8;
|
|
||||||
typedef unsigned __int64 uint64;
|
|
||||||
typedef unsigned long uint32;
|
|
||||||
typedef unsigned short uint16;
|
|
||||||
typedef unsigned char uint8;
|
|
||||||
#else
|
|
||||||
typedef long long int64;
|
|
||||||
typedef int int32;
|
|
||||||
typedef short int16;
|
|
||||||
typedef char int8;
|
|
||||||
typedef unsigned long long uint64;
|
|
||||||
typedef unsigned int uint32;
|
|
||||||
typedef unsigned short uint16;
|
|
||||||
typedef unsigned char uint8;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct memblock
|
|
||||||
{
|
|
||||||
memblock() : ptr(NULL), size(0) {}
|
|
||||||
memblock(uint8 *p, uint32 s) : size(s), ptr(p) {}
|
|
||||||
uint8 *ptr;
|
|
||||||
uint32 size;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
LVPA_NAMESPACE_END
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
#ifndef LVPA_COMPILE_CONFIG
|
|
||||||
#define LVPA_COMPILE_CONFIG
|
|
||||||
|
|
||||||
// TODO ADD TEXT
|
|
||||||
#define LVPA_NAMESPACE lvpa
|
|
||||||
|
|
||||||
//#define LVPA_SUPPORT_ZLIB
|
|
||||||
#define LVPA_SUPPORT_LZMA
|
|
||||||
//#define LVPA_SUPPORT_LZO
|
|
||||||
#define LVPA_SUPPORT_LZF
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------ End of config ------
|
|
||||||
|
|
||||||
#ifdef LVPA_NAMESPACE
|
|
||||||
# define LVPA_NAMESPACE_START namespace LVPA_NAMESPACE {
|
|
||||||
# define LVPA_NAMESPACE_END }
|
|
||||||
# define LVPA_NAMESPACE_IMPL LVPA_NAMESPACE::
|
|
||||||
namespace LVPA_NAMESPACE {} // predeclare namespace to make compilers happy
|
|
||||||
#else
|
|
||||||
# define LVPA_NAMESPACE_START
|
|
||||||
# define LVPA_NAMESPACE_END
|
|
||||||
# define LVPA_NAMESPACE_IMPL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,201 +0,0 @@
|
||||||
#ifndef LVPA_INTERNAL_H
|
|
||||||
#define LVPA_INTERNAL_H
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
# define DBG if(1)
|
|
||||||
# define DEBUG(x) x;
|
|
||||||
# define logdebug(...) { printf(__VA_ARGS__); putchar('\n'); }
|
|
||||||
# define logerror(...) { fputs("ERROR: ",stdout); printf(__VA_ARGS__); putchar('\n'); }
|
|
||||||
#else
|
|
||||||
# define DBG if(0)
|
|
||||||
# define DEBUG(x)
|
|
||||||
# define logdebug(...)
|
|
||||||
# define logerror(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////
|
|
||||||
// Platform defines
|
|
||||||
//////////////////////////////////////
|
|
||||||
|
|
||||||
#define PLATFORM_WIN32 0
|
|
||||||
#define PLATFORM_UNIX 1
|
|
||||||
#define PLATFORM_APPLE 2
|
|
||||||
#define PLATFORM_INTEL 3
|
|
||||||
|
|
||||||
#if defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 )
|
|
||||||
# define PLATFORM PLATFORM_WIN32
|
|
||||||
#elif defined( __APPLE_CC__ )
|
|
||||||
# define PLATFORM PLATFORM_APPLE
|
|
||||||
#elif defined( __INTEL_COMPILER )
|
|
||||||
# define PLATFORM PLATFORM_INTEL
|
|
||||||
#else
|
|
||||||
# define PLATFORM PLATFORM_UNIX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define COMPILER_MICROSOFT 0
|
|
||||||
#define COMPILER_GNU 1
|
|
||||||
#define COMPILER_BORLAND 2
|
|
||||||
#define COMPILER_INTEL 3
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
# define COMPILER COMPILER_MICROSOFT
|
|
||||||
#elif defined( __BORLANDC__ )
|
|
||||||
# define COMPILER COMPILER_BORLAND
|
|
||||||
#elif defined( __INTEL_COMPILER )
|
|
||||||
# define COMPILER COMPILER_INTEL
|
|
||||||
#elif defined( __GNUC__ )
|
|
||||||
# define COMPILER COMPILER_GNU
|
|
||||||
#else
|
|
||||||
# pragma error "FATAL ERROR: Unknown compiler."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// stupid warnings
|
|
||||||
#if COMPILER == COMPILER_MICROSOFT
|
|
||||||
# define _CRT_SECURE_NO_WARNINGS
|
|
||||||
# define _CRT_SECURE_NO_DEPRECATE
|
|
||||||
# pragma warning(disable: 4996)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////////
|
|
||||||
// Compiler defines
|
|
||||||
////////////////////////////////////
|
|
||||||
|
|
||||||
#if COMPILER == COMPILER_MICROSOFT
|
|
||||||
#define I64FMT "%016I64X"
|
|
||||||
#define I64FMTD "%I64u"
|
|
||||||
#define I64LIT(x) (x ## i64)
|
|
||||||
#define UI64LIT(x) (x ## ui64)
|
|
||||||
#define snprintf _snprintf
|
|
||||||
#else
|
|
||||||
#define stricmp strcasecmp
|
|
||||||
#define strnicmp strncasecmp
|
|
||||||
#define I64FMT "%016llX"
|
|
||||||
#define I64FMTD "%llu"
|
|
||||||
#define I64LIT(x) (x ## LL)
|
|
||||||
#define UI64LIT(x) (x ## ULL)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _LP64
|
|
||||||
# if defined (_M_IA64) || defined (__ia64__) || defined (_M_AMD64) || defined (__amd64) || defined(_M_X64)
|
|
||||||
# define _LP64 1
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _LP64 // to be set for 64 bit compile
|
|
||||||
# define PTRFMT "0x"I64FMT
|
|
||||||
# define SYSTEM_BITS 64
|
|
||||||
#else
|
|
||||||
# define PTRFMT "0x%X"
|
|
||||||
# define SYSTEM_BITS 32
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SIGQUIT
|
|
||||||
#define SIGQUIT 3
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if COMPILER == COMPILER_MICROSOFT
|
|
||||||
# if _MSC_VER >= 1600
|
|
||||||
# define COMPILER_NAME "VC100+"
|
|
||||||
# elif _MSC_VER >= 1500
|
|
||||||
# define COMPILER_NAME "VC90"
|
|
||||||
# elif _MSC_VER >= 1400
|
|
||||||
# define COMPILER_NAME "VC80"
|
|
||||||
# elif _MSC_VER >= 1310
|
|
||||||
# define COMPILER_NAME "VC71"
|
|
||||||
# endif
|
|
||||||
# define COMPILER_VERSION _MSC_VER
|
|
||||||
# define COMPILER_VERSION_OUT "%u"
|
|
||||||
#elif COMPILER == COMPILER_GNU
|
|
||||||
# define COMPILER_NAME "GCC"
|
|
||||||
# ifndef __GNUC_PATCHLEVEL__
|
|
||||||
# define __GNUC_PATCHLEVEL__ 0
|
|
||||||
# endif
|
|
||||||
# define COMPILER_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
|
||||||
# define COMPILER_VERSION_OUT "%u"
|
|
||||||
// TODO: add more compilers here when necessary
|
|
||||||
#else
|
|
||||||
# define COMPILER_NAME "unknown"
|
|
||||||
# define COMPILER_VERSION "unk"
|
|
||||||
# define COMPILER_VERSION_OUT "%s"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if PLATFORM == PLATFORM_UNIX
|
|
||||||
# define PLATFORM_NAME "Unix"
|
|
||||||
#elif PLATFORM == PLATFORM_WIN32
|
|
||||||
# define PLATFORM_NAME "Win32"
|
|
||||||
#elif PLATFORM == PLATFORM_APPLE
|
|
||||||
# define PLATFORM_NAME "Apple"
|
|
||||||
// TODO: add more platforms here when necessary
|
|
||||||
#else
|
|
||||||
# define PLATFORM_NAME "unknown"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if COMPILER == COMPILER_GNU
|
|
||||||
# define ATTR_NORETURN __attribute__((noreturn))
|
|
||||||
# define ATTR_PRINTF(F,V) __attribute__ ((format (printf, F, V)))
|
|
||||||
#else //COMPILER != COMPILER_GNU
|
|
||||||
# define ATTR_NORETURN
|
|
||||||
# define ATTR_PRINTF(F,V)
|
|
||||||
#endif //COMPILER == COMPILER_GNU
|
|
||||||
|
|
||||||
|
|
||||||
// taken from ACE
|
|
||||||
// have seen on some systems that both defines exist, so if that is is the case, rely on this detection here
|
|
||||||
#if (!defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)) || (defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN))
|
|
||||||
# if defined (i386) || defined (__i386__) || defined (_M_IX86) || \
|
|
||||||
defined (vax) || defined (__alpha) || defined (__LITTLE_ENDIAN__) || \
|
|
||||||
defined (ARM) || defined (_M_IA64) || defined (__ia64__) || \
|
|
||||||
defined (_M_AMD64) || defined (__amd64)
|
|
||||||
// We know these are little endian.
|
|
||||||
# undef LITTLE_ENDIAN
|
|
||||||
# undef BIG_ENDIAN
|
|
||||||
# define LITTLE_ENDIAN 1
|
|
||||||
# define IS_LITTLE_ENDIAN 1
|
|
||||||
# define IS_BIG_ENDIAN 0
|
|
||||||
# else
|
|
||||||
// Otherwise, we assume big endian.
|
|
||||||
# undef LITTLE_ENDIAN
|
|
||||||
# undef BIG_ENDIAN
|
|
||||||
# define BIG_ENDIAN 1
|
|
||||||
# define IS_LITTLE_ENDIAN 0
|
|
||||||
# define IS_BIG_ENDIAN 1
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#define ASSERT(what) { if (!(what)) { fprintf( stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n", __FILE__, __LINE__,__FUNCTION__, #what); assert( #what &&0 ); } }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "LVPACommon.h"
|
|
||||||
|
|
||||||
LVPA_NAMESPACE_START
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T> class AutoPtrVector
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
inline AutoPtrVector(uint32 prealloc) :v(prealloc)
|
|
||||||
{
|
|
||||||
for(uint32 i = 0; i < prealloc; ++i)
|
|
||||||
v[i] = NULL;
|
|
||||||
}
|
|
||||||
inline ~AutoPtrVector()
|
|
||||||
{
|
|
||||||
for(uint32 i = 0; i < v.size(); ++i)
|
|
||||||
if(v[i])
|
|
||||||
delete v[i];
|
|
||||||
}
|
|
||||||
std::vector<T*> v;
|
|
||||||
};
|
|
||||||
|
|
||||||
LVPA_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,64 +0,0 @@
|
||||||
|
|
||||||
option(TTVFS_LARGEFILE_SUPPORT "Enable support for files > 4 GB? (experimental!)" FALSE)
|
|
||||||
option(TTVFS_IGNORE_CASE "Enable full case-insensitivity even on case-sensitive OSes like Linux and alike?" FALSE)
|
|
||||||
|
|
||||||
# Be sure to copy this part to your root CMakeLists.txt if you prefer to use CMake for configuring
|
|
||||||
# instead of editing the headers directly!
|
|
||||||
# If you edit the headers, this is not necessary.
|
|
||||||
if(TTVFS_LARGEFILE_SUPPORT)
|
|
||||||
add_definitions("-DVFS_LARGEFILE_SUPPORT")
|
|
||||||
endif()
|
|
||||||
if(TTVFS_IGNORE_CASE)
|
|
||||||
add_definitions("-DVFS_IGNORE_CASE")
|
|
||||||
endif()
|
|
||||||
# --snip--
|
|
||||||
|
|
||||||
|
|
||||||
# compiler specific things
|
|
||||||
if(MSVC)
|
|
||||||
# MSVC builds require installed runtime library by default
|
|
||||||
option(TTVFS_STATIC_LIB "Link as static library without runtime dependencies (Note: To get rid of this setting with MSVC, the cmake cache must be cleared)" FALSE)
|
|
||||||
add_definitions("/GR-") # run-time type info (RTTI) not required
|
|
||||||
|
|
||||||
if(TTVFS_STATIC_LIB)
|
|
||||||
# this is ugly - hackfix compiler flags
|
|
||||||
foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
|
||||||
if(${flag_var} MATCHES "/MD")
|
|
||||||
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
|
|
||||||
endif(${flag_var} MATCHES "/MD")
|
|
||||||
if(${flag_var} MATCHES "/MDd")
|
|
||||||
string(REGEX REPLACE "/MDd" "/MTd" ${flag_var} "${${flag_var}}")
|
|
||||||
endif(${flag_var} MATCHES "/MDd")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
# hackfix linker flags - no idea why, but MSVC will produce linker errors otherwise
|
|
||||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /NODEFAULTLIB")
|
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /NODEFAULTLIB:msvcrt.lib,msvcrtd.lib") # not sure if this is correct
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /NODEFAULTLIB:msvcrt.lib,msvcrtd.lib")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
set(ttvfs_SRC
|
|
||||||
VFS.h
|
|
||||||
VFSAtomic.cpp
|
|
||||||
VFSAtomic.h
|
|
||||||
VFSDefines.h
|
|
||||||
VFSDir.cpp
|
|
||||||
VFSDir.h
|
|
||||||
VFSFile.cpp
|
|
||||||
VFSFile.h
|
|
||||||
VFSHelper.cpp
|
|
||||||
VFSHelper.h
|
|
||||||
VFSInternal.h
|
|
||||||
VFSLoader.cpp
|
|
||||||
VFSLoader.h
|
|
||||||
VFSSelfRefCounter.h
|
|
||||||
VFSTools.cpp
|
|
||||||
VFSTools.h
|
|
||||||
)
|
|
||||||
|
|
||||||
set(TTVFS_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} CACHE STRING "ttvfs include directory - for external includers" FORCE)
|
|
||||||
set(TTVFS_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE STRING "ttvfs source directory - for external includers" FORCE)
|
|
||||||
|
|
||||||
add_library(ttvfs ${ttvfs_SRC})
|
|
|
@ -1,78 +0,0 @@
|
||||||
/* ttvfs -- tiny tree virtual file system
|
|
||||||
|
|
||||||
// VFS.h - all the necessary includes to get a basic VFS working
|
|
||||||
// Only include externally, not inside the library.
|
|
||||||
|
|
||||||
See VFSDefines.h for compile configration.
|
|
||||||
|
|
||||||
|
|
||||||
---------[ License ]----------
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef TTVFS_VFS_H
|
|
||||||
#define TTVFS_VFS_H
|
|
||||||
|
|
||||||
#include "VFSDefines.h"
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
bool _checkCompatInternal(bool large, bool nocase, unsigned int vfspos_size);
|
|
||||||
|
|
||||||
/** It is recommended to call this function early in your code
|
|
||||||
and ensure it returns true - if it does not, compiler settings
|
|
||||||
are inconsistent, which may cause otherwise hard to detect problems. */
|
|
||||||
inline static bool checkCompat(void)
|
|
||||||
{
|
|
||||||
#ifdef VFS_LARGEFILE_SUPPORT
|
|
||||||
bool largefile = true;
|
|
||||||
#else
|
|
||||||
bool largefile = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef VFS_IGNORE_CASE
|
|
||||||
bool nocase = true;
|
|
||||||
#else
|
|
||||||
bool nocase = false;
|
|
||||||
#endif
|
|
||||||
return _checkCompatInternal(largefile, nocase, sizeof(vfspos));
|
|
||||||
}
|
|
||||||
VFS_NAMESPACE_END
|
|
||||||
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <string>
|
|
||||||
#include "VFSHelper.h"
|
|
||||||
#include "VFSFile.h"
|
|
||||||
#include "VFSDir.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Checks to enforce correct including.
|
|
||||||
// At least on windows, <string> includes <cstdio>,
|
|
||||||
// but that must be included after "VFSInternal.h",
|
|
||||||
// and "VFSInternal.h" may only be used inside the library (or by extensions),
|
|
||||||
// because it redefines fseek and ftell, which would
|
|
||||||
// mess up the ABI if included elsewhere.
|
|
||||||
#ifdef VFS_INTERNAL_H
|
|
||||||
#error Oops, VFS_INTERNAL_H is defined, someone messed up and included VFSInternal.h wrongly.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,103 +0,0 @@
|
||||||
// VFSAtomic.cpp - atomic operations and thread locking
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
/** --- Atomic operations and thread safety ---
|
|
||||||
* You may want to add your own implementation if thread safety is needed.
|
|
||||||
* If not, just leave everything like it is.
|
|
||||||
|
|
||||||
* If you are on windows, Interlocked[In/De]crement is faster than
|
|
||||||
explicit mutex locking for integer operations.
|
|
||||||
|
|
||||||
* TODO: The actual locking that is done in the tree when VFS_THREADSAFE is defined
|
|
||||||
is rather crude for the time beeing; a somewhat more efficient ReadWriteLock
|
|
||||||
implementation would be nice to have, someday.
|
|
||||||
|
|
||||||
* If you can, leave VFS_THREADSAFE undefined and do the locking externally,
|
|
||||||
it will probably have much better performance than if each and every operation
|
|
||||||
does a lock and unlock call.
|
|
||||||
(For a rather I/O based library this should not really make a difference, anyway.
|
|
||||||
But don't say you haven't been warned :) )
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "VFSInternal.h"
|
|
||||||
#include "VFSAtomic.h"
|
|
||||||
|
|
||||||
// for Interlocked[In/De]crement, if required
|
|
||||||
#if defined(_WIN32) && defined(VFS_THREADSAFE)
|
|
||||||
# define WIN32_LEAN_AND_MEAN
|
|
||||||
# include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
#ifdef VFS_THREADSAFE
|
|
||||||
static Mutex mtx;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int Atomic_Incr(volatile int &i)
|
|
||||||
{
|
|
||||||
#ifdef VFS_THREADSAFE
|
|
||||||
# ifdef _WIN32
|
|
||||||
volatile LONG* dp = (volatile LONG*) &i;
|
|
||||||
return InterlockedIncrement( dp );
|
|
||||||
# else
|
|
||||||
Guard g(mtx);
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
return ++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Atomic_Decr(volatile int &i)
|
|
||||||
{
|
|
||||||
#ifdef VFS_THREADSAFE
|
|
||||||
# ifdef _WIN32
|
|
||||||
volatile LONG* dp = (volatile LONG*) &i;
|
|
||||||
return InterlockedDecrement( dp );
|
|
||||||
# else
|
|
||||||
Guard g(mtx);
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
return --i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement your Mutex class here.
|
|
||||||
Important: The mutex must be re-entrant/recursive,
|
|
||||||
means it must be possible to lock it from the same thread multiple times.
|
|
||||||
*/
|
|
||||||
Mutex::Mutex()
|
|
||||||
{
|
|
||||||
// implement your own if needed. Remove the trap below when you are done.
|
|
||||||
// This is to prevent people from defining VFS_THREADSAFE and expecting everything to work just like that :)
|
|
||||||
#ifdef VFS_THREADSAFE
|
|
||||||
#error VFSAtomic: Hey, you forgot to implement the mutex class, cant guarantee thread safety! Either undef VFS_THREADSAFE or read the docs and get your hands dirty.
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
Mutex::~Mutex()
|
|
||||||
{
|
|
||||||
// implement your own if needed
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mutex::Lock(void)
|
|
||||||
{
|
|
||||||
// implement your own if needed
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mutex::Unlock(void)
|
|
||||||
{
|
|
||||||
// implement your own if needed
|
|
||||||
}
|
|
||||||
|
|
||||||
Guard::Guard(Mutex& m)
|
|
||||||
: _m(m)
|
|
||||||
{
|
|
||||||
_m.Lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
Guard::~Guard()
|
|
||||||
{
|
|
||||||
_m.Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
|
@ -1,39 +0,0 @@
|
||||||
// VFSAtomic.h - atomic operations and thread locking
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
#ifndef VFS_ATOMIC_H
|
|
||||||
#define VFS_ATOMIC_H
|
|
||||||
|
|
||||||
#include "VFSDefines.h"
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
int Atomic_Incr(volatile int &i);
|
|
||||||
int Atomic_Decr(volatile int &i);
|
|
||||||
|
|
||||||
// generic Mutex class, needs to be reentrant/recursive.
|
|
||||||
class Mutex
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Mutex();
|
|
||||||
~Mutex();
|
|
||||||
void Lock();
|
|
||||||
void Unlock();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// add own stuff if needed
|
|
||||||
};
|
|
||||||
|
|
||||||
class Guard
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Guard(Mutex& m);
|
|
||||||
~Guard();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Mutex& _m;
|
|
||||||
};
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,79 +0,0 @@
|
||||||
// VFSDefines.h - compile config and basic setup
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
#ifndef VFS_DEFINES_H
|
|
||||||
#define VFS_DEFINES_H
|
|
||||||
|
|
||||||
/* --- Config section -- modify as needed --- */
|
|
||||||
|
|
||||||
// choose a namespace name, or comment out to disable namespacing completely (not recommended)
|
|
||||||
#define VFS_NAMESPACE ttvfs
|
|
||||||
|
|
||||||
// Define this to allow dealing with files > 4 GB, using non-standard functions.
|
|
||||||
// This may or may not work with your platform/compiler, good luck.
|
|
||||||
//#define VFS_LARGEFILE_SUPPORT
|
|
||||||
|
|
||||||
// Define this to make all operations case insensitive.
|
|
||||||
// Windows systems generally don't care much, but for Linux and Mac this can be used
|
|
||||||
// to get the same behavior as on windows.
|
|
||||||
// Additionally, this achieves full case insensitivity within the library,
|
|
||||||
// if the the same files are accessed multiple times by the program, but with not-uniform case.
|
|
||||||
// (no sane programmer should do this, anyway).
|
|
||||||
// However, on non-windows systems this will decrease performance when checking for files
|
|
||||||
// on disk (see VFSLoader.cpp).
|
|
||||||
#define VFS_IGNORE_CASE
|
|
||||||
|
|
||||||
// Define this to make all VFSFile, VFSDir, VFSHelper operations thread-safe.
|
|
||||||
// If you do, do not forget to add your own implementation to VFSAtomic.cpp/.h !
|
|
||||||
// If this is not defined, you can still do manual locking if you know what you're doing,
|
|
||||||
// performance matters, and you implemented actual locking into the Mutex class.
|
|
||||||
// If no Mutex implementation is provided, its operations are no-ops, beware!
|
|
||||||
//#define VFS_THREADSAFE
|
|
||||||
|
|
||||||
|
|
||||||
/* --- End of config section --- */
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef VFS_NAMESPACE
|
|
||||||
# define VFS_NAMESPACE_START namespace VFS_NAMESPACE {
|
|
||||||
# define VFS_NAMESPACE_END }
|
|
||||||
# define VFS_NAMESPACE_IMPL VFS_NAMESPACE::
|
|
||||||
#else
|
|
||||||
# define VFS_NAMESPACE_START
|
|
||||||
# define VFS_NAMESPACE_END
|
|
||||||
# define VFS_NAMESPACE_IMPL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
#ifdef VFS_LARGEFILE_SUPPORT
|
|
||||||
# if defined(_MSC_VER)
|
|
||||||
typedef __int64 vfspos;
|
|
||||||
# else
|
|
||||||
typedef long long vfspos;
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
typedef unsigned int vfspos;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// simple guard wrapper, works also if VFS_THREADSAFE is not defined
|
|
||||||
#define VFS_GUARD(obj) VFS_NAMESPACE_IMPL Guard __vfs_stack_guard((obj)->mutex())
|
|
||||||
|
|
||||||
// defines for optional auto-locking; only if VFS_THREADSAFE is defined
|
|
||||||
#ifdef VFS_THREADSAFE
|
|
||||||
# define VFS_GUARD_OPT(obj) VFS_GUARD(obj)
|
|
||||||
#else
|
|
||||||
# define VFS_GUARD_OPT(obj)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
# define VFS_STRICMP stricmp
|
|
||||||
#else
|
|
||||||
# define VFS_STRICMP strcasecmp
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const vfspos npos = vfspos(-1);
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,255 +0,0 @@
|
||||||
// VFSDir.cpp - basic directory interface + classes
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
#include "VFSInternal.h"
|
|
||||||
#include "VFSTools.h"
|
|
||||||
#include "VFSFile.h"
|
|
||||||
#include "VFSDir.h"
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
VFSDir::VFSDir()
|
|
||||||
: ref(this), _name(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSDir::VFSDir(const char *fullpath)
|
|
||||||
: ref(this)
|
|
||||||
{
|
|
||||||
_setFullName(fullpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSDir::~VFSDir()
|
|
||||||
{
|
|
||||||
for(Files::iterator it = _files.begin(); it != _files.end(); it++)
|
|
||||||
it->second->ref--;
|
|
||||||
for(Dirs::iterator it = _subdirs.begin(); it != _subdirs.end(); it++)
|
|
||||||
it->second->ref--;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFSDir::_setFullName(const char *fullname)
|
|
||||||
{
|
|
||||||
_fullname = FixPath(fullname);
|
|
||||||
_name = PathToFileName(_fullname.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSDir *VFSDir::createNew(void) const
|
|
||||||
{
|
|
||||||
return new VFSDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int VFSDir::load(const char *dir /* = NULL */)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool VFSDir::add(VFSFile *f, bool overwrite /* = true */)
|
|
||||||
{
|
|
||||||
if(!f)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
|
|
||||||
Files::iterator it = _files.find(f->name());
|
|
||||||
|
|
||||||
if(it != _files.end())
|
|
||||||
{
|
|
||||||
if(overwrite)
|
|
||||||
{
|
|
||||||
VFSFile *oldf = it->second;
|
|
||||||
if(oldf == f)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
oldf->ref--;
|
|
||||||
_files.erase(it);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
f->ref++;
|
|
||||||
_files[f->name()] = f;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSDir::addRecursive(VFSFile *f, bool overwrite /* = true */)
|
|
||||||
{
|
|
||||||
if(!f)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
|
|
||||||
// figure out directory from full file name
|
|
||||||
std::string dirname(f->fullname());
|
|
||||||
size_t pathend = dirname.find_last_of("/\\");
|
|
||||||
VFSDir *vdir;
|
|
||||||
if(pathend != std::string::npos)
|
|
||||||
{
|
|
||||||
dirname = dirname.substr(0, pathend);
|
|
||||||
vdir = getDir(dirname.c_str(), true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
vdir = this;
|
|
||||||
|
|
||||||
return vdir->add(f, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSDir::merge(VFSDir *dir, bool overwrite /* = true */)
|
|
||||||
{
|
|
||||||
if(!dir)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool result = false;
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
|
|
||||||
for(Files::iterator it = dir->_files.begin(); it != dir->_files.end(); it++)
|
|
||||||
result = add(it->second, overwrite) || result;
|
|
||||||
|
|
||||||
for(Dirs::iterator it = dir->_subdirs.begin(); it != dir->_subdirs.end(); it++)
|
|
||||||
result = insert(it->second, overwrite) || result;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSDir::insert(VFSDir *subdir, bool overwrite /* = true */)
|
|
||||||
{
|
|
||||||
if(!subdir)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
Dirs::iterator it = _subdirs.find(subdir->name());
|
|
||||||
VFSDir *mydir;
|
|
||||||
if(it != _subdirs.end())
|
|
||||||
{
|
|
||||||
mydir = it->second;
|
|
||||||
//return it->second->merge(subdir, overwrite);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// create a new subtree, not to pollute the original one with data that may be added later
|
|
||||||
mydir = subdir->createNew(); // create subdir of same type
|
|
||||||
mydir->_setFullName(subdir->fullname());
|
|
||||||
_subdirs[mydir->name()] = mydir;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mydir->merge(subdir, overwrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSFile *VFSDir::getFile(const char *fn)
|
|
||||||
{
|
|
||||||
char *slashpos = (char *)strchr(fn, '/');
|
|
||||||
|
|
||||||
// if there is a '/' in the string, descend into subdir and continue there
|
|
||||||
if(slashpos)
|
|
||||||
{
|
|
||||||
const char *sub = slashpos + 1;
|
|
||||||
std::string t(fn, slashpos - fn);
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
VFSDir *subdir = getDir(t.c_str()); // fn is null-terminated early here
|
|
||||||
return subdir ? subdir->getFile(sub) : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no subdir? file must be in this dir now.
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
Files::iterator it = _files.find(fn);
|
|
||||||
return it != _files.end() ? it->second : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSDir *VFSDir::getDir(const char *subdir, bool forceCreate /* = false */)
|
|
||||||
{
|
|
||||||
if(!subdir[0] || (subdir[0] == '.' && (!subdir[1] || subdir[1] == '/'))) // empty string or "." or "./" ? use this.
|
|
||||||
return this;
|
|
||||||
|
|
||||||
VFSDir *ret = NULL;
|
|
||||||
char *slashpos = (char *)strchr(subdir, '/');
|
|
||||||
|
|
||||||
// if there is a '/' in the string, descend into subdir and continue there
|
|
||||||
if(slashpos)
|
|
||||||
{
|
|
||||||
const char *sub = slashpos + 1;
|
|
||||||
std::string t(subdir, slashpos - subdir);
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
Dirs::iterator it = _subdirs.find(t);
|
|
||||||
if(it != _subdirs.end())
|
|
||||||
{
|
|
||||||
ret = it->second->getDir(sub, forceCreate); // descend into subdirs
|
|
||||||
}
|
|
||||||
else if(forceCreate)
|
|
||||||
{
|
|
||||||
VFSDir *ins = createNew();
|
|
||||||
std::string newname(fullname());
|
|
||||||
newname += '/';
|
|
||||||
newname += t;
|
|
||||||
ins->_setFullName(newname.c_str());
|
|
||||||
_subdirs[ins->name()] = ins;
|
|
||||||
ret = ins->getDir(sub, true); // create remaining structure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
Dirs::iterator it = _subdirs.find(subdir);
|
|
||||||
if(it != _subdirs.end())
|
|
||||||
ret = it->second;
|
|
||||||
else if(forceCreate)
|
|
||||||
{
|
|
||||||
ret = createNew();
|
|
||||||
std::string newname(fullname());
|
|
||||||
newname += '/';
|
|
||||||
newname += subdir;
|
|
||||||
ret->_setFullName(newname.c_str());
|
|
||||||
_subdirs[ret->name()] = ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ----- VFSDirReal start here -----
|
|
||||||
|
|
||||||
|
|
||||||
VFSDirReal::VFSDirReal() : VFSDir()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSDir *VFSDirReal::createNew(void) const
|
|
||||||
{
|
|
||||||
return new VFSDirReal;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int VFSDirReal::load(const char *dir /* = NULL */)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(dir)
|
|
||||||
_setFullName(dir);
|
|
||||||
|
|
||||||
StringList li;
|
|
||||||
GetFileList(_fullname.c_str(), li);
|
|
||||||
for(StringList::iterator it = li.begin(); it != li.end(); it++)
|
|
||||||
{
|
|
||||||
if(VFSFile *oldf = getFile(it->c_str()))
|
|
||||||
oldf->ref--;
|
|
||||||
VFSFileReal *f = new VFSFileReal((_fullname + '/' + *it).c_str());
|
|
||||||
_files[f->name()] = f;
|
|
||||||
}
|
|
||||||
unsigned int sum = li.size();
|
|
||||||
|
|
||||||
li.clear();
|
|
||||||
GetDirList(_fullname.c_str(), li, false);
|
|
||||||
for(std::deque<std::string>::iterator it = li.begin(); it != li.end(); it++)
|
|
||||||
{
|
|
||||||
if(VFSDir *oldd = getDir(it->c_str()))
|
|
||||||
oldd->ref--;
|
|
||||||
VFSDir *d = createNew();
|
|
||||||
std::string full(_fullname);
|
|
||||||
full += '/';
|
|
||||||
full += *it;
|
|
||||||
sum += d->load(full.c_str()); // GetDirList() always returns relative paths
|
|
||||||
_subdirs[d->name()] = d;
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
|
@ -1,118 +0,0 @@
|
||||||
// VFSDir.h - basic directory interface + classes
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
#ifndef VFSDIR_H
|
|
||||||
#define VFSDIR_H
|
|
||||||
|
|
||||||
#include "VFSDefines.h"
|
|
||||||
#include <map>
|
|
||||||
#include "VFSSelfRefCounter.h"
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
#ifdef VFS_IGNORE_CASE
|
|
||||||
# ifdef _MSC_VER
|
|
||||||
# pragma warning(push)
|
|
||||||
# pragma warning(disable: 4996)
|
|
||||||
# endif
|
|
||||||
|
|
||||||
struct ci_less
|
|
||||||
{
|
|
||||||
inline bool operator() (const std::string& a, const std::string& b) const
|
|
||||||
{
|
|
||||||
return VFS_STRICMP(a.c_str(), b.c_str()) < 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
# ifdef _MSC_VER
|
|
||||||
# pragma warning(pop)
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
class VFSDir;
|
|
||||||
class VFSFile;
|
|
||||||
|
|
||||||
class VFSDir
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
#ifdef VFS_IGNORE_CASE
|
|
||||||
typedef std::map<std::string, VFSDir*, ci_less> Dirs;
|
|
||||||
typedef std::map<std::string, VFSFile*, ci_less> Files;
|
|
||||||
#else
|
|
||||||
typedef std::map<std::string, VFSDir*> Dirs;
|
|
||||||
typedef std::map<std::string, VFSFile*> Files;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
VFSDir();
|
|
||||||
VFSDir(const char *fullpath);
|
|
||||||
virtual ~VFSDir();
|
|
||||||
|
|
||||||
/* Load directory with given path. If dir is NULL, reload previously loaded directory.
|
|
||||||
If there is no previously loaded directory, load root. */
|
|
||||||
virtual unsigned int load(const char *dir = NULL);
|
|
||||||
virtual VFSFile *getFile(const char *fn);
|
|
||||||
virtual VFSDir *getDir(const char *subdir, bool forceCreate = false);
|
|
||||||
virtual VFSDir *createNew(void) const;
|
|
||||||
virtual const char *getType(void) const { return "VFSDir"; }
|
|
||||||
|
|
||||||
bool insert(VFSDir *subdir, bool overwrite = true);
|
|
||||||
bool merge(VFSDir *dir, bool overwrite = true);
|
|
||||||
bool add(VFSFile *f, bool overwrite = true); // add file directly in this dir
|
|
||||||
bool addRecursive(VFSFile *f, bool overwrite = true); // traverse subdir tree to find correct subdir; create if not existing
|
|
||||||
|
|
||||||
|
|
||||||
inline const char *name() const { VFS_GUARD_OPT(this); return _name; }
|
|
||||||
inline const char *fullname() const { VFS_GUARD_OPT(this); return _fullname.c_str(); }
|
|
||||||
|
|
||||||
// iterators are NOT thread-safe! If you need to iterate over things in a multithreaded environment,
|
|
||||||
// do the locking yourself! (see below)
|
|
||||||
inline Files::iterator fileIter() { return _files.begin(); }
|
|
||||||
inline Files::iterator fileIterEnd() { return _files.end(); }
|
|
||||||
inline Dirs::iterator dirIter() { return _subdirs.begin(); }
|
|
||||||
inline Dirs::iterator dirIterEnd() { return _subdirs.end(); }
|
|
||||||
inline Files::const_iterator fileIter() const { return _files.begin(); }
|
|
||||||
inline Files::const_iterator fileIterEnd() const { return _files.end(); }
|
|
||||||
inline Dirs::const_iterator dirIter() const { return _subdirs.begin(); }
|
|
||||||
inline Dirs::const_iterator dirIterEnd() const { return _subdirs.end(); }
|
|
||||||
|
|
||||||
// std::map<std::string,*> stores for files and subdirs
|
|
||||||
Files _files;
|
|
||||||
Dirs _subdirs;
|
|
||||||
|
|
||||||
// reference counter, does auto-delete holder when it reaches 0. initially 1.
|
|
||||||
SelfRefCounter<VFSDir> ref;
|
|
||||||
|
|
||||||
// the following functions should be used before and after an iteration finishes
|
|
||||||
// alternatively, VFS_GUARD(dir) can be used to create a locking guard on the stack.
|
|
||||||
inline void lock() { _mtx.Lock(); }
|
|
||||||
inline void unlock() { _mtx.Unlock(); }
|
|
||||||
inline Mutex& mutex() const { return _mtx; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void _setFullName(const char *fullname);
|
|
||||||
std::string _fullname;
|
|
||||||
const char *_name; // must point to an address constant during object lifetime (like _fullname.c_str() + N)
|
|
||||||
// (not necessary to have an additional string copy here, just wastes memory)
|
|
||||||
mutable Mutex _mtx;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef VFSDir::Files::iterator FileIter;
|
|
||||||
typedef VFSDir::Dirs::iterator DirIter;
|
|
||||||
typedef VFSDir::Files::const_iterator ConstFileIter;
|
|
||||||
typedef VFSDir::Dirs::const_iterator ConstDirIter;
|
|
||||||
|
|
||||||
class VFSDirReal : public VFSDir
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VFSDirReal();
|
|
||||||
virtual ~VFSDirReal() {};
|
|
||||||
virtual unsigned int load(const char *dir = NULL);
|
|
||||||
virtual VFSDir *createNew(void) const;
|
|
||||||
virtual const char *getType(void) const { return "VFSDirReal"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,258 +0,0 @@
|
||||||
// VFSFile.cpp - basic file interface + classes
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
#include "VFSInternal.h"
|
|
||||||
#include "VFSFile.h"
|
|
||||||
#include "VFSTools.h"
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
VFSFile::VFSFile()
|
|
||||||
: ref(this)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSFileReal::VFSFileReal(const char *name /* = NULL */)
|
|
||||||
: VFSFile()
|
|
||||||
{
|
|
||||||
_buf = NULL;
|
|
||||||
_setName(name);
|
|
||||||
_fh = NULL;
|
|
||||||
_size = npos;
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSFileReal::~VFSFileReal()
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
dropBuf(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// call this only with a lock held!
|
|
||||||
void VFSFileReal::_setName(const char *n)
|
|
||||||
{
|
|
||||||
if(n && *n)
|
|
||||||
{
|
|
||||||
_fullname = FixPath(n);
|
|
||||||
_name = PathToFileName(_fullname.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSFileReal::open(const char *fn /* = NULL */, const char *mode /* = NULL */)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
|
|
||||||
if(isopen())
|
|
||||||
close();
|
|
||||||
|
|
||||||
dropBuf(true);
|
|
||||||
|
|
||||||
_setName(fn);
|
|
||||||
|
|
||||||
_fh = fopen(_fullname.c_str(), mode ? mode : "rb");
|
|
||||||
if(!_fh)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
fseek((FILE*)_fh, 0, SEEK_END);
|
|
||||||
_size = getpos();
|
|
||||||
fseek((FILE*)_fh, 0, SEEK_SET);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSFileReal::isopen(void) const
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
return !!_fh;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSFileReal::iseof(void) const
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
return !_fh || feof((FILE*)_fh);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *VFSFileReal::name(void) const
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *VFSFileReal::fullname(void) const
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
return _fullname.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSFileReal::close(void)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(_fh)
|
|
||||||
{
|
|
||||||
fclose((FILE*)_fh);
|
|
||||||
_fh = NULL;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSFileReal::seek(vfspos pos)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(!_fh)
|
|
||||||
return false;
|
|
||||||
fseek((FILE*)_fh, pos, SEEK_SET);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSFileReal::seekRel(vfspos offs)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(!_fh)
|
|
||||||
return false;
|
|
||||||
fseek((FILE*)_fh, offs, SEEK_CUR);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSFileReal::flush(void)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(_fh)
|
|
||||||
return false;
|
|
||||||
fflush((FILE*)_fh);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
vfspos VFSFileReal::getpos(void) const
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(!_fh)
|
|
||||||
return npos;
|
|
||||||
return ftell((FILE*)_fh);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int VFSFileReal::read(void *dst, unsigned int bytes)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(!_fh)
|
|
||||||
return npos;
|
|
||||||
return fread(dst, 1, bytes, (FILE*)_fh);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int VFSFileReal::write(const void *src, unsigned int bytes)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(!_fh)
|
|
||||||
return npos;
|
|
||||||
return fwrite(src, 1, bytes, (FILE*)_fh);
|
|
||||||
}
|
|
||||||
|
|
||||||
vfspos VFSFileReal::size(void)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(_size != npos)
|
|
||||||
return _size;
|
|
||||||
open();
|
|
||||||
close();
|
|
||||||
// now size is known.
|
|
||||||
return _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
const void *VFSFileReal::getBuf(void)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(_buf)
|
|
||||||
return _buf;
|
|
||||||
|
|
||||||
bool op = isopen();
|
|
||||||
|
|
||||||
if(!op && !open()) // open with default params if not open
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
unsigned int s = (unsigned int)size();
|
|
||||||
_buf = malloc(s + 4); // a bit extra padding
|
|
||||||
if(!_buf)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if(op)
|
|
||||||
{
|
|
||||||
vfspos oldpos = getpos();
|
|
||||||
seek(0);
|
|
||||||
unsigned int offs = read(_buf, s);
|
|
||||||
memset((char*)_buf + offs, 0, 4);
|
|
||||||
seek(oldpos);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unsigned int offs = read(_buf, s);
|
|
||||||
memset((char*)_buf + offs, 0, 4);
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
return _buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFSFileReal::dropBuf(bool del)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(del && _buf)
|
|
||||||
free(_buf);
|
|
||||||
_buf = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------- VFSFileMem -----------------------
|
|
||||||
|
|
||||||
VFSFileMem::VFSFileMem(const char *name, void *buf, unsigned int size, Mode mode /* = COPY */, delete_func delfunc /* = NULL */)
|
|
||||||
: VFSFile(), _pos(0), _size(size), _buf(buf), _delfunc(delfunc), _mybuf(mode == TAKE_OVER || mode == COPY)
|
|
||||||
{
|
|
||||||
_setName(name);
|
|
||||||
if(mode == COPY)
|
|
||||||
{
|
|
||||||
_buf = malloc(size+1);
|
|
||||||
_delfunc = free;
|
|
||||||
memcpy(_buf, buf, size);
|
|
||||||
((char*)_buf)[size] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSFileMem::~VFSFileMem()
|
|
||||||
{
|
|
||||||
if(_mybuf)
|
|
||||||
{
|
|
||||||
if(_delfunc)
|
|
||||||
_delfunc(_buf);
|
|
||||||
else
|
|
||||||
delete [] (char*)_buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void VFSFileMem::_setName(const char *n)
|
|
||||||
{
|
|
||||||
if(n && *n)
|
|
||||||
{
|
|
||||||
_fullname = FixPath(n);
|
|
||||||
_name = PathToFileName(_fullname.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int VFSFileMem::read(void *dst, unsigned int bytes)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(iseof())
|
|
||||||
return 0;
|
|
||||||
unsigned int rem = std::min<unsigned int>((unsigned int)(_size - _pos), bytes);
|
|
||||||
|
|
||||||
memcpy(dst, (char*)_buf + _pos, rem);
|
|
||||||
return rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int VFSFileMem::write(const void *src, unsigned int bytes)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(iseof())
|
|
||||||
return 0;
|
|
||||||
unsigned int rem = std::min<unsigned int>((unsigned int)(_size - _pos), bytes);
|
|
||||||
|
|
||||||
memcpy((char*)_buf + _pos, src, rem);
|
|
||||||
return rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
|
@ -1,183 +0,0 @@
|
||||||
// VFSFile.h - basic file interface + classes
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
#ifndef VFSFILE_H
|
|
||||||
#define VFSFILE_H
|
|
||||||
|
|
||||||
#include "VFSDefines.h"
|
|
||||||
#include "VFSSelfRefCounter.h"
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
|
|
||||||
/** -- VFSFile basic interface --
|
|
||||||
* All functions that return bool should return true on success and false on failure.
|
|
||||||
* If an operation is not necessary or irrelevant (for example, files in memory can't be closed),
|
|
||||||
* it is useful to return true anyways, because this operation did not fail, technically.
|
|
||||||
* (Common sense here!)
|
|
||||||
* An int/vfspos value of 0 indicates failure, except the size/seek/getpos functions, where npos means failure.
|
|
||||||
* Only the functions required or applicable need to be implemented, for unsupported operations
|
|
||||||
* the default implementation should be sufficient.
|
|
||||||
**/
|
|
||||||
class VFSFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/** The ctor is expected to set both name() and fullname(). */
|
|
||||||
VFSFile();
|
|
||||||
|
|
||||||
virtual ~VFSFile() {};
|
|
||||||
|
|
||||||
/** Open a file. If fn is NULL (the default), open fullname().
|
|
||||||
Mode can be "r", "w", "rb", "rb", and possibly other things that fopen supports.
|
|
||||||
It is the subclass's choice to support other modes. Default is "rb". */
|
|
||||||
virtual bool open(const char *fn = NULL, const char *mode = NULL) { return false; }
|
|
||||||
virtual bool isopen(void) const { return false; }
|
|
||||||
virtual bool iseof(void) const { return true; }
|
|
||||||
|
|
||||||
/** Returns the plain file name. Never NULL. */
|
|
||||||
virtual const char *name(void) const { return ""; }
|
|
||||||
|
|
||||||
/** Returns the file name with full path. Never NULL. */
|
|
||||||
virtual const char *fullname(void) const { return ""; }
|
|
||||||
|
|
||||||
virtual bool close(void) { return true; }
|
|
||||||
virtual bool seek(vfspos pos) { return false; }
|
|
||||||
|
|
||||||
/** Seek relative to current position. Negative numbers will seek backwards.
|
|
||||||
(In most cases, the default implementation does not have to be changed) */
|
|
||||||
virtual bool seekRel(vfspos offs) { VFS_GUARD_OPT(this); return seek(getpos() + offs); }
|
|
||||||
|
|
||||||
virtual bool flush(void) { return true; }
|
|
||||||
|
|
||||||
/** Current offset in file. Return npos if NA. */
|
|
||||||
virtual vfspos getpos(void) const { return npos; }
|
|
||||||
|
|
||||||
virtual unsigned int read(void *dst, unsigned int bytes) { return 0; }
|
|
||||||
virtual unsigned int write(const void *src, unsigned int bytes) { return 0; }
|
|
||||||
|
|
||||||
/** Return file size. If NA, return npos. If size is not yet known,
|
|
||||||
open() and close() may be called (with default args) to find out the size.
|
|
||||||
The file is supposed to be in its old state when the function returns,
|
|
||||||
that is in the same open state and seek position.
|
|
||||||
The pointer returned by getBuf() must not change. */
|
|
||||||
virtual vfspos size(void) { return npos; }
|
|
||||||
|
|
||||||
/** Attempt to increase file size. Returns new size after completion.
|
|
||||||
May return any size. Failure is indicated by a size() that didn't change. */
|
|
||||||
virtual vfspos size(vfspos newsize) { return size(); }
|
|
||||||
|
|
||||||
/** Return full file content in memory. Like size(), this may do other operations on the file,
|
|
||||||
but after the function returns the file is expected to be in the same state it was before.
|
|
||||||
If the file is not open before the call, it will be opened with default parameters (that is, "rb").
|
|
||||||
Addition EOL mangling my happen if the file is opened in text mode before (= not binary).
|
|
||||||
Calls to open() should delete this memory if the file was previously opened in a different mode.
|
|
||||||
The returned memory is not guaranteed to be writable without problems, so don't do it.
|
|
||||||
Don't cast the const away. You have been warned.
|
|
||||||
This memory can be freed with free(), after calling dropBuf(false). */
|
|
||||||
virtual const void *getBuf(void) { return NULL; }
|
|
||||||
|
|
||||||
/** If del is true, delete internal buffer. If false, unregister internal buffer from the file,
|
|
||||||
but do not delete. Use free() later. */
|
|
||||||
virtual void dropBuf(bool del) {}
|
|
||||||
|
|
||||||
/** Basic RTTI, for debugging purposes */
|
|
||||||
virtual const char *getType(void) const { return "<BASE>"; }
|
|
||||||
|
|
||||||
|
|
||||||
/** Reference count, if the pointer to this file is stored somewhere it is advisable to increase
|
|
||||||
(ref++) it. If it reaches 0, this file is deleted automatically. */
|
|
||||||
SelfRefCounter<VFSFile> ref;
|
|
||||||
|
|
||||||
|
|
||||||
inline void lock() { _mtx.Lock(); }
|
|
||||||
inline void unlock() { _mtx.Unlock(); }
|
|
||||||
inline Mutex& mutex() const { return _mtx; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
mutable Mutex _mtx;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VFSFileReal : public VFSFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VFSFileReal(const char *name = NULL);
|
|
||||||
virtual ~VFSFileReal();
|
|
||||||
virtual bool open(const char *fn = NULL, const char *mode = NULL);
|
|
||||||
virtual bool isopen(void) const;
|
|
||||||
virtual bool iseof(void) const;
|
|
||||||
virtual const char *name(void) const;
|
|
||||||
virtual const char *fullname(void) const;
|
|
||||||
virtual bool close(void);
|
|
||||||
virtual bool seek(vfspos pos);
|
|
||||||
virtual bool seekRel(vfspos offs);
|
|
||||||
virtual bool flush(void);
|
|
||||||
virtual vfspos getpos(void) const;
|
|
||||||
virtual unsigned int read(void *dst, unsigned int bytes);
|
|
||||||
virtual unsigned int write(const void *src, unsigned int bytes);
|
|
||||||
virtual vfspos size(void);
|
|
||||||
virtual const void *getBuf(void);
|
|
||||||
virtual void dropBuf(bool del);
|
|
||||||
virtual const char *getType(void) const { return "disk"; }
|
|
||||||
|
|
||||||
inline void *getFP() { return _fh; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void _setName(const char *n);
|
|
||||||
std::string _fullname;
|
|
||||||
const char *_name;
|
|
||||||
void *_fh; // FILE*
|
|
||||||
vfspos _size;
|
|
||||||
void *_buf;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VFSFileMem : public VFSFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Mode
|
|
||||||
{
|
|
||||||
COPY, //- Make a copy of the buffer (default action).
|
|
||||||
REUSE, //- Use the passed-in buffer as is. Requires the pointer
|
|
||||||
// to remain valid over the life of this object.
|
|
||||||
TAKE_OVER, //- Take over the passed-in buffer; it will be deleted on object destruction.
|
|
||||||
};
|
|
||||||
typedef void (*delete_func)(void*);
|
|
||||||
|
|
||||||
/* Creates a virtual file from a memory buffer. By default, the memory is copied.
|
|
||||||
A deletor function can be passed optionally, if its NULL (the default),
|
|
||||||
delete[] (char*)buf will be used. For malloc()'d memory, pass free. (Only used if mode is TAKE_OVER) */
|
|
||||||
VFSFileMem(const char *name, void *buf, unsigned int size, Mode m = COPY, delete_func delfunc = NULL);
|
|
||||||
virtual ~VFSFileMem();
|
|
||||||
virtual bool open(const char *fn = NULL, const char *mode = NULL) { return true; }
|
|
||||||
virtual bool isopen(void) const { return true; } // always open
|
|
||||||
virtual bool iseof(void) const { VFS_GUARD_OPT(this); return _pos >= _size; }
|
|
||||||
virtual const char *name(void) const { VFS_GUARD_OPT(this); return _name; }
|
|
||||||
virtual const char *fullname(void) const { VFS_GUARD_OPT(this); return _fullname.c_str(); }
|
|
||||||
virtual bool close(void) { return true; } // cant close, but not a problem
|
|
||||||
virtual bool seek(vfspos pos) { VFS_GUARD_OPT(this); _pos = pos; return true; }
|
|
||||||
virtual bool seekRel(vfspos offs) { VFS_GUARD_OPT(this); _pos += offs; return true; }
|
|
||||||
virtual bool flush(void) { return false; } // can't flush, if a successful file write is expected, this IS a problem.
|
|
||||||
virtual vfspos getpos(void) const { VFS_GUARD_OPT(this); return _pos; }
|
|
||||||
virtual unsigned int read(void *dst, unsigned int bytes);
|
|
||||||
virtual unsigned int write(const void *src, unsigned int bytes);
|
|
||||||
virtual vfspos size(void) { VFS_GUARD_OPT(this); return _size; }
|
|
||||||
virtual const void *getBuf(void) { VFS_GUARD_OPT(this); return _buf; }
|
|
||||||
virtual void dropBuf(bool) {} // we can't simply drop the internal buffer, as the file is entirely memory based
|
|
||||||
virtual const char *getSource(void) const { return "mem"; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void _setName(const char *n);
|
|
||||||
std::string _fullname;
|
|
||||||
const char *_name;
|
|
||||||
vfspos _pos;
|
|
||||||
vfspos _size;
|
|
||||||
void *_buf;
|
|
||||||
delete_func _delfunc;
|
|
||||||
bool _mybuf;
|
|
||||||
};
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,350 +0,0 @@
|
||||||
// VFSHelper.cpp - glues it all together and makes use simple
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
#include <iostream> // for debug only, see EOF
|
|
||||||
|
|
||||||
#include "VFSInternal.h"
|
|
||||||
#include "VFSHelper.h"
|
|
||||||
#include "VFSAtomic.h"
|
|
||||||
#include "VFSTools.h"
|
|
||||||
|
|
||||||
#include "VFSDir.h"
|
|
||||||
#include "VFSFile.h"
|
|
||||||
#include "VFSLoader.h"
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
# include <cassert>
|
|
||||||
# define DEBUG_ASSERT(x) assert(x)
|
|
||||||
#else
|
|
||||||
# define DEBUG_ASSERT(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
// predecl is in VFS.h
|
|
||||||
bool _checkCompatInternal(bool large, bool nocase, unsigned int vfspos_size)
|
|
||||||
{
|
|
||||||
#ifdef VFS_LARGEFILE_SUPPORT
|
|
||||||
bool largefile_i = true;
|
|
||||||
#else
|
|
||||||
bool largefile_i = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef VFS_IGNORE_CASE
|
|
||||||
bool nocase_i = true;
|
|
||||||
#else
|
|
||||||
bool nocase_i = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return (large == largefile_i)
|
|
||||||
&& (nocase == nocase_i)
|
|
||||||
&& (sizeof(vfspos) == vfspos_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSHelper::VFSHelper()
|
|
||||||
: filesysRoot(NULL), merged(NULL)
|
|
||||||
{
|
|
||||||
_ldrDiskId = _AddFixedLoader(); // NULL intentionally. created by LoadFileSysRoot()
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSHelper::~VFSHelper()
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFSHelper::Clear(void)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
_cleanup();
|
|
||||||
|
|
||||||
if(filesysRoot)
|
|
||||||
{
|
|
||||||
filesysRoot->ref--; // this should always delete it...
|
|
||||||
filesysRoot = NULL; // ...but it may be referenced elsewhere, just in case
|
|
||||||
}
|
|
||||||
|
|
||||||
for(unsigned int i = 0; i < preRoot.size(); ++i)
|
|
||||||
preRoot[i]->ref--;
|
|
||||||
preRoot.clear();
|
|
||||||
|
|
||||||
for(unsigned int i = 0; i < postRoot.size(); ++i)
|
|
||||||
postRoot[i]->ref--;
|
|
||||||
postRoot.clear();
|
|
||||||
|
|
||||||
for(unsigned int i = 0; i < FixedLoadersCount(); ++i)
|
|
||||||
if(fixedLdrs[i])
|
|
||||||
{
|
|
||||||
delete fixedLdrs[i];
|
|
||||||
fixedLdrs[i] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int VFSHelper::_AddFixedLoader(VFSLoader *ldr /* = NULL */)
|
|
||||||
{
|
|
||||||
fixedLdrs.push_back(ldr);
|
|
||||||
return FixedLoadersCount() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFSHelper::_cleanup(void)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this); // be extra safe and ensure this is locked
|
|
||||||
if(merged)
|
|
||||||
{
|
|
||||||
merged->ref--;
|
|
||||||
merged = NULL;
|
|
||||||
}
|
|
||||||
for(VFSMountList::iterator it = vlist.begin(); it != vlist.end(); ++it)
|
|
||||||
it->vdir->ref--;
|
|
||||||
vlist.clear();
|
|
||||||
for(LoaderList::iterator it = dynLdrs.begin(); it != dynLdrs.end(); ++it)
|
|
||||||
delete *it;
|
|
||||||
dynLdrs.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSHelper::LoadFileSysRoot(void)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
VFSDirReal *oldroot = filesysRoot;
|
|
||||||
|
|
||||||
filesysRoot = new VFSDirReal;
|
|
||||||
if(!filesysRoot->load("."))
|
|
||||||
{
|
|
||||||
filesysRoot->ref--;
|
|
||||||
filesysRoot = oldroot;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!fixedLdrs[_ldrDiskId])
|
|
||||||
fixedLdrs[_ldrDiskId] = new VFSLoaderDisk;
|
|
||||||
|
|
||||||
if(oldroot)
|
|
||||||
oldroot->ref--;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFSHelper::Prepare(bool clear /* = true */)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(clear)
|
|
||||||
_cleanup();
|
|
||||||
if(!merged)
|
|
||||||
{
|
|
||||||
merged = new VFSDir("");
|
|
||||||
}
|
|
||||||
|
|
||||||
for(size_t i = 0; i < preRoot.size(); ++i)
|
|
||||||
merged->merge(preRoot[i]);
|
|
||||||
if(filesysRoot)
|
|
||||||
merged->merge(filesysRoot);
|
|
||||||
for(size_t i = 0; i < postRoot.size(); ++i)
|
|
||||||
merged->merge(postRoot[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFSHelper::Reload(bool fromDisk /* = false */)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(fromDisk)
|
|
||||||
LoadFileSysRoot();
|
|
||||||
Prepare(false);
|
|
||||||
for(VFSMountList::iterator it = vlist.begin(); it != vlist.end(); it++)
|
|
||||||
GetDir(it->mountPoint.c_str(), true)->merge(it->vdir, it->overwrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSHelper::Mount(const char *src, const char *dest, bool overwrite /* = true*/)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
return AddVFSDir(GetDir(src, false), dest, overwrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSHelper::AddVFSDir(VFSDir *dir, const char *subdir /* = NULL */, bool overwrite /* = true */)
|
|
||||||
{
|
|
||||||
if(!dir)
|
|
||||||
return false;
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
if(!subdir)
|
|
||||||
subdir = dir->fullname();
|
|
||||||
VFSDir *sd = GetDir(subdir, true);
|
|
||||||
if(!sd) // may be NULL if Prepare() was not called before
|
|
||||||
return false;
|
|
||||||
dir->ref++; // because this is to be added to vlist
|
|
||||||
VDirEntry ve(dir, subdir, overwrite);
|
|
||||||
_StoreMountPoint(ve);
|
|
||||||
sd->merge(dir, overwrite); // merge into specified subdir. will be (virtually) created if not existing
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSHelper::Unmount(const char *src, const char *dest)
|
|
||||||
{
|
|
||||||
VFSDir *vd = GetDir(src, false);
|
|
||||||
if(!vd)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
VDirEntry ve(vd, dest, true); // last is dummy
|
|
||||||
if(!_RemoveMountPoint(ve))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Reload(false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFSHelper::_StoreMountPoint(const VDirEntry& ve)
|
|
||||||
{
|
|
||||||
// scan through and ensure only one mount point with the same data is present.
|
|
||||||
// if present, remove and re-add, this ensures the mount point is at the end of the list
|
|
||||||
for(VFSMountList::iterator it = vlist.begin(); it != vlist.end(); )
|
|
||||||
{
|
|
||||||
const VDirEntry& oe = *it;
|
|
||||||
if(ve.mountPoint == oe.mountPoint && ve.vdir == oe.vdir
|
|
||||||
&& (ve.overwrite || !oe.overwrite) ) // overwrite definitely, or if other does not overwrite
|
|
||||||
{
|
|
||||||
it = vlist.erase(it); // do not break; just in case there are more (fixme?)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
vlist.push_back(ve);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSHelper::_RemoveMountPoint(const VDirEntry& ve)
|
|
||||||
{
|
|
||||||
for(VFSMountList::iterator it = vlist.begin(); it != vlist.end(); ++it)
|
|
||||||
{
|
|
||||||
const VDirEntry& oe = *it;
|
|
||||||
if(ve.mountPoint == oe.mountPoint && ve.vdir == oe.vdir)
|
|
||||||
{
|
|
||||||
vlist.erase(it);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFSHelper::MountExternalPath(const char *path, const char *where /* = "" */)
|
|
||||||
{
|
|
||||||
// no guard required here, AddVFSDir has one, and the reference count is locked as well.
|
|
||||||
VFSDirReal *vfs = new VFSDirReal;
|
|
||||||
if(vfs->load(path))
|
|
||||||
AddVFSDir(vfs, where);
|
|
||||||
return !!--(vfs->ref); // 0 if deleted
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFSHelper::AddLoader(VFSLoader *ldr)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
dynLdrs.push_back(ldr);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static VFSFile *VFSHelper_GetFileByLoader(VFSLoader *ldr, const char *fn, VFSDir *root)
|
|
||||||
{
|
|
||||||
if(!ldr)
|
|
||||||
return NULL;
|
|
||||||
VFSFile *vf = ldr->Load(fn);
|
|
||||||
if(vf)
|
|
||||||
{
|
|
||||||
root->addRecursive(vf, true);
|
|
||||||
--(vf->ref);
|
|
||||||
}
|
|
||||||
return vf;
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSFile *VFSHelper::GetFile(const char *fn)
|
|
||||||
{
|
|
||||||
while(fn[0] == '.' && fn[1] == '/')
|
|
||||||
fn += 2;
|
|
||||||
|
|
||||||
VFSFile *vf = NULL;
|
|
||||||
|
|
||||||
// guarded block
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
|
|
||||||
if(!merged) // Prepare() called?
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
vf = merged->getFile(fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// nothing found? maybe a loader has something.
|
|
||||||
// if so, add the newly created VFSFile to the tree.
|
|
||||||
// constant, no locking required here - also a bad idea in case a loader does heavy I/O
|
|
||||||
if(!vf)
|
|
||||||
for(unsigned int i = 0; i < fixedLdrs.size(); ++i)
|
|
||||||
if((vf = VFSHelper_GetFileByLoader(fixedLdrs[i], fn, GetDirRoot())))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if(!vf)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
for(LoaderList::iterator it = dynLdrs.begin(); it != dynLdrs.end(); ++it)
|
|
||||||
if((vf = VFSHelper_GetFileByLoader(*it, fn, GetDirRoot())))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//printf("VFS: GetFile '%s' -> '%s' (%p)\n", fn, vf ? vf->fullname() : "NULL", vf);
|
|
||||||
|
|
||||||
return vf;
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSDir *VFSHelper::GetDir(const char* dn, bool create /* = false */)
|
|
||||||
{
|
|
||||||
while(dn[0] == '.' && dn[1] == '/')
|
|
||||||
dn += 2;
|
|
||||||
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
return (merged && *dn) ? merged->getDir(dn, create) : merged;
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSDir *VFSHelper::GetDirRoot(void)
|
|
||||||
{
|
|
||||||
VFS_GUARD_OPT(this);
|
|
||||||
return merged;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// DEBUG STUFF
|
|
||||||
|
|
||||||
static void _DumpTreeRecursive(std::ostream& os, VFSDir *vd, const std::string& sp, VFSDir *parent)
|
|
||||||
{
|
|
||||||
std::string sub = sp + " ";
|
|
||||||
|
|
||||||
os << sp << "d|" << vd->name() << " [" << vd->getType() << ", ref " << vd->ref.count() << ", 0x" << vd << "]";
|
|
||||||
|
|
||||||
if(parent && strncmp(parent->fullname(), vd->fullname(), strlen(parent->fullname())))
|
|
||||||
os << " <-- {" << vd->fullname() << "} ***********";
|
|
||||||
os << std::endl;
|
|
||||||
|
|
||||||
for(DirIter it = vd->_subdirs.begin(); it != vd->_subdirs.end(); ++it)
|
|
||||||
_DumpTreeRecursive(os, it->second, sub, vd);
|
|
||||||
|
|
||||||
for(FileIter it = vd->_files.begin(); it != vd->_files.end(); ++it)
|
|
||||||
{
|
|
||||||
VFSFile *vf = it->second;
|
|
||||||
// only if refcount and/or mount point differs
|
|
||||||
bool p = false;
|
|
||||||
if(vf->ref.count() != vd->ref.count())
|
|
||||||
{
|
|
||||||
doprint:
|
|
||||||
os << sub << "f|" << vf->name() << " [" << vf->getType() << ", ref " << vf->ref.count() << ", 0x" << vf << "]";
|
|
||||||
p = true;
|
|
||||||
}
|
|
||||||
if(strncmp(vd->fullname(), vf->fullname(), strlen(vd->fullname())))
|
|
||||||
{
|
|
||||||
if(!p)
|
|
||||||
goto doprint;
|
|
||||||
os << " <-- {" << vf->fullname() << "} ***********";
|
|
||||||
}
|
|
||||||
if(p)
|
|
||||||
os << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFSHelper::debugDumpTree(std::ostream& os, VFSDir *start /* = NULL */)
|
|
||||||
{
|
|
||||||
_DumpTreeRecursive(os, start ? start : GetDirRoot(), "", NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
|
@ -1,192 +0,0 @@
|
||||||
// VFSHelper.h - glues it all together and makes use simple
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
#ifndef VFSHELPER_H
|
|
||||||
#define VFSHELPER_H
|
|
||||||
|
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
|
||||||
#include <deque>
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#include "VFSAtomic.h"
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
class VFSDir;
|
|
||||||
class VFSDirReal;
|
|
||||||
class VFSFile;
|
|
||||||
class VFSLoader;
|
|
||||||
|
|
||||||
|
|
||||||
/** VFSHelper - extensible class to simplify working with the VFS tree
|
|
||||||
* Contains a set of useful functions that should be useful for anyone.
|
|
||||||
* This class may be overridden to support adding any source in a comfortable way.
|
|
||||||
*
|
|
||||||
* Note: This class uses VFS_LAST_HELPER_CLASS, which should always store the last
|
|
||||||
* class derived from VFSHelper. This is supposed to make it easy to make extensions like this:
|
|
||||||
|
|
||||||
#include "VFSHelperExtra.h" // defines a VFSHelperExtra class that is somehow derived from VFSHelper
|
|
||||||
// and follows the same rules as explained below.
|
|
||||||
|
|
||||||
class VFSHelperArchive : public VFS_LAST_HELPER_CLASS
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
typedef VFS_LAST_HELPER_CLASS super;
|
|
||||||
public:
|
|
||||||
// .... class members ....
|
|
||||||
};
|
|
||||||
|
|
||||||
#undef VFS_LAST_HELPER_CLASS
|
|
||||||
#define VFS_LAST_HELPER_CLASS VFSHelperArchive
|
|
||||||
|
|
||||||
|
|
||||||
* Used this way, only the order in which VFSHelper extension classes are included matters.
|
|
||||||
* No code changes are required to get a nice inheritance and priority chain working.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef VFS_LAST_HELPER_CLASS
|
|
||||||
# error VFS_LAST_HELPER_CLASS defined before VFSHelper class decl, check your include order!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class VFSHelper
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VFSHelper();
|
|
||||||
virtual ~VFSHelper();
|
|
||||||
|
|
||||||
/** Creates the working tree. Required before any files or directories can be accessed.
|
|
||||||
Internally, it merges all individual VFS trees into one. If clear is true (default),
|
|
||||||
an existing merged tree is dropped, and old and previously added files and loaders removed.
|
|
||||||
(This is the recommended setting.) */
|
|
||||||
virtual void Prepare(bool clear = true);
|
|
||||||
|
|
||||||
/** Re-merges any files in the tree, and optionally reloads files on disk.
|
|
||||||
This is useful if files on disk were created or removed, and the tree needs to reflect these changes. */
|
|
||||||
virtual void Reload(bool fromDisk = false);
|
|
||||||
|
|
||||||
/** Reset an instance to its initial state */
|
|
||||||
virtual void Clear(void);
|
|
||||||
|
|
||||||
/** Load all files from working directory (into an internal tree) */
|
|
||||||
bool LoadFileSysRoot(void);
|
|
||||||
|
|
||||||
/** Mount a directory in the tree to a different location. Requires a previous call to Prepare().
|
|
||||||
This can be imagined like a symlink pointing to a different location.
|
|
||||||
Be careful not to create circles, this might technically work,
|
|
||||||
but confuses the reference counting, causing memory leaks. */
|
|
||||||
bool Mount(const char *src, const char *dest, bool overwrite = true);
|
|
||||||
|
|
||||||
/** Drops a directory from the tree. Internally, this calls Reload(false),
|
|
||||||
which is a heavy operation compared to Mount(). Be warned. */
|
|
||||||
bool Unmount(const char *src, const char *dest);
|
|
||||||
|
|
||||||
/** Merges a path into the tree. Requires a previous call to Prepare().
|
|
||||||
By default the directory is added into the root directory of the merged tree.
|
|
||||||
Pass NULL to add the directory to its original location,
|
|
||||||
or any other path to add it to that explicit location.
|
|
||||||
It is advised not to use this to re-add parts already in the tree; use Mount() instead.
|
|
||||||
Rule of thumb: If you called LoadFileSysRoot(), do not use this for subdirs. */
|
|
||||||
bool MountExternalPath(const char *path, const char *where = "");
|
|
||||||
|
|
||||||
/** Adds a VFSDir object into the merged tree. If subdir is NULL (the default),
|
|
||||||
add into the subdir stored in the VFSDir object. The tree will be extended if target dir does not exist.
|
|
||||||
If overwrite is true (the default), files in the tree will be replaced if already existing.
|
|
||||||
Requires a previous call to Prepare().
|
|
||||||
Like with Mount(); be careful not to create cycles. */
|
|
||||||
bool AddVFSDir(VFSDir *dir, const char *subdir = NULL, bool overwrite = true);
|
|
||||||
|
|
||||||
/** Add a loader that can look for files on demand.
|
|
||||||
It will be deleted if Prepare(true) is called.
|
|
||||||
It is possible (but not a good idea) to add a loader multiple times. */
|
|
||||||
inline void AddLoader(VFSLoader *ldr);
|
|
||||||
|
|
||||||
/** Get a file from the merged tree. Requires a previous call to Prepare().
|
|
||||||
Asks loaders if the file is not in the tree. If found by a loader, the file will be added to the tree.
|
|
||||||
The returned pointer is reference counted. In case the file pointer is stored elsewhere,
|
|
||||||
do ptr->ref++, and later ptr->ref--. This is to prevent the VFS tree from deleting the file when cleaning up.
|
|
||||||
Not necessary if the pointer is just retrieved and used, or temp. stored while the VFS tree is not modified. */
|
|
||||||
VFSFile *GetFile(const char *fn);
|
|
||||||
|
|
||||||
/** Get a directory from the merged tree. If create is true and the directory does not exist,
|
|
||||||
build the tree structure and return the newly created dir. NULL otherwise.
|
|
||||||
Requires a previous call to Prepare().
|
|
||||||
Reference counted, same as GetFile(), look there for more info. */
|
|
||||||
VFSDir *GetDir(const char* dn, bool create = false);
|
|
||||||
|
|
||||||
/** Returns the tree root, which is usually the working directory. */
|
|
||||||
VFSDir *GetDirRoot(void);
|
|
||||||
|
|
||||||
/** Remove a file or directory from the tree */
|
|
||||||
//bool Remove(VFSFile *vf);
|
|
||||||
//bool Remove(VFSDir *dir);
|
|
||||||
//bool Remove(const char *name); // TODO: CODE ME
|
|
||||||
|
|
||||||
/** This depends on the class type and stays constant. */
|
|
||||||
inline unsigned int FixedLoadersCount(void) const { return (unsigned int)fixedLdrs.size(); }
|
|
||||||
|
|
||||||
inline void lock() { _mtx.Lock(); }
|
|
||||||
inline void unlock() { _mtx.Unlock(); }
|
|
||||||
inline Mutex& mutex() const { return _mtx; }
|
|
||||||
|
|
||||||
// DEBUG STUFF
|
|
||||||
void debugDumpTree(std::ostream& os, VFSDir *start = NULL);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/** Drops the merged tree and additional mount points and dynamic loaders.
|
|
||||||
Overload to do additional cleanup if required. Invoked by Clear() and Prepare(true). */
|
|
||||||
virtual void _cleanup(void);
|
|
||||||
|
|
||||||
/** Add a fixed VFSLoader. Returns its array index in fixedLdrs. */
|
|
||||||
unsigned int _AddFixedLoader(VFSLoader *ldr = NULL);
|
|
||||||
|
|
||||||
struct VDirEntry
|
|
||||||
{
|
|
||||||
VDirEntry() : vdir(NULL), overwrite(false) {}
|
|
||||||
VDirEntry(VFSDir *v, std::string mp, bool ow) : vdir(v), mountPoint(mp), overwrite(ow) {}
|
|
||||||
VFSDir *vdir;
|
|
||||||
std::string mountPoint;
|
|
||||||
bool overwrite;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::list<VDirEntry> VFSMountList;
|
|
||||||
typedef std::vector<VFSLoader*> LoaderArray;
|
|
||||||
typedef std::deque<VFSLoader*> LoaderList;
|
|
||||||
typedef std::vector<VFSDir*> DirArray;
|
|
||||||
|
|
||||||
|
|
||||||
void _StoreMountPoint(const VDirEntry& ve);
|
|
||||||
|
|
||||||
bool _RemoveMountPoint(const VDirEntry& ve);
|
|
||||||
|
|
||||||
// the VFSDirs are merged in their declaration order.
|
|
||||||
// when merging, files already contained can be overwritten by files merged in later.
|
|
||||||
VFSDirReal *filesysRoot; // local files on disk (root dir)
|
|
||||||
|
|
||||||
// Additional tree stores, to be filled by subclasses if needed.
|
|
||||||
DirArray preRoot; // VFSDirs in here will be merged in, before the actual disk files.
|
|
||||||
// Means files on disk will overwrite existing entries.
|
|
||||||
DirArray postRoot; // Will be merged after the disk files, and overwrite prev. merged files.
|
|
||||||
// Both may contain NULLs.
|
|
||||||
|
|
||||||
// if files are not in the tree, maybe one of these is able to find it. May contain NULLs.
|
|
||||||
LoaderArray fixedLdrs; // defined by class type, stays constant during object lifetime
|
|
||||||
LoaderList dynLdrs; // dynamically added on demand, deleted on _cleanup()
|
|
||||||
|
|
||||||
VFSDir *merged; // contains the merged virtual/actual file system tree
|
|
||||||
|
|
||||||
mutable Mutex _mtx;
|
|
||||||
|
|
||||||
private:
|
|
||||||
unsigned int _ldrDiskId;
|
|
||||||
VFSMountList vlist; // all other dirs added later, together with path to mount to
|
|
||||||
};
|
|
||||||
|
|
||||||
#undef VFS_LAST_HELPER_CLASS
|
|
||||||
#define VFS_LAST_HELPER_CLASS VFSHelper
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,43 +0,0 @@
|
||||||
// VFSInternal.h - misc things that are not required to be visible outside of the library.
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
// !! this file is supposed to be included ONLY from VFS*.cpp files.
|
|
||||||
|
|
||||||
#ifndef VFS_INTERNAL_H
|
|
||||||
#define VFS_INTERNAL_H
|
|
||||||
|
|
||||||
// checks to enforcecorrect including
|
|
||||||
#ifdef TTVFS_VFS_H
|
|
||||||
#error Oops, TTVFS_VFS_H is defined, someone messed up and included VFS.h wrongly.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "VFSDefines.h"
|
|
||||||
|
|
||||||
#if _MSC_VER
|
|
||||||
# define _CRT_SECURE_NO_WARNINGS
|
|
||||||
# define _CRT_SECURE_NO_DEPRECATE
|
|
||||||
# pragma warning(disable: 4355) // 'this' : used in base member initializer list
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// this is for POSIX - define before including any stdio headers
|
|
||||||
#ifdef VFS_LARGEFILE_SUPPORT
|
|
||||||
# ifndef _MSC_VER
|
|
||||||
# define _FILE_OFFSET_BITS 64
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstring>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// this is for MSVC - re-define functions
|
|
||||||
#ifdef VFS_LARGEFILE_SUPPORT
|
|
||||||
# ifdef _MSC_VER
|
|
||||||
# define fseek _fseeki64
|
|
||||||
# define ftell _ftelli64
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,102 +0,0 @@
|
||||||
// VFSLoader.cpp - late loading of files not in the tree
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
#include "VFSInternal.h"
|
|
||||||
#include "VFSTools.h"
|
|
||||||
#include "VFSFile.h"
|
|
||||||
#include "VFSLoader.h"
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
#if !defined(_WIN32) && defined(VFS_IGNORE_CASE)
|
|
||||||
|
|
||||||
#include <sys/dir.h>
|
|
||||||
|
|
||||||
// based on code in PhysicsFS: http://icculus.org/physfs/
|
|
||||||
static bool locateOneElement(char *buf)
|
|
||||||
{
|
|
||||||
char *ptr;
|
|
||||||
DIR *dirp;
|
|
||||||
|
|
||||||
ptr = strrchr(buf, '/'); // find entry at end of path.
|
|
||||||
if (ptr == NULL)
|
|
||||||
{
|
|
||||||
dirp = opendir(".");
|
|
||||||
ptr = buf;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*ptr = '\0';
|
|
||||||
dirp = opendir(buf);
|
|
||||||
*ptr = '/';
|
|
||||||
ptr++; // point past dirsep to entry itself.
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dirent *dent;
|
|
||||||
while ((dent = readdir(dirp)) != NULL)
|
|
||||||
{
|
|
||||||
if (strcasecmp(dent->d_name, ptr) == 0)
|
|
||||||
{
|
|
||||||
strcpy(ptr, dent->d_name); // found a match. Overwrite with this case.
|
|
||||||
closedir(dirp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no match at all...
|
|
||||||
closedir(dirp);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool findFileHarder(char *fn)
|
|
||||||
{
|
|
||||||
char *ptr = fn;
|
|
||||||
bool found = true;
|
|
||||||
while ((ptr = strchr(ptr + 1, '/')) != 0)
|
|
||||||
{
|
|
||||||
*ptr = '\0';
|
|
||||||
found = locateOneElement(fn);
|
|
||||||
*ptr = '/'; // restore path separator
|
|
||||||
if (!found)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check final element...
|
|
||||||
found = found && locateOneElement(fn);
|
|
||||||
|
|
||||||
printf("tt: Fixed case '%s' [%s]\n", fn, found ? "found" : "NOT FOUND"); // TEMP
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
VFSFile *VFSLoaderDisk::Load(const char *fn)
|
|
||||||
{
|
|
||||||
if(FileExists(fn))
|
|
||||||
return new VFSFileReal(fn); // must contain full file name
|
|
||||||
|
|
||||||
#if !defined(_WIN32) && defined(VFS_IGNORE_CASE)
|
|
||||||
size_t s = strlen(fn);
|
|
||||||
if(s < 511) // avoid using malloc() and alloca() for short strings
|
|
||||||
{
|
|
||||||
char t[512];
|
|
||||||
memcpy(&t[0], fn, s+1); // copy terminating '\0' as well
|
|
||||||
if(findFileHarder(&t[0])) // fixes the filename on the way
|
|
||||||
return new VFSFileReal(&t[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char *t = (char*)malloc(s+1);
|
|
||||||
VFSFileReal *vf = NULL;
|
|
||||||
memcpy(t, fn, s+1);
|
|
||||||
if(findFileHarder(&t[0]))
|
|
||||||
vf = new VFSFileReal(&t[0]);
|
|
||||||
free(t);
|
|
||||||
return vf;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
|
@ -1,31 +0,0 @@
|
||||||
// VFSLoader.h - late loading of files not in the tree
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
#ifndef VFSLOADER_H
|
|
||||||
#define VFSLOADER_H
|
|
||||||
|
|
||||||
#include "VFSDefines.h"
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
class VFSFile;
|
|
||||||
|
|
||||||
// VFSLoader - to be called if a file is not in the tree.
|
|
||||||
class VFSLoader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~VFSLoader() {}
|
|
||||||
virtual VFSFile *Load(const char *fn) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VFSLoaderDisk : public VFSLoader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~VFSLoaderDisk() {}
|
|
||||||
virtual VFSFile *Load(const char *fn);
|
|
||||||
};
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,44 +0,0 @@
|
||||||
#ifndef SELFREFCOUNTER_H
|
|
||||||
#define SELFREFCOUNTER_H
|
|
||||||
|
|
||||||
#include "VFSDefines.h"
|
|
||||||
#include "VFSAtomic.h"
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
// self must point to the object that holds the counter.
|
|
||||||
template <class T, bool DELSELF = true> class SelfRefCounter
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
T *self;
|
|
||||||
volatile int c;
|
|
||||||
SelfRefCounter(SelfRefCounter& r); // forbid copy constructor
|
|
||||||
inline unsigned int _deref(void)
|
|
||||||
{
|
|
||||||
unsigned int cc = (unsigned int)Atomic_Decr(c); // copy c, in case we get deleted
|
|
||||||
if(DELSELF && !cc)
|
|
||||||
{
|
|
||||||
delete self;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
SelfRefCounter(T *p): self(p), c(1) {}
|
|
||||||
~SelfRefCounter() { /* DEBUG(ASSERT(c <= 1)); */ } // its ok if the last reference calls delete instead of _deref()
|
|
||||||
inline unsigned int count(void) { return c; }
|
|
||||||
|
|
||||||
// post-increment (dummy int)
|
|
||||||
inline unsigned int operator++(int) { unsigned int cc = c; Atomic_Incr(c); return cc; }
|
|
||||||
inline unsigned int operator--(int) { unsigned int cc = c; _deref(); return cc; }
|
|
||||||
|
|
||||||
// pre-increment
|
|
||||||
inline unsigned int operator++(void) { return (unsigned int)Atomic_Incr(c); }
|
|
||||||
inline unsigned int operator--(void) { return _deref(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,427 +0,0 @@
|
||||||
// VFSTools.cpp - useful functions and misc stuff
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
#include "VFSInternal.h"
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cctype>
|
|
||||||
#include <stack>
|
|
||||||
#include "VFSTools.h"
|
|
||||||
|
|
||||||
|
|
||||||
#if _WIN32
|
|
||||||
# define WIN32_LEAN_AND_MEAN
|
|
||||||
# include <windows.h>
|
|
||||||
#else
|
|
||||||
# include <sys/dir.h>
|
|
||||||
# include <sys/stat.h>
|
|
||||||
# include <sys/types.h>
|
|
||||||
# include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
std::string stringToLower(std::string s)
|
|
||||||
{
|
|
||||||
std::transform(s.begin(), s.end(), s.begin(), tolower);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string stringToUpper(std::string s)
|
|
||||||
{
|
|
||||||
std::transform(s.begin(), s.end(), s.begin(), toupper);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeLowercase(std::string& s)
|
|
||||||
{
|
|
||||||
std::transform(s.begin(), s.end(), s.begin(), tolower);
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeUppercase(std::string& s)
|
|
||||||
{
|
|
||||||
std::transform(s.begin(), s.end(), s.begin(), toupper);
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns list of *plain* file names in given directory,
|
|
||||||
// without paths, and without anything else
|
|
||||||
void GetFileList(const char *path, StringList& files)
|
|
||||||
{
|
|
||||||
#if !_WIN32
|
|
||||||
DIR * dirp;
|
|
||||||
struct dirent * dp;
|
|
||||||
dirp = opendir(path);
|
|
||||||
if(dirp)
|
|
||||||
{
|
|
||||||
while((dp=readdir(dirp)) != NULL)
|
|
||||||
{
|
|
||||||
if (dp->d_type != DT_DIR) // only add if it is not a directory
|
|
||||||
{
|
|
||||||
std::string s(dp->d_name);
|
|
||||||
files.push_back(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(dirp);
|
|
||||||
}
|
|
||||||
|
|
||||||
# else
|
|
||||||
|
|
||||||
WIN32_FIND_DATA fil;
|
|
||||||
std::string search(path);
|
|
||||||
MakeSlashTerminated(search);
|
|
||||||
search += "*";
|
|
||||||
HANDLE hFil = FindFirstFile(search.c_str(),&fil);
|
|
||||||
if(hFil != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if(!(fil.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
||||||
{
|
|
||||||
std::string s(fil.cFileName);
|
|
||||||
files.push_back(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while(FindNextFile(hFil, &fil));
|
|
||||||
|
|
||||||
FindClose(hFil);
|
|
||||||
}
|
|
||||||
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns a list of directory names in the given directory, *without* the source dir.
|
|
||||||
// if getting the dir list recursively, all paths are added, except *again* the top source dir beeing queried.
|
|
||||||
void GetDirList(const char *path, StringList &dirs, bool recursive /* = false */)
|
|
||||||
{
|
|
||||||
#if !_WIN32
|
|
||||||
DIR * dirp;
|
|
||||||
struct dirent * dp;
|
|
||||||
dirp = opendir(path);
|
|
||||||
if(dirp)
|
|
||||||
{
|
|
||||||
while((dp = readdir(dirp))) // assignment is intentional
|
|
||||||
{
|
|
||||||
if (dp->d_type == DT_DIR) // only add if it is a directory
|
|
||||||
{
|
|
||||||
if(strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
|
|
||||||
{
|
|
||||||
dirs.push_back(dp->d_name);
|
|
||||||
if (recursive) // needing a better way to do that
|
|
||||||
{
|
|
||||||
std::deque<std::string> newdirs;
|
|
||||||
GetDirList(dp->d_name, newdirs, true);
|
|
||||||
std::string d(dp->d_name);
|
|
||||||
for(std::deque<std::string>::iterator it = newdirs.begin(); it != newdirs.end(); ++it)
|
|
||||||
dirs.push_back(d + *it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(dirp);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
std::string search(path);
|
|
||||||
MakeSlashTerminated(search);
|
|
||||||
search += "*";
|
|
||||||
WIN32_FIND_DATA fil;
|
|
||||||
HANDLE hFil = FindFirstFile(search.c_str(),&fil);
|
|
||||||
if(hFil != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if( fil.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
|
|
||||||
{
|
|
||||||
if (!strcmp(fil.cFileName, ".") || !strcmp(fil.cFileName, ".."))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
std::string d(fil.cFileName);
|
|
||||||
dirs.push_back(d);
|
|
||||||
|
|
||||||
if (recursive) // need a better way to do that
|
|
||||||
{
|
|
||||||
StringList newdirs;
|
|
||||||
GetDirList(d.c_str(), newdirs, true);
|
|
||||||
|
|
||||||
for(std::deque<std::string>::iterator it = newdirs.begin(); it != newdirs.end(); ++it)
|
|
||||||
dirs.push_back(d + *it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while(FindNextFile(hFil, &fil));
|
|
||||||
|
|
||||||
FindClose(hFil);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FileExists(const char *fn)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
FILE *fp = fopen(fn, "rb");
|
|
||||||
if(fp)
|
|
||||||
{
|
|
||||||
fclose(fp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
return access(fn, F_OK) == 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// must return true if creating the directory was successful, or already exists
|
|
||||||
bool CreateDir(const char *dir)
|
|
||||||
{
|
|
||||||
if(IsDirectory(dir)) // do not try to create if it already exists
|
|
||||||
return true;
|
|
||||||
bool result;
|
|
||||||
# if _WIN32
|
|
||||||
result = !!::CreateDirectory(dir, NULL);
|
|
||||||
# else
|
|
||||||
result = !mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
|
||||||
#endif
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CreateDirRec(const char *dir)
|
|
||||||
{
|
|
||||||
if(IsDirectory(dir))
|
|
||||||
return true;
|
|
||||||
bool result = true;
|
|
||||||
StringList li;
|
|
||||||
StrSplit(dir, "/\\", li, false);
|
|
||||||
std::string d;
|
|
||||||
d.reserve(strlen(dir));
|
|
||||||
bool last;
|
|
||||||
for(StringList::iterator it = li.begin(); it != li.end(); it++)
|
|
||||||
{
|
|
||||||
d += *it;
|
|
||||||
last = CreateDir(d.c_str());
|
|
||||||
result = last && result;
|
|
||||||
d += '/';
|
|
||||||
}
|
|
||||||
return result || last;
|
|
||||||
}
|
|
||||||
|
|
||||||
vfspos GetFileSize(const char* fn)
|
|
||||||
{
|
|
||||||
if(!fn || !*fn)
|
|
||||||
return 0;
|
|
||||||
FILE *fp = fopen(fn, "rb");
|
|
||||||
if(!fp)
|
|
||||||
return 0;
|
|
||||||
fseek(fp, 0, SEEK_END);
|
|
||||||
vfspos s = (vfspos)ftell(fp);
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
return s == npos ? 0 : s;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string FixSlashes(const std::string& s)
|
|
||||||
{
|
|
||||||
std::string r;
|
|
||||||
r.reserve(s.length() + 1);
|
|
||||||
char last = 0, cur;
|
|
||||||
for(size_t i = 0; i < s.length(); ++i)
|
|
||||||
{
|
|
||||||
cur = s[i];
|
|
||||||
if(cur == '\\')
|
|
||||||
cur = '/';
|
|
||||||
if(last == '/' && cur == '/')
|
|
||||||
continue;
|
|
||||||
r += cur;
|
|
||||||
last = cur;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string FixPath(const std::string& s)
|
|
||||||
{
|
|
||||||
const char *p = s.c_str();
|
|
||||||
while(p[0] == '.' && p[1] == '/')
|
|
||||||
p += 2;
|
|
||||||
return FixSlashes(p == s.c_str() ? s : p); // avoid hidden re-allocation when pointer was not moved
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsDirectory(const char *s)
|
|
||||||
{
|
|
||||||
#if _WIN32
|
|
||||||
DWORD dwFileAttr = GetFileAttributes(s);
|
|
||||||
if(dwFileAttr == INVALID_FILE_ATTRIBUTES)
|
|
||||||
return false;
|
|
||||||
return !!(dwFileAttr & FILE_ATTRIBUTE_DIRECTORY);
|
|
||||||
#else
|
|
||||||
if ( access( s, 0 ) == 0 )
|
|
||||||
{
|
|
||||||
struct stat status;
|
|
||||||
stat( s, &status );
|
|
||||||
return status.st_mode & S_IFDIR;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void MakeSlashTerminated(std::string& s)
|
|
||||||
{
|
|
||||||
if(s.length() && s[s.length() - 1] != '/')
|
|
||||||
s += '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
// extracts the file name from a given path
|
|
||||||
const char *PathToFileName(const char *str)
|
|
||||||
{
|
|
||||||
const char *p = strrchr(str, '/');
|
|
||||||
return p ? p+1 : str;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string StripFileExtension(const std::string& s)
|
|
||||||
{
|
|
||||||
size_t pos = s.find_last_of('.');
|
|
||||||
size_t pos2 = s.find_last_of('/');
|
|
||||||
if(pos != std::string::npos && (pos2 < pos || pos2 == std::string::npos))
|
|
||||||
return s.substr(0, pos);
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string StripLastPath(const std::string& s)
|
|
||||||
{
|
|
||||||
if(s[s.length() - 1] == '/')
|
|
||||||
return StripLastPath(s.substr(0, s.length() - 1));
|
|
||||||
|
|
||||||
size_t pos = s.find_last_of('/');
|
|
||||||
if(pos == std::string::npos)
|
|
||||||
return ""; // nothing remains
|
|
||||||
|
|
||||||
return s.substr(0, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetFileListRecursive(std::string dir, StringList& files, bool withQueriedDir /* = false */)
|
|
||||||
{
|
|
||||||
std::stack<std::string> stk;
|
|
||||||
|
|
||||||
if(withQueriedDir)
|
|
||||||
{
|
|
||||||
stk.push(dir);
|
|
||||||
while(stk.size())
|
|
||||||
{
|
|
||||||
dir = stk.top();
|
|
||||||
stk.pop();
|
|
||||||
MakeSlashTerminated(dir);
|
|
||||||
|
|
||||||
StringList li;
|
|
||||||
GetFileList(dir.c_str(), li);
|
|
||||||
for(std::deque<std::string>::iterator it = li.begin(); it != li.end(); ++it)
|
|
||||||
files.push_back(dir + *it);
|
|
||||||
|
|
||||||
li.clear();
|
|
||||||
GetDirList(dir.c_str(), li, true);
|
|
||||||
for(std::deque<std::string>::iterator it = li.begin(); it != li.end(); ++it)
|
|
||||||
stk.push(dir + *it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::string topdir = dir;
|
|
||||||
MakeSlashTerminated(topdir);
|
|
||||||
stk.push("");
|
|
||||||
while(stk.size())
|
|
||||||
{
|
|
||||||
dir = stk.top();
|
|
||||||
stk.pop();
|
|
||||||
MakeSlashTerminated(dir);
|
|
||||||
|
|
||||||
StringList li;
|
|
||||||
dir = topdir + dir;
|
|
||||||
GetFileList(dir.c_str(), li);
|
|
||||||
for(std::deque<std::string>::iterator it = li.begin(); it != li.end(); ++it)
|
|
||||||
files.push_back(dir + *it);
|
|
||||||
|
|
||||||
li.clear();
|
|
||||||
GetDirList(dir.c_str(), li, true);
|
|
||||||
for(std::deque<std::string>::iterator it = li.begin(); it != li.end(); ++it)
|
|
||||||
stk.push(dir + *it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// from http://board.byuu.org/viewtopic.php?f=10&t=1089&start=15
|
|
||||||
bool WildcardMatch(const char *str, const char *pattern)
|
|
||||||
{
|
|
||||||
const char *cp = 0, *mp = 0;
|
|
||||||
while(*str && *pattern != '*')
|
|
||||||
{
|
|
||||||
if(*pattern != *str && *pattern != '?')
|
|
||||||
return false;
|
|
||||||
pattern++, str++;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(*str)
|
|
||||||
{
|
|
||||||
if(*pattern == '*')
|
|
||||||
{
|
|
||||||
if(!*++pattern)
|
|
||||||
return 1;
|
|
||||||
mp = pattern;
|
|
||||||
cp = str + 1;
|
|
||||||
}
|
|
||||||
else if(*pattern == *str || *pattern == '?')
|
|
||||||
{
|
|
||||||
++pattern;
|
|
||||||
++str;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pattern = mp;
|
|
||||||
str = cp++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while(*pattern++ == '*');
|
|
||||||
|
|
||||||
return !*pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy strings, mangling newlines to system standard
|
|
||||||
// windows has 13+10
|
|
||||||
// *nix has 10
|
|
||||||
// exotic systems may have 10+13
|
|
||||||
size_t strnNLcpy(char *dst, const char *src, unsigned int n /* = -1 */)
|
|
||||||
{
|
|
||||||
char *olddst = dst;
|
|
||||||
bool had10 = false, had13 = false;
|
|
||||||
|
|
||||||
--n; // reserve 1 for \0 at end
|
|
||||||
|
|
||||||
while(*src && n)
|
|
||||||
{
|
|
||||||
if((had13 && *src == 10) || (had10 && *src == 13))
|
|
||||||
{
|
|
||||||
++src; // last was already mangled
|
|
||||||
had13 = had10 = false; // processed one CRLF pair
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
had10 = *src == 10;
|
|
||||||
had13 = *src == 13;
|
|
||||||
|
|
||||||
if(had10 || had13)
|
|
||||||
{
|
|
||||||
*dst++ = '\n';
|
|
||||||
++src;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*dst++ = *src++;
|
|
||||||
|
|
||||||
--n;
|
|
||||||
}
|
|
||||||
|
|
||||||
*dst++ = 0;
|
|
||||||
|
|
||||||
return dst - olddst;
|
|
||||||
}
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
|
@ -1,59 +0,0 @@
|
||||||
// VFSTools.h - useful functions and misc stuff
|
|
||||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
||||||
|
|
||||||
#ifndef VFS_TOOLS_H
|
|
||||||
#define VFS_TOOLS_H
|
|
||||||
|
|
||||||
#include <deque>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "VFSDefines.h"
|
|
||||||
|
|
||||||
VFS_NAMESPACE_START
|
|
||||||
|
|
||||||
typedef std::deque<std::string> StringList;
|
|
||||||
|
|
||||||
std::string stringToUpper(const std::string& s);
|
|
||||||
std::string stringToLower(const std::string& s);
|
|
||||||
void makeUppercase(std::string& s);
|
|
||||||
void makeLowercase(std::string& s);
|
|
||||||
void GetFileList(const char *, StringList& files);
|
|
||||||
void GetDirList(const char *, StringList& dirs, bool recursive = false);
|
|
||||||
bool FileExists(const char *);
|
|
||||||
bool IsDirectory(const char *);
|
|
||||||
bool CreateDir(const char*);
|
|
||||||
bool CreateDirRec(const char*);
|
|
||||||
vfspos GetFileSize(const char*);
|
|
||||||
std::string FixSlashes(const std::string& s);
|
|
||||||
std::string FixPath(const std::string& s);
|
|
||||||
const char *PathToFileName(const char *str);
|
|
||||||
void MakeSlashTerminated(std::string& s);
|
|
||||||
std::string StripFileExtension(const std::string& s);
|
|
||||||
std::string StripLastPath(const std::string& s);
|
|
||||||
void GetFileListRecursive(std::string dir, StringList& files, bool withQueriedDir = false);
|
|
||||||
bool WildcardMatch(const char *str, const char *pattern);
|
|
||||||
size_t strnNLcpy(char *dst, const char *src, unsigned int n = -1);
|
|
||||||
|
|
||||||
template <class T> void StrSplit(const std::string &src, const std::string &sep, T& container, bool keepEmpty = false)
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
for (std::string::const_iterator i = src.begin(); i != src.end(); i++)
|
|
||||||
{
|
|
||||||
if (sep.find(*i) != std::string::npos)
|
|
||||||
{
|
|
||||||
if (keepEmpty || s.length())
|
|
||||||
container.push_back(s);
|
|
||||||
s = "";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s += *i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (keepEmpty || s.length())
|
|
||||||
container.push_back(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
VFS_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Add table
Add a link
Reference in a new issue