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 "AutoMap.h"
|
||||
#include "GridRender.h"
|
||||
#include <VFSFile.h>
|
||||
|
||||
#include "tinyxml.h"
|
||||
|
||||
|
@ -871,7 +870,7 @@ void Continuity::loadTreasureData()
|
|||
std::string line, gfx;
|
||||
int num, use;
|
||||
float sz;
|
||||
VFSTextStdStreamIn in2("data/treasures.txt");
|
||||
std::ifstream in2("data/treasures.txt");
|
||||
while (std::getline(in2, line))
|
||||
{
|
||||
std::istringstream is(line);
|
||||
|
@ -904,7 +903,7 @@ void Continuity::loadIngredientData()
|
|||
|
||||
/*
|
||||
int num;
|
||||
VFSTextStreamIn in2("data/ingredientdescriptions.txt");
|
||||
std::ifstream in2("data/ingredientdescriptions.txt");
|
||||
while (std::getline(in2, line))
|
||||
{
|
||||
IngredientDescription desc;
|
||||
|
@ -917,7 +916,7 @@ void Continuity::loadIngredientData()
|
|||
clearIngredientData();
|
||||
recipes.clear();
|
||||
|
||||
VFSTextStdStreamIn in("data/ingredients.txt");
|
||||
std::ifstream in("data/ingredients.txt");
|
||||
|
||||
bool recipes = false;
|
||||
while (std::getline(in, line))
|
||||
|
@ -1242,7 +1241,7 @@ void Continuity::loadEatBank()
|
|||
{
|
||||
eats.clear();
|
||||
|
||||
VFSTextStdStreamIn inf("data/eats.txt");
|
||||
std::ifstream inf("data/eats.txt");
|
||||
|
||||
EatData curData;
|
||||
std::string read;
|
||||
|
@ -2182,7 +2181,7 @@ void Continuity::setActivePet(int flag)
|
|||
void Continuity::loadPetData()
|
||||
{
|
||||
petData.clear();
|
||||
VFSTextStdStreamIn in("data/pets.txt");
|
||||
std::ifstream in("data/pets.txt");
|
||||
std::string read;
|
||||
while (std::getline(in, read))
|
||||
{
|
||||
|
@ -3260,7 +3259,7 @@ void Continuity::reset()
|
|||
health = maxHealth;
|
||||
|
||||
speedTypes.clear();
|
||||
VFSTextStreamIn inFile("data/speedtypes.txt");
|
||||
std::ifstream inFile("data/speedtypes.txt");
|
||||
int n, spd;
|
||||
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;
|
||||
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;
|
||||
|
||||
/*
|
||||
|
@ -209,6 +231,9 @@ DSQ::DSQ(std::string fileSystem) : Core(fileSystem, LR_MAX, APPNAME, PARTICLE_AM
|
|||
achievement_box = 0;
|
||||
#endif
|
||||
|
||||
vars = &v;
|
||||
v.load();
|
||||
|
||||
#ifdef AQUARIA_BUILD_CONSOLE
|
||||
console = 0;
|
||||
#endif
|
||||
|
@ -230,6 +255,25 @@ DSQ::DSQ(std::string fileSystem) : Core(fileSystem, LR_MAX, APPNAME, PARTICLE_AM
|
|||
for (int i = 0; i < 16; i++)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -299,7 +343,7 @@ void DSQ::newGame()
|
|||
|
||||
void DSQ::loadElementEffects()
|
||||
{
|
||||
VFSTextStdStreamIn inFile("data/elementeffects.txt");
|
||||
std::ifstream inFile("data/elementeffects.txt");
|
||||
elementEffects.clear();
|
||||
std::string 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()
|
||||
{
|
||||
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;
|
||||
|
||||
weird = 0;
|
||||
|
@ -2171,13 +2166,6 @@ void DSQ::loadMods()
|
|||
{
|
||||
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);
|
||||
selectedMod = 0;
|
||||
}
|
||||
|
@ -3687,7 +3675,7 @@ void DSQ::onPlayVoice()
|
|||
if (user.audio.subtitles)
|
||||
{
|
||||
std::string fn = "scripts/vox/" + sound->lastVoice + ".txt";
|
||||
VFSTextStdStreamIn inf(fn.c_str());
|
||||
std::ifstream inf(fn.c_str());
|
||||
if (inf.is_open())
|
||||
{
|
||||
std::string dia;
|
||||
|
@ -3780,6 +3768,31 @@ std::string DSQ::getDialogueFilename(const std::string &f)
|
|||
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)
|
||||
{
|
||||
std::istringstream is(line);
|
||||
|
|
|
@ -1395,6 +1395,8 @@ public:
|
|||
void takeScreenshot();
|
||||
void takeScreenshotKey();
|
||||
|
||||
void jumpToSection(std::ifstream &inFile, const std::string §ion);
|
||||
|
||||
PathFinding pathFinding;
|
||||
void runGesture(const std::string &line);
|
||||
void generateCollisionMask(RenderObject *r);
|
||||
|
|
|
@ -31,7 +31,7 @@ Emote::Emote()
|
|||
void Emote::load(const std::string &file)
|
||||
{
|
||||
emotes.clear();
|
||||
VFSTextStdStreamIn in(file.c_str());
|
||||
std::ifstream in(file.c_str());
|
||||
std::string 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 "ToolTip.h"
|
||||
#include <VFSFile.h>
|
||||
|
||||
std::vector<std::string> allowedMaps;
|
||||
|
||||
|
@ -2517,7 +2516,7 @@ void Game::loadEntityTypeList()
|
|||
// and group list!
|
||||
{
|
||||
entityTypeList.clear();
|
||||
VFSTextStdStreamIn in("scripts/entities/entities.txt");
|
||||
std::ifstream in("scripts/entities/entities.txt");
|
||||
std::string line;
|
||||
if(!in)
|
||||
{
|
||||
|
@ -2550,7 +2549,7 @@ void Game::loadEntityTypeList()
|
|||
fn = dsq->mod.getPath() + "entitygroups.txt";
|
||||
}
|
||||
|
||||
VFSTextStdStreamIn in2(fn.c_str());
|
||||
std::ifstream in2(fn.c_str());
|
||||
|
||||
int curGroup=0;
|
||||
while (std::getline(in2, line))
|
||||
|
@ -5404,7 +5403,7 @@ void Game::findMaxCameraValues()
|
|||
|
||||
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 line;
|
||||
while (std::getline(in, line))
|
||||
|
@ -7934,9 +7933,9 @@ void Game::onFlipTest()
|
|||
|
||||
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())
|
||||
{
|
||||
|
@ -10946,7 +10945,7 @@ void Game::loadElementTemplates(std::string pack)
|
|||
tileCache.clean();
|
||||
}
|
||||
|
||||
VFSTextStdStreamIn in(fn.c_str());
|
||||
std::ifstream in(fn.c_str());
|
||||
std::string line;
|
||||
while (std::getline(in, line))
|
||||
{
|
||||
|
|
|
@ -24,13 +24,12 @@ GameplayVariables *vars = 0;
|
|||
|
||||
void GameplayVariables::load()
|
||||
{
|
||||
VFSTextStreamIn inFile("data/variables.txt");
|
||||
std::ifstream inFile("data/variables.txt");
|
||||
if(!inFile)
|
||||
{
|
||||
core->messageBox("error", "Variables data not found! Aborting...");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::string s;
|
||||
inFile >> s >> maxSlowSwimSpeed;
|
||||
inFile >> s >> maxSwimSpeed;
|
||||
|
|
|
@ -41,10 +41,10 @@ static void StartAQConfig()
|
|||
{
|
||||
#if defined(BBGE_BUILD_WINDOWS)
|
||||
#if defined(AQUARIA_DEMO) || defined(AQUARIA_FULL)
|
||||
if (!exists("ran", false, true))
|
||||
if (!exists("ran", false))
|
||||
{
|
||||
MakeRan();
|
||||
if(exists("aqconfig.exe", false, true))
|
||||
if(exists("aqconfig.exe", false))
|
||||
{
|
||||
ShellExecute(NULL, "open", "aqconfig.exe", NULL, NULL, SW_SHOWNORMAL);
|
||||
exit(0);
|
||||
|
@ -58,7 +58,7 @@ static void StartAQConfig()
|
|||
static void CheckConfig(void)
|
||||
{
|
||||
#ifdef BBGE_BUILD_WINDOWS
|
||||
bool hasCfg = exists("usersettings.xml", false, true);
|
||||
bool hasCfg = exists("usersettings.xml", false);
|
||||
if(!hasCfg)
|
||||
StartAQConfig();
|
||||
#endif
|
||||
|
|
|
@ -529,7 +529,7 @@ luaFunc(indexWarnGlobal)
|
|||
std::ostringstream os;
|
||||
os << "WARNING: " << ar.short_src << ":" << ar.currentline
|
||||
<< ": script tried to get/call undefined global variable "
|
||||
<< varname;
|
||||
<< lua_tostring(L, -2);
|
||||
errorLog(os.str());
|
||||
}
|
||||
|
||||
|
@ -614,19 +614,7 @@ luaFunc(dofile_caseinsensitive)
|
|||
// This is Lua's dofile(), with some tweaks. --ryan.
|
||||
std::string fname(core->adjustFilenameCase(luaL_checkstring(L, 1)));
|
||||
int n = lua_gettop(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);
|
||||
|
||||
if (luaL_loadfile(L, fname.c_str()) != 0) lua_error(L);
|
||||
lua_call(L, 0, LUA_MULTRET);
|
||||
return lua_gettop(L) - n;
|
||||
}
|
||||
|
@ -8953,20 +8941,11 @@ Script *ScriptInterface::openScript(const std::string &file)
|
|||
lua_getglobal(baseState, "v");
|
||||
|
||||
// Load the file itself. This leaves the Lua chunk on the stack.
|
||||
int result = -1;
|
||||
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);
|
||||
}
|
||||
|
||||
int result = luaL_loadfile(baseState, realFile.c_str());
|
||||
if (result != 0)
|
||||
{
|
||||
const char *msg = 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);
|
||||
debugLog("Error loading script [" + realFile + "]: " + lua_tostring(baseState, -1));
|
||||
lua_pop(baseState, 2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#include "../BBGE/MathFunctions.h"
|
||||
|
||||
#include <VFSFile.h>
|
||||
|
||||
Shot::Shots Shot::shots;
|
||||
Shot::ShotBank Shot::shotBank;
|
||||
|
||||
|
@ -66,7 +64,7 @@ ShotData::ShotData()
|
|||
ignoreShield = false;
|
||||
}
|
||||
|
||||
template <typename T> void readEquals2(T &in)
|
||||
void readEquals2(std::ifstream &in)
|
||||
{
|
||||
std::string temp;
|
||||
in >> temp;
|
||||
|
@ -95,7 +93,7 @@ void ShotData::bankLoad(const std::string &file, const std::string &path)
|
|||
}
|
||||
|
||||
debugLog(usef);
|
||||
VFSTextStreamIn inf(usef.c_str());
|
||||
std::ifstream inf(usef.c_str());
|
||||
std::string token;
|
||||
while (inf >> token)
|
||||
{
|
||||
|
|
|
@ -22,7 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "Game.h"
|
||||
#include "Avatar.h"
|
||||
#include "StatsAndAchievements.h"
|
||||
#include <VFSFile.h>
|
||||
|
||||
#ifndef ARRAYSIZE
|
||||
#define ARRAYSIZE(x) (sizeof (x) / sizeof ((x)[0]))
|
||||
|
@ -172,50 +171,46 @@ void StatsAndAchievements::RunFrame()
|
|||
requestedStats = true;
|
||||
|
||||
const size_t max_achievements = ARRAYSIZE(g_rgAchievements);
|
||||
FILE *io = NULL;
|
||||
|
||||
char *achtxt = "";
|
||||
VFSTextStdStreamIn in("data/achievements.txt");
|
||||
std::string line;
|
||||
|
||||
// HACK: prepare fields in case data are missing
|
||||
for(int i = 0; i < max_achievements; ++i)
|
||||
// Get generic achievement data...
|
||||
io = fopen("data/achievements.txt", "r");
|
||||
char line[1024];
|
||||
for (size_t i = 0; i < max_achievements; i++)
|
||||
{
|
||||
g_rgAchievements[i].iconImage = 0;
|
||||
g_rgAchievements[i].name[sizeof (g_rgAchievements[i].name) - 1] = '\0'; // just in case.
|
||||
g_rgAchievements[i].desc[sizeof (g_rgAchievements[i].desc) - 1] = '\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);
|
||||
}
|
||||
|
||||
// read 2 lines per achievement
|
||||
int x = 0;
|
||||
int ach = 0;
|
||||
while(std::getline(in, line))
|
||||
if (!io || (fgets(line, sizeof (line), io) == NULL))
|
||||
snprintf(line, sizeof (line), "Achievement #%d", (int) i);
|
||||
else
|
||||
{
|
||||
for (char *ptr = const_cast<char*>(line.c_str() + line.length()) - 1; (ptr >= line) && ((*ptr == '\r') || (*ptr == '\n')); ptr--)
|
||||
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);
|
||||
|
||||
switch(x)
|
||||
if (!io || (fgets(line, sizeof (line), io) == NULL))
|
||||
snprintf(line, sizeof (line), "[Description of Achievement #%d is missing!]", (int) i);
|
||||
else
|
||||
{
|
||||
case 0:
|
||||
strncpy(g_rgAchievements[ach].name, line.c_str(), sizeof(g_rgAchievements[ach].name) - 1);
|
||||
++x;
|
||||
break;
|
||||
for (char *ptr = (line + strlen(line)) - 1; (ptr >= line) && ((*ptr == '\r') || (*ptr == '\n')); ptr--)
|
||||
*ptr = '\0';
|
||||
}
|
||||
line[sizeof (g_rgAchievements[i].desc) - 1] = '\0'; // just in case.
|
||||
strcpy(g_rgAchievements[i].desc, line);
|
||||
|
||||
case 1:
|
||||
strncpy(g_rgAchievements[ach].desc, line.c_str(), sizeof(g_rgAchievements[ach].desc) - 1);
|
||||
x = 0;
|
||||
++ach;
|
||||
}
|
||||
// unsupported at the moment.
|
||||
g_rgAchievements[i].iconImage = 0;
|
||||
}
|
||||
|
||||
if (io != NULL)
|
||||
fclose(io);
|
||||
|
||||
// See what this specific player has achieved...
|
||||
// FG: TODO: use VFS here!
|
||||
|
||||
unsigned char *buf = new unsigned char[max_achievements];
|
||||
size_t br = 0;
|
||||
const std::string fname(core->getUserDataFolder() + "/achievements.bin");
|
||||
FILE *io = fopen(fname.c_str(), "rb");
|
||||
io = fopen(fname.c_str(), "rb");
|
||||
if (io == NULL)
|
||||
statsValid = true; // nothing to report.
|
||||
else
|
||||
|
|
|
@ -29,7 +29,7 @@ void StringBank::load(const std::string &file)
|
|||
//debugLog("StringBank::load("+file+")");
|
||||
stringMap.clear();
|
||||
|
||||
VFSTextStdStreamIn in(file.c_str());
|
||||
std::ifstream in(file.c_str());
|
||||
|
||||
std::string line;
|
||||
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;
|
||||
while (std::getline(in, line))
|
||||
{
|
||||
|
|
|
@ -246,7 +246,7 @@ void WorldMap::load(const std::string &file)
|
|||
|
||||
std::string line;
|
||||
|
||||
VFSTextStdStreamIn in(file.c_str());
|
||||
std::ifstream in(file.c_str());
|
||||
|
||||
while (std::getline(in, line))
|
||||
{
|
||||
|
@ -261,7 +261,6 @@ void WorldMap::load(const std::string &file)
|
|||
|
||||
void WorldMap::save(const std::string &file)
|
||||
{
|
||||
// FG: TODO: use VFS here!
|
||||
std::ofstream out(file.c_str());
|
||||
|
||||
for (int i = 0; i < worldMapTiles.size(); i++)
|
||||
|
|
304
BBGE/Base.cpp
304
BBGE/Base.cpp
|
@ -20,7 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
*/
|
||||
#include "Base.h"
|
||||
#include "Core.h"
|
||||
#include "VFSDir.h"
|
||||
|
||||
#ifdef BBGE_BUILD_WINDOWS
|
||||
#include <shellapi.h>
|
||||
|
@ -273,16 +272,17 @@ std::string upperCase(const std::string &s1)
|
|||
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(!skipVFS)
|
||||
/*
|
||||
if (!PHYSFS_exists(f.c_str()))
|
||||
{
|
||||
if(core->vfs.GetFile(core->adjustFilenameCase(f).c_str()))
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
std::ostringstream os;
|
||||
os << "checking to see if [" << f << "] exists";
|
||||
debugLog(os.str());
|
||||
*/
|
||||
|
||||
FILE *file = fopen(core->adjustFilenameCase(f).c_str(), "rb");
|
||||
if (!file)
|
||||
|
@ -295,6 +295,7 @@ bool exists(const std::string &f, bool makeFatal /* = false */, bool skipVFS /*
|
|||
return false;
|
||||
}
|
||||
fclose(file);
|
||||
//}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -447,20 +448,107 @@ void debugLog(const std::string &s)
|
|||
// delete[] when no longer needed.
|
||||
char *readFile(std::string path, unsigned long *size_ret)
|
||||
{
|
||||
ttvfs::VFSFile *vf = core->vfs.GetFile(path.c_str());
|
||||
if(!vf)
|
||||
FILE *f = fopen(path.c_str(), "rb");
|
||||
if (!f)
|
||||
return NULL;
|
||||
vf->getBuf(); // force size calc early
|
||||
// we can never know how the memory was allocated;
|
||||
// because the buffer is expected to be deleted with delete[],
|
||||
// it has to be explicitly copied to memory allocated with new[].
|
||||
unsigned long s = vf->size();
|
||||
char *buf = new char[s + 1];
|
||||
memcpy(buf, vf->getBuf(), s + 1);
|
||||
core->addVFSFileForDrop(vf);
|
||||
|
||||
long fileSize;
|
||||
if (fseek(f, 0, SEEK_END) != 0
|
||||
|| (fileSize = ftell(f)) < 0
|
||||
|| fseek(f, 0, SEEK_SET) != 0)
|
||||
{
|
||||
debugLog(path + ": Failed to get file size");
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 = s;
|
||||
return buf;
|
||||
*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)
|
||||
|
@ -472,29 +560,167 @@ void forEachFile(std::string path, std::string type, void callback(const std::st
|
|||
//HACK: MAC:
|
||||
debugLog("forEachFile - path: " + path + " type: " + type);
|
||||
|
||||
ttvfs::VFSDir *vd = core->vfs.GetDir(path.c_str(), false);
|
||||
if(!vd)
|
||||
#if defined(BBGE_BUILD_UNIX)
|
||||
DIR *dir=0;
|
||||
dir = opendir(path.c_str());
|
||||
if (dir)
|
||||
{
|
||||
debugLog("Path '" + path + "' does not exist");
|
||||
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
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
for(ttvfs::ConstFileIter it = vd->fileIter(); it != vd->fileIterEnd(); ++it)
|
||||
{
|
||||
const ttvfs::VFSFile *f = it->second;
|
||||
const char *e = strrchr(f->name(), '.');
|
||||
if (e)
|
||||
{
|
||||
std::string exs(e);
|
||||
stringToLower(exs);
|
||||
if(exs != type)
|
||||
continue;
|
||||
}
|
||||
else if(type.size())
|
||||
continue;
|
||||
|
||||
callback(path + f->name(), param);
|
||||
//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)
|
||||
{
|
||||
//printf("No files found\n\n");
|
||||
debugLog("No files of type " + type + " found in path " + path);
|
||||
}
|
||||
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;
|
||||
//debugLog("found: " + filename);
|
||||
if (filename.size()>4)
|
||||
{
|
||||
|
||||
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)
|
||||
|
|
17
BBGE/Base.h
17
BBGE/Base.h
|
@ -192,11 +192,13 @@ void stringToLower(std::string &s);
|
|||
void stringToLowerUserData(std::string &s);
|
||||
void glColor3_256(int r, int g, int b);
|
||||
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 debugLog(const std::string &s);
|
||||
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);
|
||||
std::string stripEndlineForUnix(const std::string &in);
|
||||
std::vector<std::string> getFileList(std::string path, std::string type, int param);
|
||||
#ifdef HAVE_STRCASECMP
|
||||
static inline int nocasecmp(const std::string &s1, const std::string &s2)
|
||||
{ return strcasecmp(s1.c_str(), s2.c_str()); }
|
||||
|
@ -223,6 +225,19 @@ Vector colorRGB(int r, int g, int b);
|
|||
#endif
|
||||
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);
|
||||
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)
|
||||
{
|
||||
spacingMap.clear();
|
||||
VFSTextStdStreamIn inFile(file.c_str());
|
||||
std::ifstream inFile(file.c_str());
|
||||
std::string line;
|
||||
while (std::getline(inFile, line))
|
||||
{
|
||||
|
|
|
@ -4193,10 +4193,6 @@ void Core::shutdown()
|
|||
SDL_Quit();
|
||||
debugLog("OK");
|
||||
#endif
|
||||
|
||||
debugLog("Unloading VFS...");
|
||||
vfs.Clear();
|
||||
debugLog("OK");
|
||||
}
|
||||
|
||||
//util funcs
|
||||
|
@ -4532,33 +4528,6 @@ void Core::clearGarbage()
|
|||
|
||||
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()
|
||||
|
@ -4889,69 +4858,3 @@ int Core::tgaSaveSeries(char *filename,
|
|||
// 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 "Shader.h"
|
||||
|
||||
#include "VFSIncludes.h"
|
||||
|
||||
class ParticleEffect;
|
||||
|
||||
class ParticleManager;
|
||||
|
@ -1402,14 +1400,6 @@ protected:
|
|||
int tgaSave(const char *filename, short int width, short int height, unsigned char pixelDepth, unsigned char *imageData);
|
||||
virtual void onUpdate(float dt);
|
||||
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;
|
||||
|
|
|
@ -34,8 +34,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "Base.h"
|
||||
#include "Core.h"
|
||||
|
||||
#include "VFSFile.h"
|
||||
|
||||
#include "FmodOpenALBridge.h"
|
||||
|
||||
#include "al.h"
|
||||
|
@ -55,7 +53,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
class OggDecoder {
|
||||
public:
|
||||
// Create a decoder that streams from a file.
|
||||
OggDecoder(ttvfs::VFSFile *fp);
|
||||
OggDecoder(FILE *fp);
|
||||
|
||||
// Create a decoder that streams from a memory buffer.
|
||||
OggDecoder(const void *data, long data_size);
|
||||
|
@ -100,7 +98,7 @@ private:
|
|||
|
||||
// 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.
|
||||
ttvfs::VFSFile *fp;
|
||||
FILE *fp;
|
||||
const char *data;
|
||||
long data_size;
|
||||
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
|
||||
// to avoid an identifier collision when building with more recent
|
||||
// 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);
|
||||
ttvfs::VFSFile *vf = (ttvfs::VFSFile*)f;
|
||||
switch(whence)
|
||||
{
|
||||
case SEEK_SET: return vf->seek(off);
|
||||
case SEEK_CUR: return vf->seekRel(off);
|
||||
case SEEK_END: return vf->seek(vf->size() - off);
|
||||
#ifdef __MINGW32__
|
||||
return fseeko64(f,off,whence);
|
||||
#elif defined (_WIN32)
|
||||
return _fseeki64(f,off,whence);
|
||||
#else
|
||||
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)
|
||||
{
|
||||
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 int noclose(FILE *f) {return 0;}
|
||||
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 *)) noclose, // NULL doesn't work in libvorbis-1.1.2
|
||||
(long (*)(void *)) BBGE_ov_ftell_wrap
|
||||
(long (*)(void *)) ftell
|
||||
};
|
||||
|
||||
// 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++)
|
||||
{
|
||||
|
@ -535,9 +517,9 @@ static ALenum GVorbisFormat = AL_NONE;
|
|||
class OpenALSound
|
||||
{
|
||||
public:
|
||||
OpenALSound(ttvfs::VFSFile *_fp, const bool _looping);
|
||||
OpenALSound(FILE *_fp, 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; }
|
||||
long getSize() const { return size; }
|
||||
bool isLooping() const { return looping; }
|
||||
|
@ -545,21 +527,20 @@ public:
|
|||
void reference() { refcount++; }
|
||||
|
||||
private:
|
||||
ttvfs::VFSFile * const fp;
|
||||
FILE * const fp;
|
||||
void * const data; // Only used if fp==NULL
|
||||
const long size; // Only used if fp==NULL
|
||||
const bool looping;
|
||||
int refcount;
|
||||
};
|
||||
|
||||
OpenALSound::OpenALSound(ttvfs::VFSFile *_fp, const bool _looping)
|
||||
OpenALSound::OpenALSound(FILE *_fp, const bool _looping)
|
||||
: fp(_fp)
|
||||
, data(NULL)
|
||||
, size(0)
|
||||
, looping(_looping)
|
||||
, refcount(1)
|
||||
{
|
||||
fp->ref++;
|
||||
}
|
||||
|
||||
OpenALSound::OpenALSound(void *_data, long _size, const bool _looping)
|
||||
|
@ -578,11 +559,7 @@ FMOD_RESULT OpenALSound::release()
|
|||
if (refcount <= 0)
|
||||
{
|
||||
if (fp)
|
||||
{
|
||||
fp->close();
|
||||
fp->dropBuf(true); // just in case there is a buffer...
|
||||
fp->ref--;
|
||||
}
|
||||
fclose(fp);
|
||||
else
|
||||
free(data);
|
||||
delete this;
|
||||
|
@ -1067,6 +1044,8 @@ FMOD_RESULT OpenALSystem::createSound(const char *name_or_data, const FMOD_MODE
|
|||
{
|
||||
assert(!exinfo);
|
||||
|
||||
FMOD_RESULT retval = FMOD_ERR_INTERNAL;
|
||||
|
||||
// !!! FIXME: if it's not Ogg, we don't have a decoder. I'm lazy. :/
|
||||
char *fname = (char *) alloca(strlen(name_or_data) + 16);
|
||||
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';
|
||||
strcat(fname, ".ogg");
|
||||
|
||||
ttvfs::VFSFile *vf = core->vfs.GetFile(fname);
|
||||
if(!vf)
|
||||
// just in case...
|
||||
#undef fopen
|
||||
FILE *io = fopen(core->adjustFilenameCase(fname).c_str(), "rb");
|
||||
if (io == NULL)
|
||||
return FMOD_ERR_INTERNAL;
|
||||
|
||||
if (mode & FMOD_CREATESTREAM)
|
||||
{
|
||||
// does it make sense to try to stream from anything else than an actual file on disk?
|
||||
// Files inside containers are always loaded into memory, unless on-the-fly partial decompression is implemented...
|
||||
// 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())
|
||||
vf->open(NULL, "rb");
|
||||
else
|
||||
vf->seek(0);
|
||||
|
||||
*sound = (Sound *) new OpenALSound(vf, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL)));
|
||||
return FMOD_OK;
|
||||
*sound = (Sound *) new OpenALSound(io, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL)));
|
||||
retval = FMOD_OK;
|
||||
}
|
||||
|
||||
// if we are here, create & preload & pre-decode full buffer
|
||||
vf->getBuf(); // force early size detection
|
||||
void *data = malloc(vf->size()); // because release() will use free() ...
|
||||
if (!(data && vf->getBuf()))
|
||||
else
|
||||
{
|
||||
debugLog("Out of memory for " + std::string(fname));
|
||||
vf->close();
|
||||
vf->dropBuf(true);
|
||||
fseek(io, 0, SEEK_END);
|
||||
long size = ftell(io);
|
||||
if (fseek(io, 0, SEEK_SET) != 0)
|
||||
{
|
||||
debugLog("Seek error on " + std::string(fname));
|
||||
fclose(io);
|
||||
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;
|
||||
void *data = malloc(size);
|
||||
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;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
loadProgressCallback = progressCallback;
|
||||
VFSTextStdStreamIn in(list.c_str());
|
||||
std::ifstream in(list.c_str());
|
||||
std::string 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
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#include "Core.h"
|
||||
#include "Shader.h"
|
||||
#ifdef BBGE_BUILD_WINDOWS
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef BBGE_BUILD_SHADERS
|
||||
// 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 )
|
||||
{
|
||||
debugLog("readShaderFile()");
|
||||
#ifdef BBGE_BUILD_WINDOWS
|
||||
FILE *file = fopen( fileName, "r" );
|
||||
|
||||
ttvfs::VFSFile *vf = core->vfs.GetFile(fileName);
|
||||
if(!vf)
|
||||
return NULL;
|
||||
if( file == NULL )
|
||||
{
|
||||
errorLog("Cannot open shader file!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
vf->getBuf();
|
||||
unsigned char *buf = new unsigned char[vf->size() + 1];
|
||||
memcpy(buf, vf->getBuf(), vf->size() + 1);
|
||||
core->addVFSFileForDrop(vf);
|
||||
return buf;
|
||||
struct _stat fileStats;
|
||||
|
||||
if( _stat( fileName, &fileStats ) != 0 )
|
||||
{
|
||||
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()
|
||||
|
|
|
@ -93,7 +93,7 @@ class SimpleIStringStream {
|
|||
|
||||
public:
|
||||
/* Reuse flag passed to StringStream(char *,int). */
|
||||
enum Mode {
|
||||
enum {
|
||||
/* Make a copy of the buffer (default action). */
|
||||
COPY,
|
||||
/* 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 *position; // Our current position in the buffer.
|
||||
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 "Core.h"
|
||||
#include "Base.h"
|
||||
#include "PackRead.h"
|
||||
|
||||
#if defined(BBGE_BUILD_FMODEX)
|
||||
#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)
|
||||
{
|
||||
ttvfs::VFSFile *vf = core->vfs.GetFile(name);
|
||||
if(!vf)
|
||||
return FMOD_ERR_FILE_NOTFOUND;
|
||||
FILE *fp;
|
||||
|
||||
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;
|
||||
*handle = fp;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
|
@ -153,9 +160,7 @@ FMOD_RESULT F_CALLBACK myclose(void *handle, void *userdata)
|
|||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
ttvfs::VFSFile *vf = (ttvfs::VFSFile*)handle;
|
||||
vf->close();
|
||||
core->addVFSFileForDrop(vf);
|
||||
fclose((FILE *)handle);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
@ -169,8 +174,7 @@ FMOD_RESULT F_CALLBACK myread(void *handle, void *buffer, unsigned int sizebytes
|
|||
|
||||
if (bytesread)
|
||||
{
|
||||
ttvfs::VFSFile *vf = (ttvfs::VFSFile*)handle;
|
||||
*bytesread = vf->read((char*)buffer, sizebytes);
|
||||
*bytesread = (int)fread(buffer, 1, sizebytes, (FILE *)handle);
|
||||
|
||||
if (*bytesread < sizebytes)
|
||||
{
|
||||
|
@ -188,8 +192,7 @@ FMOD_RESULT F_CALLBACK myseek(void *handle, unsigned int pos, void *userdata)
|
|||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
ttvfs::VFSFile *vf = (ttvfs::VFSFile*)handle;
|
||||
vf->seek(pos);
|
||||
fseek((FILE *)handle, pos, SEEK_SET);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#include "Core.h"
|
||||
#include "TTFFont.h"
|
||||
|
||||
|
||||
|
@ -47,17 +46,8 @@ void TTFFont::destroy()
|
|||
|
||||
void TTFFont::load(const std::string &str, int sz)
|
||||
{
|
||||
ttvfs::VFSFile *vf = core->vfs.GetFile(str.c_str());
|
||||
if(!vf)
|
||||
{
|
||||
font = new FTGLTextureFont(str.c_str()); // file not in VFS, just pretend nothing happened
|
||||
font = new FTGLTextureFont(str.c_str());
|
||||
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)
|
||||
|
|
|
@ -468,20 +468,6 @@ void Texture::loadPNG(const std::string &file)
|
|||
{
|
||||
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
|
||||
|
||||
|
||||
|
@ -497,11 +483,11 @@ void Texture::loadPNG(const std::string &file)
|
|||
|
||||
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
|
||||
{
|
||||
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;
|
||||
//exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
core->addVFSFileForDrop(vf);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// 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 "Base.h"
|
||||
#include "Core.h"
|
||||
#include "lvpa/ByteBuffer.h"
|
||||
|
||||
#include "SDL_endian.h"
|
||||
|
||||
//glFont header
|
||||
#include "glfont2.h"
|
||||
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
|
||||
|
@ -50,6 +70,7 @@ GLFont::~GLFont ()
|
|||
//*******************************************************************
|
||||
bool GLFont::Create (const char *file_name, int tex, bool loadTexture)
|
||||
{
|
||||
ifstream input;
|
||||
int num_chars, num_tex_bytes;
|
||||
char *tex_bytes;
|
||||
|
||||
|
@ -57,23 +78,18 @@ bool GLFont::Create (const char *file_name, int tex, bool loadTexture)
|
|||
Destroy();
|
||||
|
||||
//Open input file
|
||||
ttvfs::VFSFile *vf = core->vfs.GetFile(file_name);
|
||||
if(!vf)
|
||||
input.open(file_name, ios::in | ios::binary);
|
||||
if (!input)
|
||||
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
|
||||
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;
|
||||
os << "tex_width: " << header.tex_width << " tex_height: " << header.tex_height;
|
||||
|
@ -87,19 +103,18 @@ bool GLFont::Create (const char *file_name, int tex, bool loadTexture)
|
|||
//Read character array
|
||||
for (int i = 0; i < num_chars; i++)
|
||||
{
|
||||
bb >> header.chars[i].dx;
|
||||
bb >> header.chars[i].dy;
|
||||
bb >> header.chars[i].tx1;
|
||||
bb >> header.chars[i].ty1;
|
||||
bb >> header.chars[i].tx2;
|
||||
bb >> header.chars[i].ty2;
|
||||
header.chars[i].dx = read_float(input);
|
||||
header.chars[i].dy = read_float(input);
|
||||
header.chars[i].tx1 = read_float(input);
|
||||
header.chars[i].ty1 = read_float(input);
|
||||
header.chars[i].tx2 = read_float(input);
|
||||
header.chars[i].ty2 = read_float(input);
|
||||
}
|
||||
|
||||
//Read texture pixel data
|
||||
num_tex_bytes = header.tex_width * header.tex_height * 2;
|
||||
tex_bytes = new char[num_tex_bytes];
|
||||
//input.read(tex_bytes, num_tex_bytes);
|
||||
bb.read(tex_bytes, num_tex_bytes);
|
||||
input.read(tex_bytes, num_tex_bytes);
|
||||
|
||||
|
||||
//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
|
||||
delete[] tex_bytes;
|
||||
|
||||
//Close input file
|
||||
input.close();
|
||||
|
||||
//Return successfully
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -22,8 +22,6 @@ must not be misrepresented as being the original software.
|
|||
distribution.
|
||||
*/
|
||||
|
||||
// hacked VFS support into this version.
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef TIXML_USE_STL
|
||||
|
@ -33,8 +31,6 @@ distribution.
|
|||
|
||||
#include "tinyxml.h"
|
||||
|
||||
#include "Core.h"
|
||||
|
||||
FILE* TiXmlFOpen( const char* filename, const char* mode );
|
||||
|
||||
bool TiXmlBase::condenseWhiteSpace = true;
|
||||
|
@ -927,11 +923,12 @@ bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )
|
|||
value = filename;
|
||||
|
||||
// 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 )
|
||||
{
|
||||
bool result = LoadFile( file, encoding );
|
||||
fclose( file );
|
||||
return result;
|
||||
}
|
||||
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 )
|
||||
{
|
||||
|
@ -954,15 +951,10 @@ bool TiXmlDocument::LoadFile( ttvfs::VFSFile* file, TiXmlEncoding encoding )
|
|||
location.Clear();
|
||||
|
||||
// Get the file size, so we can pre-allocate the string. HUGE speed impact.
|
||||
char* buf = (char*)file->getBuf();
|
||||
|
||||
if ( !buf )
|
||||
{
|
||||
SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
|
||||
return false;
|
||||
}
|
||||
|
||||
long length = file->size();
|
||||
long length = 0;
|
||||
fseek( file, 0, SEEK_END );
|
||||
length = ftell( file );
|
||||
fseek( file, 0, SEEK_SET );
|
||||
|
||||
// Strange case, but good to handle up front.
|
||||
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.)
|
||||
// Copies from the 'p' to 'q' pointer, where p can advance faster if
|
||||
// a newline-carriage return is hit.
|
||||
|
@ -1030,16 +1031,13 @@ bool TiXmlDocument::LoadFile( ttvfs::VFSFile* file, TiXmlEncoding encoding )
|
|||
|
||||
Parse( buf, 0, encoding );
|
||||
|
||||
core->addVFSFileForDrop(file);
|
||||
|
||||
delete [] buf;
|
||||
return !Error();
|
||||
}
|
||||
|
||||
|
||||
bool TiXmlDocument::SaveFile( const char * filename ) const
|
||||
{
|
||||
// FG: TODO: use VFS stuff here as well
|
||||
|
||||
// The old c stuff lives on...
|
||||
FILE* fp = TiXmlFOpen( filename, "w" );
|
||||
if ( fp )
|
||||
|
|
|
@ -53,11 +53,6 @@ distribution.
|
|||
#define TIXML_STRING TiXmlString
|
||||
#endif
|
||||
|
||||
namespace ttvfs
|
||||
{
|
||||
class VFSFile;
|
||||
}
|
||||
|
||||
// Deprecated library function hell. Compilers want to use the
|
||||
// new safe versions. This probably doesn't fully address the problem,
|
||||
// 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
|
||||
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.
|
||||
bool SaveFile( FILE* ) const;
|
||||
|
||||
|
|
|
@ -170,8 +170,6 @@ INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR})
|
|||
INCLUDE_DIRECTORIES(${OGGVORBIS_INCLUDE_DIRS})
|
||||
INCLUDE_DIRECTORIES(${SDL_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)"
|
||||
|
@ -380,7 +378,6 @@ SET(BBGE_SRCS
|
|||
${BBGEDIR}/tinyxmlerror.cpp
|
||||
${BBGEDIR}/tinyxmlparser.cpp
|
||||
${BBGEDIR}/glfont2.cpp
|
||||
${BBGEDIR}/VFSFileStream.cpp
|
||||
${COCOA_SRCS}
|
||||
${EXTLIBDIR}/glpng/glpng.c
|
||||
${EXTLIBDIR}/glpng/png/png.c
|
||||
|
@ -560,9 +557,6 @@ SET(LUA_SRCS
|
|||
${LUASRCDIR}/lmathlib.c
|
||||
)
|
||||
|
||||
ADD_SUBDIRECTORY(ExternalLibs/ttvfs)
|
||||
|
||||
SET(OPTIONAL_LIBS ${OPTIONAL_LIBS} ttvfs)
|
||||
|
||||
IF(MACOSX)
|
||||
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 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 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 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
StencilRed = red, StencilGreen = green, StencilBlue = blue;
|
||||
}
|
||||
|
@ -725,332 +717,3 @@ void APIENTRY pngSetStandardOrientation(int 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