diff --git a/JGE/JGE.vcxproj b/JGE/JGE.vcxproj index e54effc1c..3ffc76602 100644 --- a/JGE/JGE.vcxproj +++ b/JGE/JGE.vcxproj @@ -100,7 +100,7 @@ Disabled - Dependencies/SDL/include;Dependencies/include;$(JGEEXTRAS);../Boost;../projects/mtg/include;include;%(AdditionalIncludeDirectories) + src/zipFS;Dependencies/SDL/include;Dependencies/include;$(JGEEXTRAS);../Boost;../projects/mtg/include;include;%(AdditionalIncludeDirectories) SDL_CONFIG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDLL @@ -182,18 +182,7 @@ %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) - - Disabled - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - EnableFastChecks - MaxSpeed - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - MaxSpeed - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - + Disabled %(AdditionalIncludeDirectories) @@ -281,6 +270,7 @@ + Disabled %(AdditionalIncludeDirectories) @@ -300,46 +290,12 @@ - - Disabled - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - EnableFastChecks - MaxSpeed - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - MaxSpeed - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - - - Disabled - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - EnableFastChecks - MaxSpeed - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - MaxSpeed - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - - - Disabled - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - EnableFastChecks - MaxSpeed - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - MaxSpeed - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - - + + + @@ -383,12 +339,15 @@ - - - - + + + + + + + diff --git a/JGE/Makefile b/JGE/Makefile index 03a6cc22d..a55d9d3a4 100644 --- a/JGE/Makefile +++ b/JGE/Makefile @@ -15,7 +15,7 @@ GENERIC_OBJS = src/JApp.o src/JGBKFont.o \ src/JNetwork.o \ src/JParticle.o src/JParticleEmitter.o src/JParticleEffect.o \ src/JParticleSystem.o \ - src/unzip/ioapi.o src/unzip/mztools.o src/unzip/unzip.o \ + src/zipFS/zfsystem.o src/zipFS/ziphdr.o src/zipFS/zstream.o \ src/JSprite.o src/Vector2D.o \ src/tinyxml/tinystr.o src/tinyxml/tinyxml.o \ src/tinyxml/tinyxmlparser.o src/tinyxml/tinyxmlerror.o \ @@ -73,7 +73,7 @@ PSPSDK = $(shell psp-config --pspsdk-path) PSPDIR = $(shell psp-config --psp-prefix) OBJS = $(GENERIC_OBJS) $(PSP_OBJS) TARGET_HGE = libhgetools.a -INCDIR = include/psp include/psp/freetype2 ../Boost +INCDIR = include/psp include/psp/freetype2 ../Boost src/zipFS CXXFLAGS += -O2 -G0 -DPSP LIBDIR = lib/psp endif diff --git a/JGE/Makefile.hge b/JGE/Makefile.hge index a14ef12f9..c7b5f6158 100644 --- a/JGE/Makefile.hge +++ b/JGE/Makefile.hge @@ -6,7 +6,7 @@ OBJS = src/hge/hgecolor.o src/hge/hgeparticle.o \ src/hge/hgedistort.o src/hge/hgefont.o -INCDIR = include/psp include/psp/freetype2 +INCDIR = include/psp include/psp/freetype2 src/zipFS LIBDIR = lib/psp CFLAGS = -O2 -G0 -Wall diff --git a/JGE/include/JFileSystem.h b/JGE/include/JFileSystem.h index 8ce68fdd3..c882c61e0 100644 --- a/JGE/include/JFileSystem.h +++ b/JGE/include/JFileSystem.h @@ -1,28 +1,11 @@ -//------------------------------------------------------------------------------------- -// -// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows. -// -// Licensed under the BSD license, see LICENSE in JGE root for details. -// -// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) -// -//------------------------------------------------------------------------------------- +#ifndef _J_FILE_SYSTEM_H_ +#define _J_FILE_SYSTEM_H_ -#ifndef _FILE_SYSTEM_H_ -#define _FILE_SYSTEM_H_ - -#define JGE_GET_RES(filename) JFileSystem::GetInstance()->GetResourceFile(filename) -#define JGE_GET_RESPATH() JFileSystem::GetInstance()->GetResourceRoot() - -#include -#include -#include +#include "zfsystem.h" #include - -#if defined (PSP) - #include - #include -#endif +using zip_file_system::filesystem; +using zip_file_system::izfstream; +using namespace std; #include "unzip/unzip.h" @@ -40,22 +23,30 @@ class JZipCache { public: JZipCache(); ~JZipCache(); - map dir; + map dir; }; -class JFileSystem -{ +class JFileSystem { +private: + string mSystemFSPath, mUserFSPath; + filesystem * mSystemFS, * mUserFS; + static JFileSystem* mInstance; + izfstream mFile; + + mapmZipCache; + string mZipFileName; + int mFileSize; + char *mPassword; + bool mZipAvailable; + void preloadZip(const string& filename); + izfstream mZipFile; + filesystem::file_info * mCurrentFileInZip; + + std::vector& scanRealFolder(const std::string& folderName, std::vector& results); + public: - ////////////////////////////////////////////////////////////////////////// - /// Get the singleton instance - /// - ////////////////////////////////////////////////////////////////////////// - static JFileSystem* GetInstance(); - - static void Destroy(); - ////////////////////////////////////////////////////////////////////////// /// Attach ZIP archive to the file system. @@ -74,12 +65,26 @@ public: ////////////////////////////////////////////////////////////////////////// void DetachZipFile(); + // Manually Clear the zip cache + void clearZipCache(); + + ////////////////////////////////////////////////////////////////////////// + /// Get the singleton instance + /// + ////////////////////////////////////////////////////////////////////////// + static JFileSystem* GetInstance(); + + static void Destroy(); + ////////////////////////////////////////////////////////////////////////// /// Open file for reading. /// ////////////////////////////////////////////////////////////////////////// bool OpenFile(const string &filename); + //Fills the vector results with a list of children of the given folder + std::vector& scanfolder(const std::string& folderName, std::vector& results); + std::vector scanfolder(const std::string& folderName); ////////////////////////////////////////////////////////////////////////// /// Read data from file. /// @@ -96,6 +101,7 @@ public: /// ////////////////////////////////////////////////////////////////////////// int GetFileSize(); + int GetFileSize(izfstream & file); ////////////////////////////////////////////////////////////////////////// /// Close file. @@ -109,37 +115,47 @@ public: /// @resourceRoot - New root. /// ////////////////////////////////////////////////////////////////////////// - void SetResourceRoot(const string& resourceRoot); - string GetResourceRoot(); + void SetSystemRoot(const string& resourceRoot); + string GetSystemRoot() { return mSystemFSPath; }; - // Returns a string prefixed with the resource path - string GetResourceFile(string filename); + void SetUSerRoot(const string& resourceRoot); + string GetUserRoot() { return mUserFSPath; }; + + bool openForRead(izfstream & File, const string & FilePath); + bool readIntoString(const string & FilePath, string & target); + bool openForWrite(ofstream & File, const string & FilePath, ios_base::openmode mode = ios_base::out ); + bool Rename(string from, string to); + + //Returns true if strFilename exists somewhere in the fileSystem + bool FileExists(const string& strFilename); + + //Returns true if strdirname exists somewhere in the fileSystem, and is a directory + bool DirExists(const string& strDirname); + + static void init( const string & userPath, const string & systemPath = ""); + + + + // AVOID Using This function!!! + /* + This function is deprecated, but some code is still using it + It used to give a pathname to a file in the file system. + Now with the support of zip resources, a pathname does not make sense anymore + However some of our code still relies on "physical" files not being in zip. + So this call is now super heavy: it checks where the file is, and if it's in a zip, it extracts + it to the user Filesystem, assuming that whoever called this needs to access the file through its pathname later on + */ + string GetResourceFile(string filename); - // Manually Clear the zip cache - void clearZipCache(); - protected: - JFileSystem(); + JFileSystem(const string & userPath, const string & systemPath = ""); ~JFileSystem(); -private: - static JFileSystem* mInstance; - - mapmZipCache; - string mResourceRoot; - string mZipFileName; - char *mPassword; - bool mZipAvailable; - void preloadZip(const string& filename); - -#if defined (PSP) - SceUID mFile; -#else - FILE *mFile; -#endif - unzFile mZipFile; - int mFileSize; }; -#endif + + + + +#endif \ No newline at end of file diff --git a/JGE/include/JLogger.h b/JGE/include/JLogger.h index cb07cffc8..e4d88495e 100644 --- a/JGE/include/JLogger.h +++ b/JGE/include/JLogger.h @@ -3,7 +3,9 @@ //logging facility //#define DOLOG -#ifdef DOLOG +#include +//The PSP one is to log stuff in JLogger's lastLog, it does not do full log in a text file unless DOLOG is defined +#if defined(DOLOG) || defined (PSP) #define LOG(x) JLogger::Log(x); #else #define LOG(x) {}; @@ -22,6 +24,8 @@ class JLogger{ ~JLogger(); const char* mText; + + static std::string lastLog; }; #endif diff --git a/JGE/src/JFileSystem.cpp b/JGE/src/JFileSystem.cpp index c5b021602..d1e934220 100644 --- a/JGE/src/JFileSystem.cpp +++ b/JGE/src/JFileSystem.cpp @@ -1,12 +1,21 @@ -//------------------------------------------------------------------------------------- -// -// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows. -// -// Licensed under the BSD license, see LICENSE in JGE root for details. -// -// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) -// -//------------------------------------------------------------------------------------- +/* JFileSystem centralizes all access to resources in JGE. +It allows to have files for the game split in two subfolders, a "system" subfolder (read only) and a "user" subfolder (read/write) +Additionally, these two subfolders can have some of their resources in zip file (see zfsystem.h). +Zip files can contain duplicates of the same file, the one that will eventually be used is the one is the latest zip file (by alphabetical order) + +Read access priority: +User folder, real file +User folder, zip file +System folder, real file +System folder, zip file + +Write access: +User folder, real file + +User folder is the only one that is really needed to guarantee both read and write access, the system folder is not necessary but provides a nice way to distinguish +The content that users should not be touching. +*/ + #ifdef WIN32 #pragma warning(disable : 4786) @@ -15,26 +24,15 @@ #include "../include/JGE.h" #include "../include/JFileSystem.h" #include "../include/JLogger.h" -#include "tinyxml/tinyxml.h" -#include "unzip/unzip.h" - - -#include -#include -#include -#include +#include +JFileSystem* JFileSystem::mInstance = NULL; JZipCache::JZipCache() {} JZipCache::~JZipCache() { - map::iterator it; - for (it = dir.begin(); it != dir.end(); ++it) - { - delete(it->second); - } dir.clear(); } @@ -46,38 +44,115 @@ void JFileSystem::preloadZip(const string& filename) JZipCache * cache = new JZipCache(); mZipCache[filename] = cache; - if (!mZipAvailable || !mZipFile) + if (!mZipAvailable || !mZipFile) { + AttachZipFile(filename); + if (!mZipAvailable || !mZipFile) return; + } + + if (! (mUserFS->PreloadZip(filename.c_str(), cache->dir) || (mSystemFS && mSystemFS->PreloadZip(filename.c_str(), cache->dir)))) { - AttachZipFile(filename); - if (!mZipAvailable || !mZipFile) return; - } - int err = unzGoToFirstFile (mZipFile); - while (err == UNZ_OK) - { - unz_file_pos* filePos = new unz_file_pos(); - char filenameInzip[4096]; - if (unzGetCurrentFileInfo(mZipFile, NULL, filenameInzip, sizeof(filenameInzip), NULL, 0, NULL, 0) == UNZ_OK) - { - unzGetFilePos(mZipFile, filePos); - string name = filenameInzip; - cache->dir[name] = filePos; - } - err = unzGoToNextFile(mZipFile); + DetachZipFile(); } } -JFileSystem* JFileSystem::mInstance = NULL; + +void JFileSystem::init(const string & userPath, const string & systemPath) +{ + Destroy(); + mInstance = new JFileSystem(userPath, systemPath); +} JFileSystem* JFileSystem::GetInstance() { - if (mInstance == NULL) + if (!mInstance) { - mInstance = new JFileSystem(); +#ifdef RESPATH + init( RESPATH"/"); +#else + init("Res/"); } - +#endif return mInstance; } +// Tries to set the system and user paths. +// On some OSes, the parameters get overriden by hardcoded values +JFileSystem::JFileSystem(const string & _userPath, const string & _systemPath) + +{ + string systemPath = _systemPath; + string userPath = _userPath; + +#ifdef IOS + //copy the RES folder over to the Documents folder + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error; + NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, + NSUserDomainMask, YES); + NSString *documentsDirectory = [[paths objectAtIndex:0] stringByAppendingString: @"/Res"]; + + NSString *resourceDBFolderPath = [[[NSBundle mainBundle] resourcePath] + stringByAppendingPathComponent:@"Res"]; + // copy the Res folder over to the Documents directory if it doesn't exist. + if ( ![fileManager fileExistsAtPath: documentsDirectory]) + [fileManager copyItemAtPath:resourceDBFolderPath toPath:documentsDirectory error:&error]; + + userPath = [documentsDirectory cStringUsingEncoding:1]; + userPath += "/"; + systemPath = ""; +#elif defined (ANDROID) + userPath = "/sdcard/Wagic/Res/"; + systemPath = ""; +#else + //Find the Res.txt file and matching Res folders for backwards compatibility + ifstream mfile("Res.txt"); + string resPath; + if (mfile) + { + bool found = false; + while (!found && std::getline(mfile, resPath)) + { + if (resPath[resPath.size() - 1] == '\r') + resPath.erase(resPath.size() - 1); //Handle DOS files + string testfile = resPath; + testfile.append("graphics/simon.dat"); + ifstream file(testfile.c_str()); + if (file) + { + userPath = resPath; + systemPath = ""; + found = true; + file.close(); + } + } + mfile.close(); + } +#endif + + // Make sure the base paths finish with a '/' or a '\' + if (! userPath.empty()) { + string::iterator c = --(userPath.end()); + if ((*c != '/') && (*c != '\\')) + userPath += '/'; + } + + if (! systemPath.empty()) { + string::iterator c = --(systemPath.end()); + if ((*c != '/') && (*c != '\\')) + systemPath += '/'; + } + + mUserFSPath = userPath; + mSystemFSPath = systemPath; + + mUserFS = new filesystem(userPath.c_str()); + mSystemFS = (mSystemFSPath.size() && (mSystemFSPath.compare(mUserFSPath) != 0)) ? new filesystem(systemPath.c_str()) : NULL; + + mZipAvailable = false; + mPassword = NULL; + mFileSize = 0; + mCurrentFileInZip = NULL; +}; void JFileSystem::Destroy() { @@ -88,32 +163,29 @@ void JFileSystem::Destroy() } } - -JFileSystem::JFileSystem() -{ - mZipAvailable = false; -#if defined (PSP) - mFile = -1; -#else - mFile = NULL; -#endif - mPassword = NULL; - mZipFile = NULL; - mFileSize = 0; - -#ifdef RESPATH - SetResourceRoot(RESPATH"/"); -#else - SetResourceRoot("Res/"); // default root folder -#endif +bool JFileSystem::DirExists(const string& strDirname) +{ + return mUserFS->DirExists(strDirname) || (mSystemFS && mSystemFS->DirExists(strDirname)); } +bool JFileSystem::FileExists(const string& strFilename) +{ + izfstream temp; + bool result = openForRead(temp, strFilename); + if (temp) + temp.close(); + + return result; +} JFileSystem::~JFileSystem() { clearZipCache(); + SAFE_DELETE(mUserFS); + SAFE_DELETE(mSystemFS); } + void JFileSystem::clearZipCache() { DetachZipFile(); @@ -138,166 +210,313 @@ bool JFileSystem::AttachZipFile(const string &zipfile, char *password /* = NULL mZipFileName = zipfile; mPassword = password; - mZipFile = unzOpen(mZipFileName.c_str()); + openForRead(mZipFile, mZipFileName); - if (mZipFile != NULL) + if (!mZipFile) + return false; + + + //A hack for a zip inside a zip: instead we open the zip containing it + if (mZipFile.Zipped()) { - mZipAvailable = true; - return true; + mZipFile.close(); + assert(filesystem::getCurrentFS()); + mZipFile.open(filesystem::getCurrentZipName().c_str(), filesystem::getCurrentFS()); + assert(mZipFile); } + mZipAvailable = true; + return true; - return false; } void JFileSystem::DetachZipFile() { - if (mZipAvailable && mZipFile != NULL) + if (mZipFile) { - int error = unzCloseCurrentFile(mZipFile); - if (error < 0 ) - JLOG("error calling unzCloseCurrentFile"); - - error = unzClose(mZipFile); - if (error < 0) - JLOG("Error calling unzClose"); + mZipFile.close(); } - - mZipFile = NULL; + mCurrentFileInZip = NULL; mZipAvailable = false; } +bool JFileSystem::openForRead(izfstream & File, const string & FilePath) { + + File.open(FilePath.c_str(), mUserFS); + if (File) + return true; + + if(!mSystemFS) + return false; + + File.open(FilePath.c_str(), mSystemFS); + if (File) + return true; + + return false; +} + +bool JFileSystem::readIntoString(const string & FilePath, string & target) +{ + izfstream file; + if (!openForRead(file, FilePath)) + return false; + + int fileSize = GetFileSize(file); + + target.resize((std::string::size_type) fileSize); + + if (fileSize) + file.read(&target[0], fileSize); + + file.close(); + return true; +} + +bool JFileSystem::openForWrite(ofstream & File, const string & FilePath, ios_base::openmode mode) +{ + string filename = mUserFSPath; + filename.append(FilePath); + File.open(filename.c_str(), mode); + + if (File) + { + return true; + } + return false; +} bool JFileSystem::OpenFile(const string &filename) { - string path = mResourceRoot + filename; + mCurrentFileInZip = NULL; - if (mZipAvailable && mZipFile != NULL) + if (!mZipAvailable || !mZipFile) + return openForRead(mFile, filename); + + preloadZip(mZipFileName); + map::iterator it = mZipCache.find(mZipFileName); + if (it == mZipCache.end()) { - preloadZip(mZipFileName); - map::iterator it = mZipCache.find(mZipFileName); - if (it == mZipCache.end()) - { - DetachZipFile(); - return OpenFile(filename); - } - JZipCache * zc = it->second; - map::iterator it2 = zc->dir.find(filename); - if (it2 == zc->dir.end()) - { - DetachZipFile(); - return OpenFile(filename); - } - unzGoToFilePos(mZipFile,it2->second); - char filenameInzip[256]; - unz_file_info fileInfo; - - if (unzGetCurrentFileInfo(mZipFile, &fileInfo, filenameInzip, sizeof(filenameInzip), NULL, 0, NULL, 0) == UNZ_OK) - mFileSize = fileInfo.uncompressed_size; - else - mFileSize = 0; - - return (unzOpenCurrentFilePassword(mZipFile, mPassword) == UNZ_OK); + //DetachZipFile(); + //return OpenFile(filename); + return openForRead(mFile, filename); } - else + JZipCache * zc = it->second; + map::iterator it2 = zc->dir.find(filename); + if (it2 == zc->dir.end()) { -#if defined (PSP) - mFile = sceIoOpen(path.c_str(), PSP_O_RDONLY, 0777); - if (mFile > 0) - { - mFileSize = sceIoLseek(mFile, 0, PSP_SEEK_END); - sceIoLseek(mFile, 0, PSP_SEEK_SET); - return true; - } -#else - mFile = fopen(path.c_str(), "rb"); - if (mFile != NULL) - { - fseek(mFile, 0, SEEK_END); - mFileSize = ftell(mFile); - fseek(mFile, 0, SEEK_SET); - return true; - } -#endif + /*DetachZipFile(); + return OpenFile(filename); */ + return openForRead(mFile, filename); } - return false; + mCurrentFileInZip = &(it2->second); + mFileSize = it2->second.m_Size; + return true; + } void JFileSystem::CloseFile() { - if (mZipAvailable && mZipFile != NULL) + if (mZipAvailable && mZipFile) { - unzCloseCurrentFile(mZipFile); - return; + mCurrentFileInZip = NULL; } -#if defined (PSP) - if (mFile > 0) - sceIoClose(mFile); -#else - if (mFile != NULL) - fclose(mFile); -#endif + if (mFile) + mFile.close(); } - +//returns 0 if less than "size" bits were read int JFileSystem::ReadFile(void *buffer, int size) { - if (mZipAvailable && mZipFile != NULL) - { - return unzReadCurrentFile(mZipFile, buffer, size); - } - else - { -#if defined (PSP) - return sceIoRead(mFile, buffer, size); -#else - return fread(buffer, 1, size, mFile); -#endif - } + if (mCurrentFileInZip) + { + assert(mZipFile); + if((size_t)size > mCurrentFileInZip->m_CompSize) //only support "store" method for zip inside zips + return 0; + std::streamoff offset = filesystem::SkipLFHdr(mZipFile, mCurrentFileInZip->m_Offset); + if (!mZipFile.seekg(offset)) + return 0; + mZipFile.read((char *) buffer, size); + //TODO what if can't read + return size; + } + + if (!mFile) + return 0; + + assert(!mFile.Zipped() || (size_t)size <= mFile.getUncompSize()); + mFile.read((char *)buffer, size); + if (mFile.eof()) + return 0; + return size; } +std::vector& JFileSystem::scanRealFolder(const std::string& folderName, std::vector& results) +{ + DIR *dip = opendir(folderName.c_str()); + if (!dip) + return results; + + while (struct dirent * dit = readdir(dip)) + { + results.push_back(dit->d_name); + } + + closedir(dip); + + return results; +} + +std::vector& JFileSystem::scanfolder(const std::string& _folderName, std::vector& results) +{ + if (!_folderName.size()) + return results; + + map seen; + + + string folderName = _folderName; + if (folderName[folderName.length() - 1] != '/') + folderName.append("/"); + + //user filesystem + { + //Scan the zip filesystem + std::vector userZips; + mUserFS->scanfolder(folderName, userZips); + + for (size_t i = 0; i < userZips.size(); ++i) + seen[userZips[i]] = true; + + //scan the real files + //TODO check for "/" + std::vector userReal; + string realFolderName = mUserFSPath; + realFolderName.append(folderName); + scanRealFolder(realFolderName, userReal); + + for (size_t i = 0; i < userReal.size(); ++i) + seen[userReal[i]] = true; + } + + if (mSystemFS) + { + //Scan the zip filesystem + std::vector systemZips; + mSystemFS->scanfolder(folderName, systemZips); + + for (size_t i = 0; i < systemZips.size(); ++i) + seen[systemZips[i]] = true; + + //scan the real files + //TODO check for "/" + std::vector systemReal; + string realFolderName = mSystemFSPath; + realFolderName.append(folderName); + scanRealFolder(realFolderName, systemReal); + + + for (size_t i = 0; i < systemReal.size(); ++i) + seen[systemReal[i]] = true; + } + + + for(map::iterator it = seen.begin(); it != seen.end(); ++it) + { + results.push_back(it->first); + } + + return results; +} + +std::vector JFileSystem::scanfolder(const std::string& folderName) +{ + std::vector result; + return scanfolder(folderName, result); +} int JFileSystem::GetFileSize() { - return mFileSize; + if (mCurrentFileInZip) + return mFileSize; + + return GetFileSize(mFile); } - -void JFileSystem::SetResourceRoot(const string& resourceRoot) +bool JFileSystem::Rename(string _from, string _to) { -#ifdef IOS - //copy the RES folder over to the Documents folder - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSError *error; - NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, - NSUserDomainMask, YES); - NSString *documentsDirectory = [[paths objectAtIndex:0] stringByAppendingString: @"/Res"]; - - NSString *resourceDBFolderPath = [[[NSBundle mainBundle] resourcePath] - stringByAppendingPathComponent:@"Res"]; - // copy the Res folder over to the Documents directory if it doesn't exist. - if ( ![fileManager fileExistsAtPath: documentsDirectory]) - [fileManager copyItemAtPath:resourceDBFolderPath toPath:documentsDirectory error:&error]; - - mResourceRoot = [documentsDirectory cStringUsingEncoding:1]; - mResourceRoot += "/"; -#elif defined (ANDROID) - mResourceRoot = "/sdcard/Wagic/Res/"; -#else - mResourceRoot = resourceRoot; -#endif + string from = mUserFSPath + _from; + string to = mUserFSPath + _to; + std::remove(to.c_str()); + return rename(from.c_str(), to.c_str()) ? true: false; } -string JFileSystem::GetResourceRoot() +int JFileSystem::GetFileSize(izfstream & file) { - return mResourceRoot; + if (!file) + return 0; + + if (file.Zipped()) + { + //There's a bug in zipped version that prevents from sending a correct filesize with the "standard" seek method + //The hack below only works for the "stored" version I think... + return file.getUncompSize(); + } + + file.seekg (0, ios::end); + int length = (int) file.tellg(); + file.seekg (0, ios::beg); + return length; + } +// AVOID Using This function!!! +/* +This function is deprecated, but some code is still using it +It used to give a pathname to a file in the file system. +Now with the support of zip resources, a pathname does not make sense anymore +However some of our code still relies on "physical" files not being in zip. +So this call is now super heavy: it checks where the file is, and if it's in a zip, it extracts +it to the user Filesystem, assuming that whoever called this needs to access the file through its pathname later on. + +As a result, this function isvery inefficient and shouldn't be used in the general case. +*/ string JFileSystem::GetResourceFile(string filename) { - string result = mResourceRoot; - return result.append(filename); + izfstream temp; + bool result = openForRead(temp, filename); + + if (!temp || !result) + return ""; + + if (!temp.Zipped()) + { + string result = temp.FullFilePath(); + temp.close(); + return result; + } + + // File is inside a zip archive, + //we copy it to the user FS + string destFile = mUserFSPath + filename; + ofstream dest; + if (openForWrite(dest, filename, ios_base::binary)) + { + // allocate memory: + size_t length = temp.getUncompSize(); + char * buffer = new char [length]; + + // read data as a block: + temp.read(buffer, length); + temp.close(); + + dest.write (buffer,length); + delete[] buffer; + dest.close(); + return destFile; + } + return ""; } diff --git a/JGE/src/JGfx.cpp b/JGE/src/JGfx.cpp index d470dd520..addb503f8 100644 --- a/JGE/src/JGfx.cpp +++ b/JGE/src/JGfx.cpp @@ -1024,8 +1024,6 @@ void JRenderer::LoadJPG(TextureInfo &textureInfo, const char *filename, int mode { JLOG("JRenderer::LoadJPG"); textureInfo.mBits = NULL; - char filenamenew[4096]; - sprintf(filenamenew, JGE_GET_RES(filename).c_str()); bool useVideoRAM = (mode == TEX_TYPE_USE_VRAM); diff --git a/JGE/src/JLogger.cpp b/JGE/src/JLogger.cpp index dc2a5f9a2..46c6a904c 100644 --- a/JGE/src/JLogger.cpp +++ b/JGE/src/JLogger.cpp @@ -3,7 +3,10 @@ #include +string JLogger::lastLog = ""; + void JLogger::Log(const char * text){ +#ifdef DOLOG std::ofstream file(LOG_FILE, std::ios_base::app); if (file){ file << text; @@ -12,6 +15,8 @@ void JLogger::Log(const char * text){ } DebugTrace(text); +#endif + lastLog = text; } JLogger::JLogger(const char* text) : mText(text) diff --git a/JGE/src/JSfx.cpp b/JGE/src/JSfx.cpp index 2bab04ce8..37d40693e 100644 --- a/JGE/src/JSfx.cpp +++ b/JGE/src/JSfx.cpp @@ -110,7 +110,7 @@ void JSoundSystem::DestroySoundSystem() JMusic *JSoundSystem::LoadMusic(const char *fileName) { - string s = JGE_GET_RES(fileName); + string s = JFileSystem::GetInstance()->GetResourceFile(fileName); JMusic *music = new JMusic(); if (music) diff --git a/JGE/src/hge/hgeparticle.cpp b/JGE/src/hge/hgeparticle.cpp index 453da387c..403b91fd7 100644 --- a/JGE/src/hge/hgeparticle.cpp +++ b/JGE/src/hge/hgeparticle.cpp @@ -70,7 +70,7 @@ hgeParticleSystem::hgeParticleSystem(const char *filename, JQuad *sprite) // we're actually trying to read more than the file size now, but it's no problem. // Note that this fix is only to avoid the largest problems, filling a structure // by directly reading a file, is really a bad idea ... - fileSys->ReadFile(&(info.nEmission), sizeof(hgeParticleSystemInfo)); + fileSys->ReadFile(&(info.nEmission), sizeof(hgeParticleSystemInfo) - 4); fileSys->CloseFile(); info.sprite=sprite; diff --git a/JGE/src/main.cpp b/JGE/src/main.cpp index abebd9c5a..4061789ff 100644 --- a/JGE/src/main.cpp +++ b/JGE/src/main.cpp @@ -149,6 +149,7 @@ void ExceptionHandler(PspDebugRegBlock * regs) pspDebugScreenPrintf("Your PSP has just crashed!\n"); pspDebugScreenPrintf("Exception details:\n\n"); + pspDebugScreenPrintf("Last Log Message: \n%s\n\n", JLogger::lastLog.c_str()); pspDebugScreenPrintf("Exception - %s\n", codeTxt[(regs->cause >> 2) & 31]); pspDebugScreenPrintf("EPC - %08X / %s.text + %08X\n", (int)regs->epc, module_info.modname, (unsigned int)(regs->epc-(int)&_ftext)); pspDebugScreenPrintf("Cause - %08X\n", (int)regs->cause); diff --git a/JGE/src/zipFS/Makefile b/JGE/src/zipFS/Makefile new file mode 100644 index 000000000..4be58344d --- /dev/null +++ b/JGE/src/zipFS/Makefile @@ -0,0 +1,25 @@ +MAIN=zfs + +CC=g++ + +CFLAGS= -O2 -Wall -DNDEBUG -DUNIX + +INCLUDES= + +LFLAGS= -lz + +SRCS = \ + zfs.cpp \ + zfsystem.cpp \ + ziphdr.cpp \ + zstream.cpp \ + +OBJS = $(SRCS:.cpp=.o) + +$(MAIN): $(OBJS) + $(CC) -o $(MAIN) $(LFLAGS) $(OBJS) +.cpp.o: + $(CC) $(CFLAGS) $(INCLUDES) -c $< + +clean: + rm -f *.o $(MAIN) diff --git a/JGE/src/zipFS/base_data/!Pak0.cpk b/JGE/src/zipFS/base_data/!Pak0.cpk new file mode 100644 index 000000000..3a6843613 Binary files /dev/null and b/JGE/src/zipFS/base_data/!Pak0.cpk differ diff --git a/JGE/src/zipFS/base_data/!Pak1.cpk b/JGE/src/zipFS/base_data/!Pak1.cpk new file mode 100644 index 000000000..ccc1ca0a1 Binary files /dev/null and b/JGE/src/zipFS/base_data/!Pak1.cpk differ diff --git a/JGE/src/zipFS/fileio.h b/JGE/src/zipFS/fileio.h new file mode 100644 index 000000000..0a7ae967e --- /dev/null +++ b/JGE/src/zipFS/fileio.h @@ -0,0 +1,252 @@ +// bfileio.h: interface for the binary file i/o. +// +////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2004 Tanguy Fautré. +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// +// Tanguy Fautré +// softdev@telenet.be +// +////////////////////////////////////////////////////////////////////// +// +// File I/O Facilities. +// ******************** +// +// Current version: 1.00 BETA 4 (16/07/2004) +// +// Comment: readvar() and writevar() read a little endian ordered +// value on a file and put it in a variable. +// search_iterator only accepts "/*.". +// Uses ANSI C "assert()". Define NDEBUG to turn it off. +// (note: Visual C++ define NDEBUG in Release mode) +// +// History: - 1.00 BETA 4 (16/07/2004) - Fixed small bug in UNIX search_iterator +// - 1.00 BETA 3 (27/06/2004) - Added UNIX compatibility +// - 1.00 BETA 2 (21/02/2003) - Now endianess independent +// - 1.00 BETA 1 (06/09/2002) - First public release +// +////////////////////////////////////////////////////////////////////// + +#pragma once + + + +#if defined WIN32 +#include // Windows I/O facilities (Directories) +#else +#include +#include +#endif + +#include + +namespace io_facilities { + + + + +// Global function for reading binary variables +template std::istream & readvar(std::istream & File, T & Var, const std::streamsize NbBytes); +template std::ostream & writevar(std::ostream & File, const T & Var, const std::streamsize NbBytes); + + + +// Class for searching files and directories +// (!!! not compliant with C++ std::iterator and is thus meant for specific use !!!) +class search_iterator +{ +public: + search_iterator(); + search_iterator(const char * FileSpec); + ~search_iterator(); + + operator bool () const; + search_iterator & operator ++ (); + search_iterator & begin(const char * FileSpec); + search_iterator & next(); + bool end() const; + std::string Name() const; + +protected: + bool m_Valid; + +#if defined WIN32 + intptr_t m_hFiles; + _finddata_t m_FindData; +#else + DIR * m_Directory; + std::string m_Extension; + struct dirent * m_DirectoryEntry; +#endif +}; + + + + +////////////////////////////////////////////////////////////////////// +// io_facilities:: Inline Functions +////////////////////////////////////////////////////////////////////// + +template +inline std::istream & readvar(std::istream & File, T & Var, const std::streamsize NbBytes) +{ + // Debug test to ensure type size is big enough + assert(sizeof(T) >= size_t(NbBytes)); + + // Var = 0 ensure type size won't matter + T TmpVar = Var = 0; + + for (std::streamsize i = 0; i < NbBytes; ++i) { + File.read(reinterpret_cast(&TmpVar), 1); + Var |= TmpVar << (i * CHAR_BIT); + } + + return File; +} + + + +template +inline std::ostream & writevar(std::ostream & File, const T & Var, const std::streamsize NbBytes) +{ + // Debug test to ensure type size is big enough + assert(sizeof(T) >= size_t(NbBytes)); + + T TmpVar = Var; + + for (std::streamsize i = 0; i < NbBytes; ++i) + File.write(reinterpret_cast(&(TmpVar >>= (CHAR_BIT * i))), 1); + + return File; +} + + + +////////////////////////////////////////////////////////////////////// +// io_facilities::search_iterator Inline Member Functions +////////////////////////////////////////////////////////////////////// + +inline search_iterator::search_iterator() + : m_Valid(false), +#if defined WIN32 + m_hFiles(-1) +#else + m_Directory(NULL) +#endif + { } + +inline search_iterator::search_iterator(const char * FileSpec) + : m_Valid(false), +#if defined WIN32 + m_hFiles(-1) +#else + m_Directory(NULL) +#endif +{ + begin(FileSpec); +} + +inline search_iterator::~search_iterator() { +#if defined WIN32 + if (m_hFiles != -1) _findclose(m_hFiles); +#else + if (m_Directory != NULL) closedir(m_Directory); +#endif +} + +inline search_iterator::operator bool () const { + return m_Valid; +} + +inline search_iterator & search_iterator::operator ++ () { + return next(); +} + +inline search_iterator & search_iterator::begin(const char * FileSpec) { +#if defined WIN32 + if (m_hFiles != -1) _findclose(m_hFiles); + m_Valid = ((m_hFiles = _findfirst(FileSpec, &m_FindData)) != -1); +#else + std::string DirectoryName; + + if (m_Directory != NULL) closedir(m_Directory); + + int i; + for (i = strlen(FileSpec); i >= 0; --i) + if (FileSpec[i] == '/') break; + + if (i < 0) + DirectoryName = "."; + else + DirectoryName.assign(FileSpec + 0, FileSpec + i++); + + m_Extension = FileSpec + i + 1; + m_Valid = ((m_Directory = opendir(DirectoryName.c_str())) != NULL); + + if (! m_Valid) + return (* this); + + next(); +#endif + + return (* this); +} + +inline bool search_iterator::end() const { + return false; +} + +inline search_iterator & search_iterator::next() { +#if defined WIN32 + m_Valid = (_findnext(m_hFiles, &m_FindData) != -1); +#else + bool Found = false; + while (! Found) { + m_Valid = ((m_DirectoryEntry = readdir(m_Directory)) != NULL); + if (m_Valid) { + std::string FileName = m_DirectoryEntry->d_name; + if (FileName[0] == '.') + Found = false; + else if (FileName.size() <= m_Extension.size()) + Found = false; + else if (std::equal(m_Extension.rbegin(), m_Extension.rend(), FileName.rbegin())) + Found = true; + } + else + break; + } +#endif + + return (* this); +} + +inline std::string search_iterator::Name() const { +#if defined WIN32 + return (m_FindData.name); +#else + return (m_DirectoryEntry->d_name); +#endif +} + + + + +} // namespace io_facilities + + diff --git a/JGE/src/zipFS/static_assert.h b/JGE/src/zipFS/static_assert.h new file mode 100644 index 000000000..ff41d7529 --- /dev/null +++ b/JGE/src/zipFS/static_assert.h @@ -0,0 +1,16 @@ + +#pragma once + + + +namespace mstatic_assert { + + template class compile_time_error; + template <> class compile_time_error { }; + +} + + + +#define mstatic_assert(expr) { mstatic_assert::compile_time_error<((expr) != 0)> ERROR_STATIC_ASSERT; (void) ERROR_STATIC_ASSERT; } +#define mstatic_assert_msg(expr, msg) { mstatic_assert::compile_time_error<((expr) != 0)> ERROR_##msg; (void) ERROR_##msg; } diff --git a/JGE/src/zipFS/stdafx.cpp b/JGE/src/zipFS/stdafx.cpp new file mode 100644 index 000000000..a7cfad1a8 --- /dev/null +++ b/JGE/src/zipFS/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// zfs.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/JGE/src/zipFS/stdafx.h b/JGE/src/zipFS/stdafx.h new file mode 100644 index 000000000..d0e83ed69 --- /dev/null +++ b/JGE/src/zipFS/stdafx.h @@ -0,0 +1,21 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + + +// Standard headers +#include +#include +#include +#include +#include +#include +#include +#include + +//#include "stdint.h" + +#include \ No newline at end of file diff --git a/JGE/src/zipFS/stdint_old.h b/JGE/src/zipFS/stdint_old.h new file mode 100644 index 000000000..0e83819f1 --- /dev/null +++ b/JGE/src/zipFS/stdint_old.h @@ -0,0 +1,77 @@ +#ifndef _ZIPFS_STDINT_H_ +#define _ZIPFS_STDINT_H_ + +#include "static_assert.h" + + +#if defined _MSC_VER + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + +typedef signed char int_least8_t; +typedef unsigned char uint_least8_t; +typedef signed short int_least16_t; +typedef unsigned short uint_least16_t; +typedef signed int int_least32_t; +typedef unsigned int uint_least32_t; +typedef signed __int64 int_least64_t; +typedef unsigned __int64 uint_least64_t; + +#elif defined UNIX + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef signed long long int64_t; +typedef unsigned long long uint64_t; + +typedef signed char int_least8_t; +typedef unsigned char uint_least8_t; +typedef signed short int_least16_t; +typedef unsigned short uint_least16_t; +typedef signed int int_least32_t; +typedef unsigned int uint_least32_t; +typedef signed long long int_least64_t; +typedef unsigned long long uint_least64_t; + +#endif + + + + + +inline void __CheckSizedTypes() +{ + // one byte must be exactly 8 bits + //static_assert(CHAR_BIT == 8); + + mstatic_assert(sizeof(int8_t) == 1); + mstatic_assert(sizeof(uint8_t) == 1); + mstatic_assert(sizeof(int16_t) == 2); + mstatic_assert(sizeof(uint16_t) == 2); + mstatic_assert(sizeof(int32_t) == 4); + mstatic_assert(sizeof(uint32_t) == 4); + mstatic_assert(sizeof(int64_t) == 8); + mstatic_assert(sizeof(uint64_t) == 8); + + mstatic_assert(sizeof(int_least8_t) >= 1); + mstatic_assert(sizeof(uint_least8_t) >= 1); + mstatic_assert(sizeof(int_least16_t) >= 2); + mstatic_assert(sizeof(uint_least16_t) >= 2); + mstatic_assert(sizeof(int_least32_t) >= 4); + mstatic_assert(sizeof(uint_least32_t) >= 4); + mstatic_assert(sizeof(int_least64_t) >= 8); + mstatic_assert(sizeof(uint_least64_t) >= 8); +} + +#endif \ No newline at end of file diff --git a/JGE/src/zipFS/zfs.cpp b/JGE/src/zipFS/zfs.cpp new file mode 100644 index 000000000..646c1767f --- /dev/null +++ b/JGE/src/zipFS/zfs.cpp @@ -0,0 +1,44 @@ +// ZFS.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" + + +// ZFS headers +#include "zfsystem.h" + + + +void DoSomething(std::istream & File) +{ + // Output the file via cout (note: rdbuf() method is a std C++ method, not zfs specific) + std::cout << File.rdbuf() << std::endl; +} + + + +int main(int argc, char * argv[]) +{ + using namespace std; + using zip_file_system::filesystem; + using zip_file_system::izfstream; + + // Create and initialize the Zip File System (basepath, file_extension, makedefault) + // and output the its status via cout + filesystem FileSystem("base_data", "cpk", true); + cout << FileSystem << endl; + + // Try to open a zipped file (Careful! The openmode is always 'ios::in | ios::binary'.) + izfstream File("testfile.txt"); + + if (! File) + cout << "ERROR: Cannot open file!" << endl; + + // Call some function expecting an istream object + DoSomething(File); + + // The End. + cout << "\nPress ENTER to continue." << endl; + cin.get(); +} + diff --git a/JGE/src/zipFS/zfs.sln b/JGE/src/zipFS/zfs.sln new file mode 100644 index 000000000..28797f70d --- /dev/null +++ b/JGE/src/zipFS/zfs.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zfs", "zfs.vcproj", "{54F414A2-0634-467B-95D4-35E8D171D2CA}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {54F414A2-0634-467B-95D4-35E8D171D2CA}.Debug.ActiveCfg = Debug|Win32 + {54F414A2-0634-467B-95D4-35E8D171D2CA}.Debug.Build.0 = Debug|Win32 + {54F414A2-0634-467B-95D4-35E8D171D2CA}.Release.ActiveCfg = Release|Win32 + {54F414A2-0634-467B-95D4-35E8D171D2CA}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/JGE/src/zipFS/zfs.vcproj b/JGE/src/zipFS/zfs.vcproj new file mode 100644 index 000000000..662081baf --- /dev/null +++ b/JGE/src/zipFS/zfs.vcproj @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JGE/src/zipFS/zfs.vcxproj b/JGE/src/zipFS/zfs.vcxproj new file mode 100644 index 000000000..f1223b037 --- /dev/null +++ b/JGE/src/zipFS/zfs.vcxproj @@ -0,0 +1,105 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {54F414A2-0634-467B-95D4-35E8D171D2CA} + Win32Proj + + + + Application + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + . + Debug\ + true + Release\ + Release\ + false + .lib + + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + NotUsing + Level3 + EditAndContinue + ..\JGE\Dependencies\include;%(AdditionalIncludeDirectories) + /NODEFAULTLIB:LIBCMT /NODEFAULTLIB:MSVCPRTD %(AdditionalOptions) + + + $(OutDir)zfs.exe + true + $(OutDir)zfs.pdb + Console + MachineX86 + + + + + + + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + $(OutDir)zfs.exe + true + Console + true + true + MachineX86 + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/JGE/src/zipFS/zfs.vcxproj.filters b/JGE/src/zipFS/zfs.vcxproj.filters new file mode 100644 index 000000000..f6794b8ce --- /dev/null +++ b/JGE/src/zipFS/zfs.vcxproj.filters @@ -0,0 +1,53 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/JGE/src/zipFS/zfsystem.cpp b/JGE/src/zipFS/zfsystem.cpp new file mode 100644 index 000000000..c821b7c45 --- /dev/null +++ b/JGE/src/zipFS/zfsystem.cpp @@ -0,0 +1,651 @@ +//Important: This file has been modified in order to be integrated in to JGE++ +// + +// zfsystem.cpp: implementation of the zip file system classes. +// +// Copyright (C) 2004 Tanguy Fautré. +// For conditions of distribution and use, +// see copyright notice in zfsystem.h +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "zfsystem.h" + +#include "fileio.h" // I/O facilities + + +#if defined (WIN32) +#include +#endif + +#include + +namespace zip_file_system { + +using namespace std; + + + + +////////////////////////////////////////////////////////////////////// +// Static variables initialization +////////////////////////////////////////////////////////////////////// + +filesystem * izfstream::pDefaultFS = NULL; +string filesystem::CurrentZipName = ""; +ifstream filesystem::CurrentZipFile; +filesystem * filesystem::pCurrentFS = NULL; + +static const int STORED = 0; +static const int DEFLATED = 8; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +filesystem::filesystem(const char * BasePath, const char * FileExt, bool DefaultFS) + : m_BasePath(BasePath), m_FileExt(FileExt) +{ + using io_facilities::search_iterator; + + // Init m_BasePath and be sure the base path finish with a '/' or a '\' + if (! m_BasePath.empty()) { + string::iterator c = --(m_BasePath.end()); + if ((*c != '/') && (*c != '\\')) + m_BasePath += '/'; + } + + // Search all *.zip files (or whatever the ZipExt specify as the file extension) + vector ZipFiles; + + for (search_iterator ZSrch = (m_BasePath + "*." + m_FileExt).c_str(); ZSrch != ZSrch.end(); ++ZSrch) + ZipFiles.push_back(ZSrch.Name()); + + // Open each zip files that have been found, in alphabetic order + sort(ZipFiles.begin(), ZipFiles.end()); + + for (vector::const_iterator ZipIt = ZipFiles.begin(); ZipIt != ZipFiles.end(); ++ZipIt) + InsertZip(ZipIt->c_str(), ZipIt - ZipFiles.begin()); + + // Should we make this the default File System for ifile? + if (DefaultFS) + MakeDefault(); +} + + + +////////////////////////////////////////////////////////////////////// +// File System Member Functions +////////////////////////////////////////////////////////////////////// + +void filesystem::Open(izfstream & File, const char * Filename) +{ + // Close the file if it was opened; + File.close(); + File.setFS(this); + + // Generate the path and see if the file is zipped or not + string FullPath = m_BasePath + Filename; + + // File is not zipped + if (FileNotZipped(FullPath.c_str())) { + + // Link the izfile object with an opened filebuf + filebuf * FileBuf = new filebuf; + FileBuf->open(FullPath.c_str(), ios::binary | ios::in); + + if (FileBuf->is_open()) { + delete File.rdbuf(FileBuf); + File.clear(ios::goodbit); + File.m_FilePath = Filename; + File.m_FullFilePath = FullPath; + File.m_Zipped = false; + } + + // File is maybe zipped + } else { + + file_info FileInfo; + string ZipPath; + + // Check whether the file is zipped, whether the file is a directory and try to open. + if (FindFile(Filename, &FileInfo) && (! FileInfo.m_Directory) && (! ((ZipPath = FindZip(FileInfo.m_PackID)).empty()))) { + + // Get the position of the compressed data + if (CurrentZipName.size()) + { + if ((pCurrentFS!= this) || (CurrentZipName.compare(ZipPath) != 0)) + { + CurrentZipFile.close(); + CurrentZipName = ""; + pCurrentFS = NULL; + } + } + if (!CurrentZipName.size()) + { + CurrentZipName = ZipPath; + string zipName = m_BasePath + CurrentZipName; + CurrentZipFile.open(zipName.c_str(), ios::binary); + pCurrentFS = this; + } + + if (!CurrentZipFile) { + CurrentZipName = ""; + pCurrentFS = NULL; + return; + } + + streamoff DataPos = SkipLFHdr(CurrentZipFile, streamoff(FileInfo.m_Offset)); + + if (DataPos != streamoff(-1)) { + string zipName = m_BasePath + CurrentZipName; + // Open the file at the right position + ((izstream &) File).open( + zipName.c_str(), + streamoff(DataPos), + streamoff(FileInfo.m_CompSize), + FileInfo.m_CompMethod + ); + + if (File) { + File.m_FilePath = Filename; + File.m_FullFilePath = FullPath; + File.m_Zipped = true; + File.m_UncompSize = FileInfo.m_Size; + File.m_CompSize = FileInfo.m_CompSize; + File.m_Offset = FileInfo.m_Offset; + } + } + + } + } +} + +bool filesystem::DirExists(const std::string & folderName) +{ + + //check real folder + string FullPath = m_BasePath + folderName; + +#if defined (WIN32) + struct _stat statBuffer; + if ((_stat(FullPath.c_str(), &statBuffer) >= 0 && // make sure it exists + statBuffer.st_mode & S_IFDIR)) // and it's not a file + return true; +#else + struct stat st; + if (stat(FullPath.c_str(), &st) == 0) + return true; +#endif + + //Check in zip + file_info FileInfo; + + // Check whether the file is zipped, whether the file is a directory and try to open. + if (FindFile(folderName.c_str(), &FileInfo) && (FileInfo.m_Directory)) + return true; + + //Neither in real folder nor in zip + return false; +} + +// Note: this doesn't scan the folders outside of the zip...should we add that here ? +std::vector& filesystem::scanfolder(const std::string& folderName, std::vector& results) +{ + filemap_const_iterator folderPos = m_Files.find(folderName); + + if (folderPos == m_Files.end()) + return results; + + filemap_const_iterator It = folderPos; + + string folderNameLC = folderName; + std::transform(folderNameLC.begin(), folderNameLC.end(), folderNameLC.begin(), ::tolower); + size_t length = folderNameLC.length(); + + while(++It != m_Files.end()) + { + string currentFile = (* It).first; + string currentFileLC = currentFile; + std::transform(currentFileLC.begin(), currentFileLC.end(), currentFileLC.begin(), ::tolower); + if (currentFileLC.find(folderNameLC) == 0) + { + string relativePath = currentFile.substr(length); + size_t pos = relativePath.find_first_of("/\\"); + //Only add direct children, no recursive browse + if (pos == string::npos || pos == (relativePath.length() - 1)) + results.push_back(relativePath); + } + else + { + break; + //We know other files will not belong to that folder because of the order of the map + } + } + + return results; +} + + +////////////////////////////////////////////////////////////////////// +// File System Protected Member Functions +////////////////////////////////////////////////////////////////////// + +bool filesystem::FileNotZipped(const char * FilePath) const +{ + //return io_facilities::search_iterator(FilePath); + // follow new search_iterator implementation + std::ifstream File(FilePath); + + if (! File) + return false; + + return true; +} + + + +bool filesystem::FindFile(const char * Filename, file_info * FileInfo) const +{ + filemap_const_iterator It = m_Files.find(Filename); + + if (It == m_Files.end()) + return false; // File not found + + * FileInfo = (* It).second; + return true; +} + + + +const string & filesystem::FindZip(size_t PackID) const +{ + static const string EmptyString; + + zipmap_const_iterator It = m_Zips.find(PackID); + + if (It == m_Zips.end()) + return EmptyString; // PackID not valid + + return (* It).second.m_Filename; +} + + + +void filesystem::InsertZip(const char * Filename, const size_t PackID) +{ + zipfile_info ZipInfo; + + // Get full path to the zip file and prepare ZipInfo + ZipInfo.m_Filename = Filename; + string ZipPath = m_BasePath + Filename; + + // Open zip + ifstream File(ZipPath.c_str(), ios::binary); + + if (! File) + return; + + // Find the start of the central directory + if (! File.seekg(CentralDir(File))) return; + + // Check every headers within the zip file + file_header FileHdr; + + while ((NextHeader(File) == FILE) && (FileHdr.ReadHeader(File))) { + + // Include files into Files map + const char * Name = &(* FileHdr.m_Filename.begin()); + const unsigned short i = FileHdr.m_FilenameSize - 1; + if (FileHdr.m_FilenameSize != 0) { + + m_Files[Name] = file_info( + PackID, // Package ID + FileHdr.m_RelOffset, // "Local File" header offset position + FileHdr.m_UncompSize, // File Size + FileHdr.m_CompSize, // Compressed File Size + FileHdr.m_CompMethod, // Compression Method; + ((Name[i] == '/') || (Name[i] == '\\')) // Is a directory? + ); + + ++(ZipInfo.m_NbEntries); + ZipInfo.m_FilesSize += FileHdr.m_UncompSize; + ZipInfo.m_FilesCompSize += FileHdr.m_CompSize; + } + } + + File.close(); + + // Add zip file to Zips data base (only if not empty) + if (ZipInfo.m_NbEntries != 0) + m_Zips[PackID] = ZipInfo; +} + + +bool filesystem::PreloadZip(const char * Filename, map& target) +{ + zipfile_info ZipInfo; + + // Open zip + izfstream File; + File.open(Filename, this); + + if (! File) + return false; + + // Find the start of the central directory + if (File.Zipped()) + { + streamoff realBeginOfFile = SkipLFHdr(CurrentZipFile, File.getOffset()); + if (! CurrentZipFile.seekg(CentralDirZipped(CurrentZipFile, realBeginOfFile, File.getCompSize()))) + return false; + + // Check every headers within the zip file + file_header FileHdr; + + while ((NextHeader(CurrentZipFile) == FILE) && (FileHdr.ReadHeader(CurrentZipFile))) { + + // Include files into Files map + const char * Name = &(* FileHdr.m_Filename.begin()); + const unsigned short i = FileHdr.m_FilenameSize - 1; + if (FileHdr.m_FilenameSize != 0) { + + // The zip in zip method only supports stored Zips because of JFileSystem limitations + if ((FileHdr.m_UncompSize != FileHdr.m_CompSize) || FileHdr.m_CompMethod != STORED) + continue; + + target[Name] = file_info( + 1, // Package ID + realBeginOfFile + FileHdr.m_RelOffset, // "Local File" header offset position + FileHdr.m_UncompSize, // File Size + FileHdr.m_CompSize, // Compressed File Size + FileHdr.m_CompMethod, // Compression Method; + ((Name[i] == '/') || (Name[i] == '\\')) // Is a directory? + ); + } + } + + File.close(); + return (target.size() ? true : false); + } + else + { + if (! File.seekg(CentralDir(File))) + return false; + + // Check every headers within the zip file + file_header FileHdr; + + while ((NextHeader(File) == FILE) && (FileHdr.ReadHeader(File))) { + + // Include files into Files map + const char * Name = &(* FileHdr.m_Filename.begin()); + const unsigned short i = FileHdr.m_FilenameSize - 1; + if (FileHdr.m_FilenameSize != 0) { + + target[Name] = file_info( + 1, // Package ID + FileHdr.m_RelOffset, // "Local File" header offset position + FileHdr.m_UncompSize, // File Size + FileHdr.m_CompSize, // Compressed File Size + FileHdr.m_CompMethod, // Compression Method; + ((Name[i] == '/') || (Name[i] == '\\')) // Is a directory? + ); + } + } + + File.close(); + return (target.size() ? true : false); + } + + +} + + + +////////////////////////////////////////////////////////////////////// +// File System Friend Functions +////////////////////////////////////////////////////////////////////// + +ostream & operator << (ostream & Out, const filesystem & FS) +{ + size_t NbFiles = 0; + filesystem::zipfile_info AllZipsInfo; + + for (filesystem::zipmap_const_iterator It = FS.m_Zips.begin(); It != FS.m_Zips.end(); ++It) { + + const filesystem::zipfile_info & ZInfo = (* It).second; + + // Print zip filename + Out << setiosflags(ios::left) << setw(32) << "-> \"" + ZInfo.m_Filename + "\"" << resetiosflags(ios::left); + // Print number of entries found in this zip file + Out << " " << setw(5) << ZInfo.m_NbEntries << " files"; + // Print the uncompressed size of all included files + Out << " " << setw(7) << ZInfo.m_FilesSize / 1024 << " KB"; + // Print the compressed size of all these files + Out << " " << setw(7) << ZInfo.m_FilesCompSize / 1024 << " KB packed" << endl; + + ++NbFiles; + AllZipsInfo.m_NbEntries += ZInfo.m_NbEntries; + AllZipsInfo.m_FilesSize += ZInfo.m_FilesSize; + AllZipsInfo.m_FilesCompSize += ZInfo.m_FilesCompSize; + } + + // Print the general info + Out << "\nTotal: "; + Out << NbFiles << " packs "; + Out << AllZipsInfo.m_NbEntries << " files "; + Out << float(AllZipsInfo.m_FilesSize) / (1024 * 1024) << " MB "; + Out << float(AllZipsInfo.m_FilesCompSize) / (1024 * 1024) << " MB packed." << endl; + + return Out; +} + + + +////////////////////////////////////////////////////////////////////// +// "Less Than" Comparaison lt_path_str Member Functions +////////////////////////////////////////////////////////////////////// + +bool filesystem::lt_path::operator () (const string & s1, const string & s2) const +{ + const char * A = s1.c_str(); + const char * B = s2.c_str(); + + for (size_t i = 0; ; ++i) { + + if ((A[i] == '\0') && (B[i] == '\0')) + return false; + + // case insensitive and '/' is the same as '\' + if (! ( + (A[i] == B[i] + ('a' - 'A')) || + (A[i] == B[i] - ('a' - 'A')) || + (A[i] == B[i]) || + ((A[i] == '\\') && (B[i] == '/')) || + ((A[i] == '/') && (B[i] == '\\')) + )) { + + if ((A[i] == '\0') || (A[i] < B[i])) + return true; + else + return false; + } + } +} + + + +////////////////////////////////////////////////////////////////////// +// Zip Header Classes Related Member Functions +////////////////////////////////////////////////////////////////////// + + +streamoff filesystem::CentralDirZipped(std::istream & File, std::streamoff begin, std::size_t size) const +{ + using io_facilities::readvar; + + std::streamoff eof = begin + size; + + // Look for the "end of central dir" header. Start minimum 22 bytes before end. + if (! File.seekg(eof - 22, ios::beg)) + return -1; + + streamoff EndPos; + streamoff StartPos = File.tellg(); + + if (StartPos == streamoff(0)) + return -1; + + if (StartPos <= begin + streamoff(65536)) + EndPos = 1; + else + EndPos = StartPos - streamoff(65536); + + // Start the scan + do { + unsigned int RawSignature; + + if (! readvar(File, RawSignature, 4)) + return -1; + + eofcd_header Header; + streampos Pos = File.tellg(); + + // Found a potential "eofcd" header? + if ((RawSignature == ENDOFDIR) && (File.seekg(-4, ios::cur)) && (Header.ReadHeader(File))) { + + // Check invariant values (1 disk only) + if ((Header.m_NbDisks == 0) && (0 == Header.m_DirDisk) && (Header.m_LocalEntries == Header.m_TotalEntries)) { + + // Check comment ends at eof + if (! File.seekg(eof - 1 , ios::beg)) + return -1; + if ((File.tellg() + streamoff(1)) == (Pos + streamoff(Header.m_CommentSize + 22 - 4))) { + + // Check the start offset leads to a correct directory/file header; + if (! File.seekg(begin + Header.m_Offset)) return -1; + if (! readvar(File, RawSignature, 4)) return -1; + if (RawSignature == FILE) + return begin + Header.m_Offset; + } + } + } + + File.seekg(Pos); + + } while ((File.seekg(-5, ios::cur)) && (File.tellg() > EndPos) && (File.tellg() > begin)); + + return -1; +} + +streamoff filesystem::CentralDir(istream & File) const +{ + using io_facilities::readvar; + + // Look for the "end of central dir" header. Start minimum 22 bytes before end. + if (! File.seekg(-22, ios::end)) return -1; + + streamoff EndPos; + streamoff StartPos = File.tellg(); + + if (StartPos == streamoff(0)) return -1; + + if (StartPos <= streamoff(65536)) + EndPos = 1; + else + EndPos = StartPos - streamoff(65536); + + // Start the scan + do { + unsigned int RawSignature; + + if (! readvar(File, RawSignature, 4)) return -1; + + eofcd_header Header; + streampos Pos = File.tellg(); + + // Found a potential "eofcd" header? + if ((RawSignature == ENDOFDIR) && (File.seekg(-4, ios::cur)) && (Header.ReadHeader(File))) { + + // Check invariant values (1 disk only) + if ((Header.m_NbDisks == 0) && (0 == Header.m_DirDisk) && (Header.m_LocalEntries == Header.m_TotalEntries)) { + + // Check comment ends at eof + if (! File.seekg(-1, ios::end)) return -1; + if ((File.tellg() + streamoff(1)) == (Pos + streamoff(Header.m_CommentSize + 22 - 4))) { + + // Check the start offset leads to a correct directory/file header; + if (! File.seekg(Header.m_Offset)) return -1; + if (! readvar(File, RawSignature, 4)) return -1; + if (RawSignature == FILE) + return Header.m_Offset; + } + } + } + + File.seekg(Pos); + + } while ((File.seekg(-5, ios::cur)) && (File.tellg() > EndPos)); + + return -1; +} + + + +streamoff filesystem::SkipLFHdr(istream & File, streamoff LFHdrPos) +{ + using io_facilities::readvar; + + unsigned short NameSize; + unsigned short FieldSize; + unsigned int RawSignature; + + // verify it's a local header + if (! File.seekg(LFHdrPos)) return -1; + if (! readvar(File, RawSignature, 4)) return -1; + if (RawSignature != LOCALFILE) return -1; + + // Skip and go directly to comment/field size + if (! File.seekg(22, ios::cur)) return -1; + if (! readvar(File, NameSize, 2)) return -1; + if (! readvar(File, FieldSize, 2)) return -1; + + // Skip comment and extra field + if (! File.seekg(NameSize + FieldSize, ios::cur)) return -1; + + // Now we are at the compressed data position + return (File.tellg()); +} + + + +headerid filesystem::NextHeader(istream & File) const +{ + using io_facilities::readvar; + + unsigned int RawSignature; + + if (! readvar(File, RawSignature, 4)) + return READERROR; + + if (! File.seekg(-4, ios::cur)) + return READERROR; + + headerid Signature = headerid(RawSignature); + + switch (Signature) { + case FILE: + case LOCALFILE: + case ENDOFDIR: + return Signature; + default: + return UNKNOWN; + } +} + + + + +} // namespace zip_file_system diff --git a/JGE/src/zipFS/zfsystem.h b/JGE/src/zipFS/zfsystem.h new file mode 100644 index 000000000..2e1de3960 --- /dev/null +++ b/JGE/src/zipFS/zfsystem.h @@ -0,0 +1,288 @@ +//Important: This file has been modified in order to be integrated in to JGE++ +// + +// zfsystem.h: interface for the zip file system classes. +// +////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2004 Tanguy Fautré. +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// +// Tanguy Fautré +// softdev@telenet.be +// +////////////////////////////////////////////////////////////////////// +// +// Zip File System. +// **************** +// +// Current version: 1.00 BETA 2 (16/07/2004) +// +// Comment: - +// +// History: - 1.00 BETA 2 (16/07/2004) - Updated to follow latest version +// of fileio.h +// - 1.00 BETA 1 (21/07/2002) - First public release +// +////////////////////////////////////////////////////////////////////// + +#pragma once + + +#include "stdafx.h" +#include "ziphdr.h" // Zip file header +#include "zstream.h" // Zip Stream + + + +// Zip File System Namespace +namespace zip_file_system { + + + + +class filesystem; + + + +// Input Zip File class +class izfstream : public izstream +{ +public: + izfstream(filesystem * pFS = pDefaultFS); + izfstream(const char * FilePath, filesystem * pFS = pDefaultFS); + + void open(const char * FilePath, filesystem * pFS = pDefaultFS); + void close(); + + bool is_open() const; + + void setFS(filesystem * pFS = pDefaultFS); + + bool Zipped() const; + const std::string & FilePath() const; + const std::string & FullFilePath() const; + size_t getUncompSize(); + size_t getOffset(); + size_t getCompSize(); + +protected: + friend class filesystem; + + // Default File System Pointer (default = NULL) + static filesystem * pDefaultFS; + + std::string m_FilePath; + std::string m_FullFilePath; + filesystem * m_pFS; + bool m_Zipped; + size_t m_UncompSize; + size_t m_Offset; + size_t m_CompSize; + +}; + + + + +// Zip File System central class +class filesystem +{ +public: + // "local" file info class + class file_info + { + public: + file_info() : m_PackID(0), m_Offset(0), m_Size(0), m_CompSize(0), m_CompMethod(0), m_Directory(true) { } + file_info(size_t PackID, size_t Offset, size_t Size, size_t CompSize, short CompMethod, bool Directory) : + m_PackID(PackID), m_Offset(Offset), m_Size(Size), m_CompSize(CompSize), m_CompMethod(CompMethod), m_Directory(Directory) { } + + size_t m_PackID; + size_t m_Offset; + size_t m_Size; + size_t m_CompSize; + short m_CompMethod; + bool m_Directory; + }; + + filesystem(const char * BasePath = "", const char * FileExt = "zip", bool DefaultFS = true); + ~filesystem(); + + void MakeDefault(); + void Open(izfstream & File, const char * Filename); + bool DirExists(const std::string & folderName); + bool PreloadZip(const char * Filename, std::map& target); + static std::string getCurrentZipName(); + static filesystem * getCurrentFS(); + static std::streamoff SkipLFHdr(std::istream & File, std::streamoff LFHdrPos); + + //Fills the vector results with a list of children of the given folder + std::vector& scanfolder(const std::string& folderName, std::vector& results); + + friend std::ostream & operator << (std::ostream & Out, const filesystem & FS); + +protected: + + // Zip file info class + class zipfile_info + { + public: + zipfile_info() : m_NbEntries(0), m_FilesSize(0), m_FilesCompSize(0) { } + + std::string m_Filename; + size_t m_NbEntries; + size_t m_FilesSize; + size_t m_FilesCompSize; + }; + + // Class for file path string comparaison + struct lt_path + { + bool operator() (const std::string & s1, const std::string & s2) const; + }; + + + // Protected member functions + // Zip file format related functions + std::streamoff CentralDir(std::istream & File) const; + std::streamoff CentralDirZipped(std::istream & File, std::streamoff begin, std::size_t size) const; + headerid NextHeader(std::istream & File) const; + + // File/Zip map related functions + bool FileNotZipped(const char * FilePath) const; + bool FindFile(const char * Filename, file_info * FileInfo) const; + const std::string & FindZip(size_t PackID) const; + void InsertZip(const char * Filename, const size_t PackID); + + // New type definitions + typedef std::map zipmap; + typedef std::map::iterator zipmap_iterator; + typedef std::map::const_iterator zipmap_const_iterator; + typedef std::map filemap; + typedef std::map::iterator filemap_iterator; + typedef std::map::const_iterator filemap_const_iterator; + + // Mighty protected member variables + std::string m_BasePath; + std::string m_FileExt; + zipmap m_Zips; + filemap m_Files; + static std::ifstream CurrentZipFile; + static std::string CurrentZipName; + static filesystem * pCurrentFS; +}; + + + + +////////////////////////////////////////////////////////////////////// +// zip_file_system::izfile Inline Functions +////////////////////////////////////////////////////////////////////// + +inline izfstream::izfstream(filesystem * pFS) : m_pFS(pFS) { } + +inline izfstream::izfstream(const char * FilePath, filesystem * pFS) : m_pFS(pFS) { + open(FilePath); +} + +inline void izfstream::setFS(filesystem * pFS) { + m_pFS = pFS; +} + +inline size_t izfstream::getUncompSize() +{ + return m_UncompSize; +} + +inline size_t izfstream::getOffset() +{ + return m_Offset; +} + +inline size_t izfstream::getCompSize() +{ + return m_CompSize; +} + + + +inline void izfstream::open(const char * FilePath, filesystem * pFS) { + if (pFS) + m_pFS = pFS; + + if (m_pFS != NULL) + m_pFS->Open(* this, FilePath); +} + +inline void izfstream::close() { + izstream::close(); + m_FilePath = m_FullFilePath = ""; + m_UncompSize = 0; +} + +inline bool izfstream::is_open() const { + return static_cast(rdbuf())->is_open(); +} + +inline bool izfstream::Zipped() const { + return m_Zipped; +} + +inline const std::string & izfstream::FilePath() const { + return m_FilePath; +} + +inline const std::string & izfstream::FullFilePath() const { + return m_FullFilePath; +} + + + +////////////////////////////////////////////////////////////////////// +// zip_file_system::filesystem Inline Functions +////////////////////////////////////////////////////////////////////// + +inline filesystem::~filesystem() { + // Security mesure with izfile::pDefaultFS + if (izfstream::pDefaultFS == this) + izfstream::pDefaultFS = NULL; + + if (CurrentZipName.size()) + { + CurrentZipFile.close(); + CurrentZipName = ""; + } +} + +inline void filesystem::MakeDefault() { + izfstream::pDefaultFS = this; +} + + +inline std::string filesystem::getCurrentZipName() +{ + return CurrentZipName; +} + +inline filesystem * filesystem::getCurrentFS() +{ + return pCurrentFS; +} + +} // namespace zip_file_system + diff --git a/JGE/src/zipFS/ziphdr.cpp b/JGE/src/zipFS/ziphdr.cpp new file mode 100644 index 000000000..ff85c51d9 --- /dev/null +++ b/JGE/src/zipFS/ziphdr.cpp @@ -0,0 +1,123 @@ +// ziphdr.cpp: implementation of the zip header classes. +// +// Copyright (C) 2002 Tanguy Fautré. +// For conditions of distribution and use, +// see copyright notice in ziphdr.h +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "ziphdr.h" + +#include "fileio.h" // I/O facilities + + + +namespace zip_file_system { + + + + +////////////////////////////////////////////////////////////////////// +// Zip Header Classes Member Functions +////////////////////////////////////////////////////////////////////// + +bool local_file_header::ReadHeader(std::istream & File) +{ + using io_facilities::readvar; + + // quick check about char size + //static_assert(CHAR_BIT == 8); + + if (! readvar(File, m_Signature, 4)) return false; + if (! readvar(File, m_VersionExtract, 2)) return false; + if (! readvar(File, m_GeneralFlags, 2)) return false; + if (! readvar(File, m_CompMethod, 2)) return false; + if (! readvar(File, m_Time, 2)) return false; + if (! readvar(File, m_Date, 2)) return false; + if (! readvar(File, m_CRC32, 4)) return false; + if (! readvar(File, m_CompSize, 4)) return false; + if (! readvar(File, m_UncompSize, 4)) return false; + if (! readvar(File, m_FilenameSize, 2)) return false; + if (! readvar(File, m_FieldSize, 2)) return false; + + m_Filename.resize(m_FilenameSize + 1); + m_ExtraField.resize(m_FieldSize + 1); + + if (! File.read(&(m_Filename[0]), m_FilenameSize)) return false; + if (! File.read(&(m_ExtraField[0]), m_FieldSize)) return false; + + m_Filename[m_FilenameSize] = '\0'; + m_ExtraField[m_FieldSize] = '\0'; + + return true; +} + + + +bool file_header::ReadHeader(std::istream & File) +{ + using io_facilities::readvar; + + if (! readvar(File, m_Signature, 4)) return false; + if (! readvar(File, m_VersionMade, 2)) return false; + if (! readvar(File, m_VersionExtract, 2)) return false; + if (! readvar(File, m_GeneralFlags, 2)) return false; + if (! readvar(File, m_CompMethod, 2)) return false; + if (! readvar(File, m_Time, 2)) return false; + if (! readvar(File, m_Date, 2)) return false; + if (! readvar(File, m_CRC32, 4)) return false; + if (! readvar(File, m_CompSize, 4)) return false; + if (! readvar(File, m_UncompSize, 4)) return false; + if (! readvar(File, m_FilenameSize, 2)) return false; + if (! readvar(File, m_FieldSize, 2)) return false; + if (! readvar(File, m_CommentSize, 2)) return false; + if (! readvar(File, m_DiskNb, 2)) return false; + if (! readvar(File, m_IntAttrib, 2)) return false; + if (! readvar(File, m_ExtAttrib, 4)) return false; + if (! readvar(File, m_RelOffset, 4)) return false; + + m_Filename.resize(m_FilenameSize + 1); + m_ExtraField.resize(m_FieldSize + 1); + m_Comment.resize(m_CommentSize + 1); + + if (! File.read(&(m_Filename[0]), m_FilenameSize)) return false; + if (! File.read(&(m_ExtraField[0]), m_FieldSize)) return false; + if (! File.read(&(m_Comment[0]), m_CommentSize)) return false; + + m_Filename[m_FilenameSize] = '\0'; + m_ExtraField[m_FieldSize] = '\0'; + m_Comment[m_CommentSize] = '\0'; + + return true; +} + + + +bool eofcd_header::ReadHeader(std::istream & File) +{ + using io_facilities::readvar; + + if (! readvar(File, m_Signature, 4)) return false; + if (! readvar(File, m_NbDisks, 2)) return false; + if (! readvar(File, m_DirDisk, 2)) return false; + if (! readvar(File, m_LocalEntries, 2)) return false; + if (! readvar(File, m_TotalEntries, 2)) return false; + if (! readvar(File, m_DirSize, 4)) return false; + if (! readvar(File, m_Offset, 4)) return false; + if (! readvar(File, m_CommentSize, 2)) return false; + + m_Comment.resize(m_CommentSize + 1); + + if (! File.read(&(m_Comment[0]), m_CommentSize)) return false; + + m_Comment[m_CommentSize] = '\0'; + + return true; +} + + + + +} // namespace zip_file_system + diff --git a/JGE/src/zipFS/ziphdr.h b/JGE/src/zipFS/ziphdr.h new file mode 100644 index 000000000..530d83c98 --- /dev/null +++ b/JGE/src/zipFS/ziphdr.h @@ -0,0 +1,143 @@ +// zfsystem.h: interface for the zip header classes. +// +////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002 Tanguy Fautré. +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// +// Tanguy Fautré +// softdev@telenet.be +// +////////////////////////////////////////////////////////////////////// +// +// Zip File Format Headers. +// *********************** +// +// Current version: 1.00 BETA 2 (01/09/2003) +// +// Comment: Based on the ZIP file format specification from Appnote.txt +// from the PKZip Website on July 13, 1998. +// New implementations of the ZIP file format might not work +// correctly (ZIP64 ?). +// +// History: - 1.00 BETA 2 (01/09/2003) - Use stdint.h sized types +// - 1.00 BETA 1 (12/06/2002) - First public release +// +////////////////////////////////////////////////////////////////////// + +#pragma once + + + +// Zip File System Namespace +namespace zip_file_system { + + + + +// Zip file headers +enum headerid { LOCALFILE = 0x04034b50, + FILE = 0x02014b50, + ENDOFDIR = 0x06054b50, + UNKNOWN, + READERROR +}; + + + +// Zip file "local file" header class +struct local_file_header +{ + bool ReadHeader(std::istream & File); + + static const uint_least32_t m_ConstSign= LOCALFILE; + + uint_least32_t m_Signature; + uint_least16_t m_VersionExtract; + uint_least16_t m_GeneralFlags; + uint_least16_t m_CompMethod; + uint_least16_t m_Time; + uint_least16_t m_Date; + uint_least32_t m_CRC32; + uint_least32_t m_CompSize; + uint_least32_t m_UncompSize; + uint_least16_t m_FilenameSize; + uint_least16_t m_FieldSize; + + std::vector m_Filename; + std::vector m_ExtraField; +}; + + + +// Zip file "file header" header class +struct file_header +{ + bool ReadHeader(std::istream & File); + + static const headerid m_ConstSign = FILE; + + uint_least32_t m_Signature; + uint_least16_t m_VersionMade; + uint_least16_t m_VersionExtract; + uint_least16_t m_GeneralFlags; + uint_least16_t m_CompMethod; + uint_least16_t m_Time; + uint_least16_t m_Date; + uint_least32_t m_CRC32; + uint_least32_t m_CompSize; + uint_least32_t m_UncompSize; + uint_least16_t m_FilenameSize; + uint_least16_t m_FieldSize; + uint_least16_t m_CommentSize; + uint_least16_t m_DiskNb; + uint_least16_t m_IntAttrib; + uint_least32_t m_ExtAttrib; + uint_least32_t m_RelOffset; + + std::vector m_Filename; + std::vector m_ExtraField; + std::vector m_Comment; +}; + + + +// Zip file "end of central dir" header class +struct eofcd_header +{ + bool ReadHeader(std::istream & File); + + static const headerid m_ConstSign = ENDOFDIR; + + uint_least32_t m_Signature; + uint_least16_t m_NbDisks; + uint_least16_t m_DirDisk; + uint_least16_t m_LocalEntries; + uint_least16_t m_TotalEntries; + uint_least32_t m_DirSize; + uint_least32_t m_Offset; + uint_least16_t m_CommentSize; + + std::vector m_Comment; +}; + + + + +} // namespace zip_file_system + diff --git a/JGE/src/zipFS/zstream.cpp b/JGE/src/zipFS/zstream.cpp new file mode 100644 index 000000000..e9ee966ff --- /dev/null +++ b/JGE/src/zipFS/zstream.cpp @@ -0,0 +1,427 @@ +// zstream.cpp: implementation of the zstream class. +// +// Copyright (C) 2002 Tanguy Fautré. +// For conditions of distribution and use, +// see copyright notice in zfsystem.h +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "zstream.h" + + + +namespace zip_file_system { + +using namespace std; + + + + +////////////////////////////////////////////////////////////////////// +// zstream Member Functions +////////////////////////////////////////////////////////////////////// + +void izstream::open(const char * Filename, streamoff Offset, streamoff Size, int CompMethod) +{ + // Change the buffer if need + if (m_CompMethod == CompMethod) { + if (rdbuf() != NULL) + static_cast(rdbuf())->close(); + } else + SetCompMethod(CompMethod); + + // clear up the file status + clear(ios::goodbit); + + // open the buffer + switch (m_CompMethod) { + case STORED: + case DEFLATED: + + if (! (static_cast(rdbuf())->open(Filename, Offset, Size))) { + setstate(ios::badbit); + SetCompMethod(-1); + } + + break; + + default: + setstate(ios::badbit); + } +} + +zbuffer * izstream::GetRightBuffer(int CompMethod) const +{ + switch (CompMethod) { + + // stored + case STORED: + return new zbuffer_stored; + + // deflated + case DEFLATED: + return new zbuffer_deflated; + + // else not supported + default: + return NULL; + } +} + + + +////////////////////////////////////////////////////////////////////// +// zbuffer_stored Member Functions +////////////////////////////////////////////////////////////////////// + +zbuffer_stored * zbuffer_stored::open(const char * Filename, streamoff Offset, streamoff Size) +{ + // open main compressed file + m_ZipFile.open(Filename, ios::binary); + if (! m_ZipFile) + return NULL; + + // adjust file position + if (! m_ZipFile.seekg(Offset, ios::beg)) + return NULL; + + m_Opened = true; + m_Pos = -1; + m_Size = Size; + + return this; +} + + + +zbuffer_stored * zbuffer_stored::close() +{ + if (! m_Opened) + return NULL; + else { + m_Opened = false; + m_ZipFile.close(); + } + + return this; +} + + + +int zbuffer_stored::overflow(int c) +{ + return EOF; +} + + + +int zbuffer_stored::underflow() +{ + // Buffer Valid? + if (! m_Opened) + return EOF; + + // Do we really need to refill it? + if (gptr() < egptr()) + return static_cast(* gptr()); + + // Refill de buffer. + streamoff ToRead = ((m_Size - m_Pos) < BUFFERSIZE) ? (m_Size - m_Pos) : BUFFERSIZE; + if ((ToRead == 0) || (! m_ZipFile.read(m_Buffer, BUFFERSIZE))) + return EOF; + + // Set the real position of the beginning of the buffer. + if (m_Pos == streamoff(-1)) + m_Pos = 0; + else + m_Pos += ToRead; + + // Reset buffer pointers. + setg( m_Buffer, // beginning of putback area + m_Buffer, // read position + m_Buffer + ToRead); // end of buffer + + return static_cast(m_Buffer[0]); +} + + + +streampos zbuffer_stored::seekoff(streamoff off, ios::seekdir dir, ios::openmode nMode) +{ + streamoff WantedPos = 0; + + // Find out the wanted position. + switch (dir) { + case ios_base::cur: + WantedPos = m_Pos + streamoff(gptr() - eback()) + off; + break; + + case ios_base::beg: + WantedPos = off; + break; + + case ios_base::end: + WantedPos = m_Size + off; + break; + + default: + assert(false); + } + + // Is the position valid? + if ((WantedPos < 0) || (WantedPos > m_Size)) + return streambuf::seekoff(off, dir, nMode); // return invalid streamoff + + // Is the position already within the buffer? + if ((WantedPos >= m_Pos) && (WantedPos - m_Pos < egptr() - eback())) { + setg(eback(), eback() + (WantedPos - m_Pos), egptr()); + return WantedPos; + } + + // Fill up the buffer at the right position. + if (! m_ZipFile.seekg(WantedPos, ios::beg)) + return streambuf::seekoff(off, dir, nMode); + + m_Pos = WantedPos; + streamoff ToRead = ((m_Size - m_Pos) < BUFFERSIZE) ? (m_Size - m_Pos) : BUFFERSIZE; + + if (ToRead == 0) + return WantedPos; + if (! m_ZipFile.read(m_Buffer, BUFFERSIZE)) + return streambuf::seekoff(off, dir, nMode); + + // Set the buffer at the right position + setg(m_Buffer, m_Buffer, m_Buffer + ToRead); + + return WantedPos; +} + + + +int zbuffer_stored::sync() +{ + return 0; +} + + + +streambuf * zbuffer_stored::setbuf(char * pr, int nLength) +{ + return NULL; +} + + + +////////////////////////////////////////////////////////////////////// +// zbuffer_deflated Member Functions +////////////////////////////////////////////////////////////////////// + +zbuffer_deflated * zbuffer_deflated::open(const char * Filename, streamoff Offset, streamoff Size) +{ + // open main compressed file + m_ZipFile.open(Filename, ios::binary); + if (! m_ZipFile) + return NULL; + + // adjust file position + if (! m_ZipFile.seekg(Offset, ios::beg)) + return NULL; + + // z_stream (NULL) Initialization + m_ZStream.next_in = Z_NULL; + m_ZStream.avail_in = 0; + m_ZStream.total_in = 0; + m_ZStream.next_out = Z_NULL; + m_ZStream.avail_out = 0; + m_ZStream.total_out = 0; + m_ZStream.zalloc = Z_NULL; + m_ZStream.zfree = Z_NULL; + m_ZStream.opaque = Z_NULL; + + // inflate routine Initialization: Window Size = -MAX_WBITS tells there are no header + if (inflateInit2(&m_ZStream, -MAX_WBITS) != Z_OK) + return NULL; + + m_Opened = true; + m_StreamEnd = false; + m_Pos = 0; + m_CompPos = 0; + m_Size = Size; + + return this; +} + + + +zbuffer_deflated * zbuffer_deflated::close() +{ + if (! m_Opened) + return NULL; + else { + m_Opened = false; + m_ZipFile.close(); + + // z_stream unitialization. + if (inflateEnd(&m_ZStream) != Z_OK) + return NULL; + } + + return this; +} + + + +int zbuffer_deflated::overflow(int c) +{ + return EOF; +} + + + +int zbuffer_deflated::underflow() +{ + // Buffer Valid? + if (! m_Opened) + return EOF; + + // Do we really need to refill it? + if (gptr() < egptr()) + return static_cast(* gptr()); + + // Can we refill? + if (m_StreamEnd) + return EOF; + + streamoff ToRead; + streamoff OldPos; + bool BufferRefill = false; + + // Check input (compressed) buffer status + if ((m_ZStream.avail_in == 0) && (m_CompPos < m_Size )) { + ToRead = ((m_Size - m_CompPos) > BUFFERSIZE) ? BUFFERSIZE : (m_Size - m_CompPos); + m_CompPos += ToRead; + + if (! m_ZipFile.read(m_CompBuffer, ToRead)) + return EOF; + + m_ZStream.next_in = reinterpret_cast(m_CompBuffer); + m_ZStream.avail_in = ToRead; + } + + // Ajust start read position in output buffer at the "old" end of buffer + ToRead = m_ZStream.total_out % BUFFERSIZE; + OldPos = m_ZStream.total_out; + + // Check output (decompressed) buffer status + if (m_ZStream.avail_out == 0) { + BufferRefill = true; + m_ZStream.next_out = reinterpret_cast(m_Buffer); + m_ZStream.avail_out = BUFFERSIZE; + } + + // Decompress (Inflate) + int Result = inflate(&m_ZStream, Z_SYNC_FLUSH); + + // Check decompression result + if (Result == Z_STREAM_END) + m_StreamEnd = true; + else if (Result != Z_OK) + return EOF; + + // Set the real position of the beginning of the buffer. + if (m_Pos == streamoff(-1)) + m_Pos = 0; + else + if (BufferRefill) + m_Pos += m_ZStream.total_out - OldPos; + + // Reset buffer pointers. + setg( m_Buffer, // beginning of putback area + m_Buffer + ToRead, // read position + m_Buffer + ((m_ZStream.total_out - 1) % (BUFFERSIZE)) + 1); // end of buffer + + return static_cast(m_Buffer[ToRead]); +} + + + +streampos zbuffer_deflated::seekoff(std::streamoff off, std::ios::seekdir dir, std::ios::openmode nMode) +{ + streamoff WantedPos = 0; + + // Find out the wanted position. + switch (dir) { + case ios_base::cur: + WantedPos = m_Pos + streamoff(gptr() - eback()) + off; + break; + + case ios_base::beg: + WantedPos = off; + break; + + case ios_base::end: + WantedPos = m_Size + off; + break; + + default: + assert(false); + } + + // Is the position valid? + if ((WantedPos < 0) || (WantedPos > m_Size)) + return streambuf::seekoff(off, dir, nMode); // return invalid streamoff + + // Is the position already within the buffer? + if ((WantedPos >= m_Pos) && (WantedPos - m_Pos < egptr() - eback())) { + setg(eback(), eback() + (WantedPos - m_Pos), egptr()); + return WantedPos; + } + + // Found out whether we have to decompress further or if we have to reset the decompression. + if (WantedPos < m_Pos) { + + // Reset the decompression. + if (inflateReset(&m_ZStream) != Z_OK) + return streambuf::seekoff(off, dir, nMode); + + // z_stream Reset + m_ZStream.next_in = Z_NULL; + m_ZStream.avail_in = 0; + m_ZStream.total_in = 0; + m_ZStream.next_out = Z_NULL; + m_ZStream.avail_out = 0; + m_ZStream.total_out = 0; + } + + // call underflow() untill the right position is within the buffer. + while (WantedPos - m_Pos >= egptr() - eback()) { + setg(eback(), egptr(), egptr()); + if (underflow() == EOF) + return streambuf::seekoff(off, dir, nMode); + } + + // now the position is within the buffer. + setg(eback(), eback() + (WantedPos - m_Pos), egptr()); + + return WantedPos; +} + + + +int zbuffer_deflated::sync() +{ + return 0; +} + + + +streambuf * zbuffer_deflated::setbuf(char * pr, int nLength) +{ + return NULL; +} + + + + +} // namespace zip_file_system diff --git a/JGE/src/zipFS/zstream.h b/JGE/src/zipFS/zstream.h new file mode 100644 index 000000000..12768c223 --- /dev/null +++ b/JGE/src/zipFS/zstream.h @@ -0,0 +1,172 @@ +// zstream.h: interface for the zstream classes. +// +////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002 Tanguy Fautré. +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// +// Tanguy Fautré +// softdev@telenet.be +// +////////////////////////////////////////////////////////////////////// +// +// Zip (Input) Stream. +// ******************* +// +// Current version: 1.00 BETA 4 (02/09/2003) +// +// Comment: izstream currently only supports "stored" and "deflated" +// compression methods. +// +// !!!IMPORTANT!!! +// Modify "zstream_zlib.h" for headers and lib dependencies +// on Zlib (http://www.zlib.org) +// +// History: - 1.00 BETA 4 (02/09/2003) - Made zbuffer constructor protected +// - 1.00 BETA 3 (21/02/2003) - Fixed bugs with seekoff() +// - 1.00 BETA 2 (23/12/2002) - Fixed a bug with izstream +// (Added m_ComMethod(-1) in constructor) +// - 1.00 BETA 1 (29/05/2002) - First public release +// +////////////////////////////////////////////////////////////////////// + +#pragma once + + + +#include "zstream_zlib.h" // Zlib dependencies + + + +// Zip File System Namespace +namespace zip_file_system { + + + + +// Base buffer class +class zbuffer : public std::streambuf +{ +public: + virtual ~zbuffer() { } + + virtual zbuffer * open(const char * Filename, std::streamoff Offset, std::streamoff Size) = 0; + virtual zbuffer * close() = 0; + + bool is_open() const { return m_Opened; } + +protected: + zbuffer() : m_Size(0), m_Opened(false) { } + + static const int BUFFERSIZE = 4092; + + std::ifstream m_ZipFile; + std::streamoff m_Pos; + std::streamoff m_Size; + char m_Buffer[BUFFERSIZE]; + bool m_Opened; +}; + + + +// Buffer class for stored compression method. +class zbuffer_stored : public zbuffer +{ +public: + virtual ~zbuffer_stored() { } + + virtual zbuffer_stored * open(const char * Filename, std::streamoff Offset, std::streamoff Size); + virtual zbuffer_stored * close(); + + virtual int overflow(int c = EOF); + virtual int underflow(); + virtual int sync(); + virtual std::streambuf * setbuf(char * pr, int nLength); + virtual std::streampos seekoff(std::streamoff, std::ios::seekdir, std::ios::openmode); + + // Default Implementation is enough + // virtual streampos seekpos(streampos, int); +}; + + + + +// Buffer class for deflated compression method. +class zbuffer_deflated : public zbuffer +{ +public: + + virtual ~zbuffer_deflated() { + if (m_Opened) + inflateEnd(&m_ZStream); + } + + virtual zbuffer_deflated * open(const char * Filename, std::streamoff Offset, std::streamoff Size); + virtual zbuffer_deflated * close(); + + virtual int overflow(int c = EOF); + virtual int underflow(); + virtual int sync(); + virtual std::streambuf * setbuf(char * pr, int nLength); + virtual std::streampos seekoff(std::streamoff, std::ios::seekdir, std::ios::openmode); + + // Default Implementation is enough + // virtual streampos seekpos(streampos, int); + +protected: + z_stream m_ZStream; + std::streamoff m_CompPos; + char m_CompBuffer[BUFFERSIZE]; + bool m_StreamEnd; +}; + + + + +// main istream class for reading zipped files +class izstream : public std::istream +{ +public: + + izstream() : std::istream(NULL), m_CompMethod(-1) { setstate(std::ios::badbit); } + virtual ~izstream() { delete rdbuf(); } + + void open(const char * Filename, std::streamoff Offset, std::streamoff Size, int CompMethod); + void close() { SetCompMethod(-1); } + +protected: + static const int STORED = 0; + static const int DEFLATED = 8; + + zbuffer * GetRightBuffer(int CompMethod) const; + + void SetCompMethod(int CompMethod) { + delete rdbuf(GetRightBuffer(m_CompMethod = CompMethod)); + + if (rdbuf() == NULL) + setstate(std::ios::badbit); + } + + int m_CompMethod; +}; + + + + +} // namespace zip_file_system; + diff --git a/JGE/src/zipFS/zstream_zlib.h b/JGE/src/zipFS/zstream_zlib.h new file mode 100644 index 000000000..4182cc060 --- /dev/null +++ b/JGE/src/zipFS/zstream_zlib.h @@ -0,0 +1,27 @@ +////////////////////////////////////////////////////////////////////// +// +// !!! IMPORTANT !!! +// +// You'll need to modify the following library and header paths to +// correctly link with ZLib. +// +////////////////////////////////////////////////////////////////////// + +#pragma once + + + +#include + + + +// Visual C++ +/* +#if defined _MSC_VER + #if defined _DEBUG + #pragma comment(lib, "../JGE/Dependencies/lib/zlibd.lib") + #else + #pragma comment(lib, "../JGE/Dependencies/lib/zdll.lib") + #endif +#endif +*/ diff --git a/projects/mtg/Android/default.properties b/projects/mtg/Android/default.properties index 9d135cb85..0b9250e02 100644 --- a/projects/mtg/Android/default.properties +++ b/projects/mtg/Android/default.properties @@ -8,4 +8,4 @@ # project structure. # Project target. -target=android-7 +target=android-8 diff --git a/projects/mtg/Android/jni/Android.mk b/projects/mtg/Android/jni/Android.mk index 73b95ee2e..88c31c9cf 100644 --- a/projects/mtg/Android/jni/Android.mk +++ b/projects/mtg/Android/jni/Android.mk @@ -22,6 +22,7 @@ LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/$(SDL_PATH)/include \ $(LOCAL_PATH)/$(MTG_PATH)/include \ $(LOCAL_PATH)/$(JGE_PATH)/include \ + $(LOCAL_PATH)/$(JGE_PATH)/src/zipFS \ $(LOCAL_PATH)/$(BOOST_PATH) \ $(LOCAL_PATH)/$(JPEG_PATH) \ $(LOCAL_PATH)/$(PNG_PATH) \ @@ -163,9 +164,9 @@ LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.cpp \ $(JGE_PATH)/src/hge/hgeparticle.cpp \ $(JGE_PATH)/src/hge/hgerect.cpp \ $(JGE_PATH)/src/hge/hgevector.cpp \ - $(JGE_PATH)/src/unzip/ioapi.c \ - $(JGE_PATH)/src/unzip/mztools.c \ - $(JGE_PATH)/src/unzip/unzip.c \ + $(JGE_PATH)/src/zipFS/zfsystem.cpp \ + $(JGE_PATH)/src/zipFS/ziphdr.cpp \ + $(JGE_PATH)/src/zipFS/zstream.cpp \ $(JGE_PATH)/src/pc/JSfx.cpp \ $(JGE_PATH)/src/pc/JGfx.cpp \ $(JGE_PATH)/src/JNetwork.cpp \ diff --git a/projects/mtg/Makefile b/projects/mtg/Makefile index b1e0bd7e1..4725bea37 100644 --- a/projects/mtg/Makefile +++ b/projects/mtg/Makefile @@ -35,7 +35,7 @@ PSP_EBOOT_ICON = icon.png #PSP_EBOOT_ICON1 = icon1.pmf PSP_EBOOT_UNKPNG = pic0.png PSP_EBOOT_PIC1 = pic1.png -INCDIR = ../../JGE/include ../../JGE/include/psp ../../JGE/include/psp/freetype2 ../../JGE/src ../../projects/mtg/include ../../Boost +INCDIR = ../../JGE/include ../../JGE/src/zipFS ../../JGE/include/psp ../../JGE/include/psp/freetype2 ../../JGE/src ../../projects/mtg/include ../../Boost LIBDIR = ../../JGE/lib/psp CFLAGS = -O2 -G0 -DPSPFW3XX -DDEVHOOK -DUSE_PRECOMPILED_HEADERS=1 -DPSP else @@ -56,7 +56,7 @@ CXXFLAGS += $(CFLAGS) LDFLAGS += $(LIBS) -debug: CXXFLAGS += -ggdb3 -D_DEBUG -DDEBUG +debug: CXXFLAGS += -ggdb3 -D_DEBUG -DDEBUG -DDEBUG_CACHE log: CXXFLAGS += -DDOLOG diff --git a/projects/mtg/include/CardPrimitive.h b/projects/mtg/include/CardPrimitive.h index 37a969460..cf6d197f1 100644 --- a/projects/mtg/include/CardPrimitive.h +++ b/projects/mtg/include/CardPrimitive.h @@ -33,7 +33,7 @@ public: CastRestrictions * clone() const { - return NEW CastRestrictions(*this); + return NEW CastRestrictions(*this); }; }; diff --git a/projects/mtg/include/GameApp.h b/projects/mtg/include/GameApp.h index 0c1245ddc..b36a7a753 100644 --- a/projects/mtg/include/GameApp.h +++ b/projects/mtg/include/GameApp.h @@ -96,7 +96,7 @@ public: void DoTransition(int trans, int tostate, float dur = -1, bool animonly = false); void DoAnimation(int trans, float dur = -1); static hgeParticleSystem * Particles[6]; - static int HasMusic; + static bool HasMusic; static string systemError; static JMusic* music; static string currentMusicFile; diff --git a/projects/mtg/include/GameOptions.h b/projects/mtg/include/GameOptions.h index 805231ac3..2b4d7a9d1 100644 --- a/projects/mtg/include/GameOptions.h +++ b/projects/mtg/include/GameOptions.h @@ -402,7 +402,7 @@ public: //These return a filepath accurate to the current mode/profile/theme, and can //optionally fallback to a file within a certain directory. //The sanity=false option returns the adjusted path even if the file doesn't exist. - string profileFile(string filename="", string fallback="", bool sanity=false,bool relative=false); + string profileFile(string filename="", string fallback="", bool sanity=false); void reloadProfile(); //Reloads profile using current options[ACTIVE_PROFILE] void checkProfile(); //Confirms that a profile is loaded and contains a collection. diff --git a/projects/mtg/include/GameStateMenu.h b/projects/mtg/include/GameStateMenu.h index 1c6a09132..4a2d6b713 100644 --- a/projects/mtg/include/GameStateMenu.h +++ b/projects/mtg/include/GameStateMenu.h @@ -26,14 +26,15 @@ private: char nbcardsStr[400]; vector langs; vector primitives; + + size_t mCurrentSetFolderIndex; + string mCurrentSetName; + string mCurrentSetFileName; + vector setFolders; + string wallpaper; int primitivesLoadCounter; - DIR *mDip; - struct dirent *mDit; - char mCurrentSetName[32]; - char mCurrentSetFileName[512]; - int mReadConf; float timeIndex; void fillScroller(); @@ -61,8 +62,7 @@ public: virtual void Render(); virtual void ButtonPressed(int controllerId, int controlId); - int nextDirectory(const char * root, const char * file); // Retrieves the next directory to have matching file - void resetDirectory(); + int nextSetFolder(const string & root, const string & file); // Retrieves the next directory to have matching file void createUsersFirstDeck(int setId); virtual ostream& toString(ostream& out) const; diff --git a/projects/mtg/include/MTGDeck.h b/projects/mtg/include/MTGDeck.h index 77625f610..0ce182d11 100644 --- a/projects/mtg/include/MTGDeck.h +++ b/projects/mtg/include/MTGDeck.h @@ -127,8 +127,6 @@ public: int totalCards(); int randomCardId(); - static void loadPrimitives(const char *root_directory); - static void loadSets(const char *root_directory, const char* filename); static void loadInstance(); static void unloadAll(); static inline MTGAllCards* getInstance() { return instance; }; diff --git a/projects/mtg/include/WResourceManager.h b/projects/mtg/include/WResourceManager.h index 48549add1..a1f6f82fd 100644 --- a/projects/mtg/include/WResourceManager.h +++ b/projects/mtg/include/WResourceManager.h @@ -101,8 +101,8 @@ public: virtual string cardFile(const string& filename) = 0; virtual string musicFile(const string& filename) = 0; virtual string sfxFile(const string& filename) = 0; - virtual int fileOK(const string&, bool relative = false) = 0; - virtual int dirOK(const string& dirname) = 0; + virtual bool fileOK(const string&) = 0; + virtual bool dirOK(const string& dirname) = 0; //For backwards compatibility with JWResourceManager. Avoid using these, they're not optimal. virtual int CreateTexture(const string &textureName) = 0; diff --git a/projects/mtg/include/WResourceManagerImpl.h b/projects/mtg/include/WResourceManagerImpl.h index 609eab793..d06817d81 100644 --- a/projects/mtg/include/WResourceManagerImpl.h +++ b/projects/mtg/include/WResourceManagerImpl.h @@ -173,8 +173,8 @@ public: string cardFile(const string& filename); string musicFile(const string& filename); string sfxFile(const string& filename); - int fileOK(const string&, bool relative = false); - int dirOK(const string& dirname); + bool fileOK(const string&); + bool dirOK(const string& dirname); //For backwards compatibility with JResourceManager. Avoid using these, they're not optimal. int CreateTexture(const string &textureName); diff --git a/projects/mtg/include/utils.h b/projects/mtg/include/utils.h index 17deae7a6..3c142866e 100644 --- a/projects/mtg/include/utils.h +++ b/projects/mtg/include/utils.h @@ -29,46 +29,6 @@ #include "DebugRoutines.h" -// enable this define to collect statistics on how many times an ifstream is created for a given file. -//#define TRACK_FILE_USAGE_STATS - -namespace wagic -{ - -#ifdef TRACK_FILE_USAGE_STATS - class ifstream : public std::ifstream - { - public: - explicit ifstream(const char *inFilename, ios_base::openmode inMode = ios_base::in) : - std::ifstream(inFilename, inMode) - { - sFileMap[std::string(inFilename)] += 1; - DebugTrace("ifstream opened on file: " << inFilename); - } - - static void Dump() - { - DebugTrace("-------------------"); - DebugTrace("File Usage Statistics" << std::endl); - std::map::const_iterator iter = sFileMap.begin(); - for (; iter != sFileMap.end(); ++iter) - { - DebugTrace(iter->first << " -- " << iter->second); - } - - DebugTrace("End File Usage Statistics"); - DebugTrace("-------------------"); - } - - private: - static std::map sFileMap; - }; - -#else - typedef std::ifstream ifstream; -#endif - -} //namespace wagic using std::string; @@ -105,7 +65,6 @@ unsigned long hash_djb2(const char *str); int loadRandValues(string s); int filesize(const char * filename); -int fileExists(const char * filename); int WRand(); #ifdef LINUX @@ -135,6 +94,9 @@ u32 ramAvailable(void); #define MAKEDIR(name) mkdir(name, 0777) #endif -bool FileExists(const string& strFilename); +bool fileExists(const char * filename); +bool FileExists(const string & filename); + +std::string buildFilePath(const vector & folders, const string & filename); #endif diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index 7c053a69c..40b200762 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -1322,7 +1322,7 @@ AIStats * AIPlayer::getStats() if (!stats) { char statFile[512]; - sprintf(statFile, JGE_GET_RES("ai/baka/stats/%s.stats").c_str(), opponent()->deckFileSmall.c_str()); + sprintf(statFile, "ai/baka/stats/%s.stats", opponent()->deckFileSmall.c_str()); stats = NEW AIStats(this, statFile); } return stats; @@ -1352,12 +1352,10 @@ AIPlayer * AIPlayerFactory::createAIPlayer(MTGAllCards * collection, Player * op { found = 0; char buffer[512]; - sprintf(buffer, JGE_GET_RES("ai/baka/deck%i.txt").c_str(), nbdecks + 1); - wagic::ifstream file(buffer); - if (file) + sprintf(buffer, "ai/baka/deck%i.txt", nbdecks + 1); + if (FileExists(buffer)) { found = 1; - file.close(); nbdecks++; } } @@ -1365,7 +1363,7 @@ AIPlayer * AIPlayerFactory::createAIPlayer(MTGAllCards * collection, Player * op return NULL; deckid = 1 + WRand() % (nbdecks); } - sprintf(deckFile, JGE_GET_RES("ai/baka/deck%i.txt").c_str(), deckid); + sprintf(deckFile, "ai/baka/deck%i.txt", deckid); DeckMetaData *aiMeta = DeckManager::GetInstance()->getDeckMetaDataByFilename( deckFile, true); avatarFilename = aiMeta->getAvatarFilename(); sprintf(deckFileSmall, "ai_baka_deck%i", deckid); diff --git a/projects/mtg/src/AIStats.cpp b/projects/mtg/src/AIStats.cpp index 22ac86301..42cd11b1f 100644 --- a/projects/mtg/src/AIStats.cpp +++ b/projects/mtg/src/AIStats.cpp @@ -146,34 +146,33 @@ AIStat * AIStats::find(MTGCard * source) void AIStats::load(char * filename) { - wagic::ifstream file(filename); - std::string s; - - if (file) + std::string contents; + if (JFileSystem::GetInstance()->readIntoString(filename, contents)) { - while (std::getline(file, s)) + std::stringstream stream(contents); + std::string s; + while (std::getline(stream, s)) { int cardid = atoi(s.c_str()); - std::getline(file, s); + std::getline(stream, s); int value = atoi(s.c_str()); - std::getline(file, s); + std::getline(stream, s); bool direct = atoi(s.c_str()) > 0; AIStat * stat = NEW AIStat(cardid, value, 1, direct); stats.push_back(stat); } - file.close(); } else { - //TODO Error management + DebugTrace("FATAL: AIStats.cpp:load : can't load" << filename); } } void AIStats::save() { - std::ofstream file(filename.c_str()); - char writer[128]; - if (file) + std::ofstream file; + if (JFileSystem::GetInstance()->openForWrite(file, filename)) { + char writer[128]; list::iterator it; for (it = stats.begin(); it != stats.end(); it++) { diff --git a/projects/mtg/src/Credits.cpp b/projects/mtg/src/Credits.cpp index 486c0a889..8308a9f07 100644 --- a/projects/mtg/src/Credits.cpp +++ b/projects/mtg/src/Credits.cpp @@ -336,7 +336,7 @@ int Credits::isDifficultyUnlocked(DeckStats * stats) found = 0; char buffer[512]; char aiSmallDeckName[512]; - sprintf(buffer, JGE_GET_RES("ai/baka/deck%i.txt").c_str(), nbAIDecks + 1); + sprintf(buffer, "ai/baka/deck%i.txt", nbAIDecks + 1); if (fileExists(buffer)) { found = 1; @@ -486,12 +486,10 @@ int Credits::IsMoreAIDecksUnlocked(DeckStats * stats) { { found = 0; char buffer[512]; - sprintf(buffer, JGE_GET_RES("ai/baka/deck%i.txt").c_str(), nbdecks + 1); - wagic::ifstream file(buffer); - if (file) + sprintf(buffer, "ai/baka/deck%i.txt", nbdecks + 1); + if (JFileSystem::GetInstance()->FileExists(buffer)) { found = 1; - file.close(); nbdecks++; if (nbdecks > currentlyUnlocked) return 1; diff --git a/projects/mtg/src/DeckStats.cpp b/projects/mtg/src/DeckStats.cpp index f3d1c3d76..d56abe8df 100644 --- a/projects/mtg/src/DeckStats.cpp +++ b/projects/mtg/src/DeckStats.cpp @@ -114,11 +114,12 @@ void DeckStats::load(const std::string& filename) { return; } - wagic::ifstream file(filename.c_str()); - std::string s; - if (file) + std::string contents; + if (JFileSystem::GetInstance()->readIntoString(filename, contents)) { + std::stringstream stream(contents); + std::string s; // get the associated player deck file: int deckId = atoi(filename.substr(filename.find("_deck") + 5, filename.find(".txt")).c_str()); char buffer[512]; @@ -128,31 +129,30 @@ void DeckStats::load(const std::string& filename) if (!playerDeckMetaData) { DebugTrace("DeckStats.cpp:CONSISTENCY ERROR: DeckStats are set, but no deck meta data"); - file.close(); return; } // check if this player deck has already been profiled for manacolors - char next = file.peek(); + char next = stream.peek(); string manaColorIndex = ""; if ( next == 'M') { - std::getline(file, s ); + std::getline(stream, s ); manaColorIndex = s.substr( s.find(":") + 1); playerDeckMetaData->setColorIndex( manaColorIndex ); } - while (std::getline(file, s)) + while (std::getline(stream, s)) { string deckfile = s; - std::getline(file, s); + std::getline(stream, s); int games = atoi(s.c_str()); - std::getline(file, s); + std::getline(stream, s); int victories = atoi(s.c_str()); - next = file.peek(); + next = stream.peek(); if ( next == 'M') { - std::getline(file, s ); + std::getline(stream, s ); manaColorIndex = s.substr( s.find(":") + 1); } if ( masterDeckStats[filename].find(deckfile) != masterDeckStats[filename].end()) @@ -162,16 +162,15 @@ void DeckStats::load(const std::string& filename) DeckStat * newDeckStat = NEW DeckStat(games, victories, manaColorIndex); (masterDeckStats[filename])[deckfile] = newDeckStat; } - file.close(); } } void DeckStats::save(const std::string& filename) { - std::ofstream file(filename.c_str()); - char writer[512]; - if (file) + std::ofstream file; + if (JFileSystem::GetInstance()->openForWrite(file, filename)) { + char writer[512]; map stats = masterDeckStats[currentDeck]; map::iterator it; string manaColorIndex = ""; @@ -327,7 +326,7 @@ void StatsWrapper::initStatistics(string deckstats) char smallDeckName[512]; ostringstream oss; oss << "deck" << (nbDecks + 1); - string bakaDir = JGE_GET_RES("/ai/baka"); + string bakaDir = "ai/baka/"; string deckFilename = oss.str(); sprintf(buffer, "%s/%s.txt", bakaDir.c_str(), deckFilename.c_str()); if (fileExists(buffer)) diff --git a/projects/mtg/src/GameApp.cpp b/projects/mtg/src/GameApp.cpp index 9eff90f66..abf58b204 100644 --- a/projects/mtg/src/GameApp.cpp +++ b/projects/mtg/src/GameApp.cpp @@ -28,11 +28,12 @@ #include "WFilter.h" #include "Rules.h" #include "ModRules.h" +#include "JFileSystem.h" #define DEFAULT_DURATION .25 int GameApp::players[] = { 0, 0 }; -int GameApp::HasMusic = 1; +bool GameApp::HasMusic = true; JMusic * GameApp::music = NULL; string GameApp::currentMusicFile = ""; string GameApp::systemError = ""; @@ -95,28 +96,22 @@ void GameApp::Create() LOG("starting Game"); WResourceManager::Instance()->ResetCacheLimits(); - //Find the Res folder - wagic::ifstream mfile("Res.txt"); - string resPath; - if (mfile) + + JFileSystem::init("User/", "Res/"); + + // Create User Folders (for write access) if they don't exist { - bool found = false; - while (!found && std::getline(mfile, resPath)) + const char* folders[] = { "ai", "ai/baka", "ai/baka/stats", "campaigns", "graphics", "lang", "packs", "player", "player/stats", "profiles", "rules", "sets", "settings", "sound", "sound/sfx", "themes"}; + string userRoot = JFileSystem::GetInstance()->GetUserRoot(); + MAKEDIR(userRoot.c_str()); + + for (size_t i = 0; i < sizeof(folders)/sizeof(folders[0]); ++i) { - if (resPath[resPath.size() - 1] == '\r') - resPath.erase(resPath.size() - 1); //Handle DOS files - string testfile = resPath; - testfile.append("graphics/simon.dat"); - if (fileExists(testfile.c_str())) - { - JFileSystem::GetInstance()->SetResourceRoot(trim(resPath)); - found = true; - } + string current(folders[i]); + string folder = userRoot + current; + MAKEDIR(folder.c_str()); } - mfile.close(); } - LOG("Res Root:"); - LOG(JFileSystem::GetInstance()->GetResourceRoot().c_str()); //Load Mod Rules before everything else gModRules.load("rules/modrules.xml"); @@ -130,19 +125,8 @@ void GameApp::Create() LOG("Checking for music files"); //Test for Music files presence - string filepath = JGE_GET_RES(WResourceManager::Instance()->musicFile("Track0.mp3")); - wagic::ifstream file(filepath.c_str()); - if (file) - file.close(); - else - HasMusic = 0; - - filepath = JGE_GET_RES(WResourceManager::Instance()->musicFile("Track1.mp3")); - wagic::ifstream file2(filepath.c_str()); - if (file2) - file2.close(); - else - HasMusic = 0; + JFileSystem * jfs = JFileSystem::GetInstance(); + HasMusic = jfs->FileExists(WResourceManager::Instance()->musicFile("Track0.mp3")) && jfs->FileExists(WResourceManager::Instance()->musicFile("Track1.mp3")); LOG("Loading Textures"); LOG("--Loading menuicons.png"); diff --git a/projects/mtg/src/GameOptions.cpp b/projects/mtg/src/GameOptions.cpp index 0e6c23d9a..c35a7cbf4 100644 --- a/projects/mtg/src/GameOptions.cpp +++ b/projects/mtg/src/GameOptions.cpp @@ -317,12 +317,13 @@ GameOptions::GameOptions(string filename) int GameOptions::load() { - wagic::ifstream file(mFilename.c_str()); - std::string s; - - if (file) + std::string contents; + if (JFileSystem::GetInstance()->readIntoString(mFilename, contents)) { - while (std::getline(file, s)) + std::stringstream stream(contents); + string s; + + while (std::getline(stream, s)) { if (!s.size()) continue; @@ -340,7 +341,6 @@ int GameOptions::load() (*this)[id].read(val); } - file.close(); } // (PSY) Make sure that cheatmode is switched off for ineligible profiles: if (options[Options::ACTIVE_PROFILE].str != SECRET_PROFILE) @@ -369,8 +369,8 @@ int GameOptions::save() (*this)[Options::CHEATMODEAIDECK].number = 0; } - std::ofstream file(mFilename.c_str()); - if (file) + std::ofstream file; + if (JFileSystem::GetInstance()->openForWrite(file, mFilename)) { for (int x = 0; x < (int) values.size(); x++) { @@ -640,14 +640,15 @@ int GameSettings::save() if (profileOptions) { - //Force our directories to exist. - MAKEDIR(JGE_GET_RES("profiles").c_str()); - string temp = profileFile("", "", false, false); + //Create a temp directory + // Erwan 2011/08/14: what does this really do? temp is never used. + /* + string temp = profileFile("", "", false); MAKEDIR(temp.c_str()); temp += "/stats"; MAKEDIR(temp.c_str()); temp = profileFile(PLAYER_SETTINGS, "", false); - + */ profileOptions->save(); } @@ -656,7 +657,7 @@ int GameSettings::save() return 1; } -string GameSettings::profileFile(string filename, string fallback, bool sanity, bool relative) +string GameSettings::profileFile(string filename, string fallback, bool sanity) { char buf[512]; string profile = (*this)[Options::ACTIVE_PROFILE].str; @@ -666,30 +667,27 @@ string GameSettings::profileFile(string filename, string fallback, bool sanity, //No file, return root of profile directory if (filename == "") { - sprintf(buf, "%sprofiles/%s", (relative ? "" : JGE_GET_RES("").c_str()), profile.c_str()); + sprintf(buf, "profiles/%s", profile.c_str()); return buf; } //Return file - sprintf(buf, JGE_GET_RES("profiles/%s/%s").c_str(), profile.c_str(), filename.c_str()); + sprintf(buf, "profiles/%s/%s", profile.c_str(), filename.c_str()); if (fileExists(buf)) { - if (relative) - sprintf(buf, "profiles/%s/%s", profile.c_str(), filename.c_str()); return buf; } } else { //Use the default directory. - sprintf(buf, "%splayer%s%s", (relative ? "" : JGE_GET_RES("").c_str()), (filename == "" ? "" : "/"), filename.c_str()); + sprintf(buf, "player%s%s", (filename == "" ? "" : "/"), filename.c_str()); return buf; } //Don't fallback if sanity checking is disabled.. if (!sanity) { - sprintf(buf, "%sprofiles/%s%s%s", (relative ? "" : JGE_GET_RES("").c_str()), profile.c_str(), (filename == "" ? "" : "/"), - filename.c_str()); + sprintf(buf, "profiles/%s%s%s", profile.c_str(), (filename == "" ? "" : "/"), filename.c_str()); return buf; } @@ -697,8 +695,7 @@ string GameSettings::profileFile(string filename, string fallback, bool sanity, if (fallback == "") return ""; - sprintf(buf, "%s%s%s%s", (relative ? "" : JGE_GET_RES("").c_str()), fallback.c_str(), (filename == "" ? "" : "/"), - filename.c_str()); + sprintf(buf, "%s%s%s", fallback.c_str(), (filename == "" ? "" : "/"), filename.c_str()); return buf; } @@ -711,7 +708,7 @@ void GameSettings::reloadProfile() void GameSettings::checkProfile() { if (!globalOptions) - globalOptions = NEW GameOptions(JGE_GET_RES(GLOBAL_SETTINGS)); + globalOptions = NEW GameOptions(GLOBAL_SETTINGS); //If it doesn't exist, load current profile. if (!profileOptions) @@ -744,13 +741,13 @@ void GameSettings::checkProfile() if (profileOptions) { //Force our directories to exist. - MAKEDIR(JGE_GET_RES("profiles").c_str()); - string temp = profileFile("", "", false, false); + /* + string temp = profileFile("", "", false); MAKEDIR(temp.c_str()); temp += "/stats"; MAKEDIR(temp.c_str()); temp = profileFile(PLAYER_SETTINGS, "", false); - + */ profileOptions->save(); } } diff --git a/projects/mtg/src/GameStateDeckViewer.cpp b/projects/mtg/src/GameStateDeckViewer.cpp index 2b4d46a58..2d7c67f3c 100644 --- a/projects/mtg/src/GameStateDeckViewer.cpp +++ b/projects/mtg/src/GameStateDeckViewer.cpp @@ -218,7 +218,7 @@ void GameStateDeckViewer::Start() lastPos = 0; lastTotal = 0; - pricelist = NEW PriceList(JGE_GET_RES("settings/prices.dat").c_str(), MTGCollection()); + pricelist = NEW PriceList("settings/prices.dat", MTGCollection()); playerdata = NEW PlayerData(MTGCollection()); myCollection = NEW DeckDataWrapper(playerdata->collection); myCollection->Sort(WSrcCards::SORT_ALPHA); @@ -321,7 +321,7 @@ void GameStateDeckViewer::saveDeck() void GameStateDeckViewer::saveAsAIDeck(string deckName) { - vector aiDecks = GameState::BuildDeckList(JGE_GET_RES("ai/baka"), "ai_baka", NULL); + vector aiDecks = GameState::BuildDeckList("ai/baka", "ai_baka", NULL); int nbAiDecks = aiDecks.size() + 1; aiDecks.clear(); @@ -335,7 +335,7 @@ void GameStateDeckViewer::saveAsAIDeck(string deckName) else oss << myDeck->parent->meta_desc; string deckDesc = oss.str(); - string filepath = JGE_GET_RES("ai/baka/"); + string filepath = "ai/baka/"; filepath.append(defaultAiDeckName).append(".txt"); DebugTrace("saving AI deck " << filepath); myDeck->save(filepath, true, deckName, deckDesc); @@ -1496,7 +1496,7 @@ int GameStateDeckViewer::loadDeck(int deckid) SAFE_DELETE(myDeck->parent); SAFE_DELETE(myDeck); } - myDeck = NEW DeckDataWrapper(NEW MTGDeck(options.profileFile(deckname, "", false, false).c_str(), MTGCollection())); + myDeck = NEW DeckDataWrapper(NEW MTGDeck(options.profileFile(deckname, "", false).c_str(), MTGCollection())); // Check whether the cards in the deck are actually available in the player's collection: int cheatmode = options[Options::CHEATMODE].number; diff --git a/projects/mtg/src/GameStateDuel.cpp b/projects/mtg/src/GameStateDuel.cpp index bf7fd4410..3dc1f4786 100644 --- a/projects/mtg/src/GameStateDuel.cpp +++ b/projects/mtg/src/GameStateDuel.cpp @@ -102,7 +102,7 @@ void GameStateDuel::Start() #ifdef TESTSUITE SAFE_DELETE(testSuite); - testSuite = NEW TestSuite(JGE_GET_RES("test/_tests.txt").c_str(),MTGCollection()); + testSuite = NEW TestSuite("test/_tests.txt",MTGCollection()); #endif mGamePhase = DUEL_STATE_CHOOSE_DECK1; @@ -156,7 +156,7 @@ void GameStateDuel::Start() deckmenu->Add(MENUITEM_NEW_DECK, "Create your Deck!", desc); } premadeDeck = true; - fillDeckMenu(deckmenu, JGE_GET_RES("player/premade")); + fillDeckMenu(deckmenu, "player/premade"); } else if (gModRules.general.hasDeckEditor()) { @@ -181,7 +181,7 @@ void GameStateDuel::loadPlayer(int playerId, int decknb, bool isAI, bool isNetwo { char deckFile[255]; if (premadeDeck) - sprintf(deckFile, JGE_GET_RES("player/premade/deck%i.txt").c_str(), decknb); + sprintf(deckFile, "player/premade/deck%i.txt", decknb); else sprintf(deckFile, "%s/deck%i.txt", options.profileFile().c_str(), decknb); char deckFileSmall[255]; @@ -286,15 +286,7 @@ void GameStateDuel::End() //TODO Move This to utils or ResourceManager. Don't we have more generic functions that can do that? bool GameStateDuel::MusicExist(string FileName) { - string filepath = JGE_GET_RES(WResourceManager::Instance()->musicFile(FileName)); - wagic::ifstream file(filepath.c_str()); - if (file) - { - file.close(); - return true; - } - else - return false; + return FileExists(WResourceManager::Instance()->musicFile(FileName)); } void GameStateDuel::ConstructOpponentMenu() @@ -309,7 +301,7 @@ void GameStateDuel::ConstructOpponentMenu() DeckManager * deckManager = DeckManager::GetInstance(); vector opponentDeckList; int nbUnlockedDecks = options[Options::CHEATMODEAIDECK].number ? 1000 : options[Options::AIDECKS_UNLOCKED].number; - opponentDeckList = fillDeckMenu(opponentMenu, JGE_GET_RES("ai/baka"), "ai_baka", mPlayers[0], nbUnlockedDecks); + opponentDeckList = fillDeckMenu(opponentMenu, "ai/baka", "ai_baka", mPlayers[0], nbUnlockedDecks); deckManager->updateMetaDataList(&opponentDeckList, true); opponentMenu->Add(MENUITEM_CANCEL, "Cancel", _("Choose a different player deck").c_str()); opponentDeckList.clear(); diff --git a/projects/mtg/src/GameStateMenu.cpp b/projects/mtg/src/GameStateMenu.cpp index 923ada52c..369f4a3b3 100644 --- a/projects/mtg/src/GameStateMenu.cpp +++ b/projects/mtg/src/GameStateMenu.cpp @@ -71,10 +71,8 @@ GameStateMenu::~GameStateMenu() void GameStateMenu::Create() { - mDip = NULL; mGuiController = NULL; mReadConf = 0; - mCurrentSetName[0] = 0; //load all the icon images. Menu icons are managed, so we can do this here. int n = 0; @@ -97,8 +95,10 @@ void GameStateMenu::Create() string lang = options[Options::LANG].str; if (lang.size()) { - lang = JGE_GET_RES("lang/") + lang + ".txt"; - if (fileExists(lang.c_str())) + string langpath = "lang/"; + langpath.append(lang); + langpath.append(".txt"); + if (JFileSystem::GetInstance()->FileExists(langpath)) langChosen = true; } if (!langChosen) @@ -110,6 +110,8 @@ void GameStateMenu::Create() splashTex = NULL; + JFileSystem::GetInstance()->scanfolder("sets/", setFolders); + mCurrentSetFolderIndex = 0; } void GameStateMenu::Destroy() @@ -265,35 +267,27 @@ void GameStateMenu::fillScroller() scrollerSet = 1; scroller->setRandom(); } -void GameStateMenu::resetDirectory() + +int GameStateMenu::nextSetFolder(const string & root, const string & file) { - if (mDip != NULL) + bool found = false; + while (!found && (mCurrentSetFolderIndex < setFolders.size())) { - closedir(mDip); - mDip = NULL; - } -} -int GameStateMenu::nextDirectory(const char * root, const char * file) -{ - int found = 0; - if (!mDip) - { - mDip = opendir(root); + vector folders; + folders.push_back(root); + folders.push_back(setFolders[mCurrentSetFolderIndex]); + mCurrentSetFileName = buildFilePath(folders, file); + + if (JFileSystem::GetInstance()->FileExists(mCurrentSetFileName)) + { + mCurrentSetName = setFolders[mCurrentSetFolderIndex]; + if (mCurrentSetName.length() && (mCurrentSetName[mCurrentSetName.length() - 1] == '/')) + mCurrentSetName.resize(mCurrentSetName.length() - 1); + found = true; + } + mCurrentSetFolderIndex++; } - while (!found && (mDit = readdir(mDip))) - { - sprintf(mCurrentSetFileName, "%s/%s/%s", root, mDit->d_name, file); - wagic::ifstream file(mCurrentSetFileName); - if (file) - { - sprintf(mCurrentSetName, "%s", mDit->d_name); - file.close(); - found = 1; - } - } - if (!found) - resetDirectory(); return found; } @@ -311,9 +305,8 @@ string GameStateMenu::loadRandomWallpaper() return wallpaper; vector wallpapers; - wagic::ifstream file(JGE_GET_RES("graphics/wallpapers.txt").c_str()); - - if (!file) + izfstream file; + if (! JFileSystem::GetInstance()->openForRead(file, "graphics/wallpapers.txt")) return wallpaper; string s; @@ -325,6 +318,7 @@ string GameStateMenu::loadRandomWallpaper() s.erase(s.size() - 1); //Handle DOS files wallpapers.push_back(s); } + file.close(); int rnd = rand() % (wallpapers.size()); wallpaper = wallpapers[rnd]; @@ -359,66 +353,60 @@ void GameStateMenu::loadLangMenu() subMenuController = NEW SimpleMenu(MENU_LANGUAGE_SELECTION, this, Fonts::MENU_FONT, 150, 60); if (!subMenuController) return; - resetDirectory(); - if (!mDip) - { - mDip = opendir(JGE_GET_RES("lang").c_str()); - } - while ((mDit = readdir(mDip))) + vector langFiles = JFileSystem::GetInstance()->scanfolder("lang/"); + for (size_t i = 0; i < langFiles.size(); ++i) { - string filename = JGE_GET_RES("lang/"); - filename += mDit->d_name; - wagic::ifstream file(filename.c_str()); + izfstream file; + string filePath = "lang/"; + filePath.append(langFiles[i]); + if (! JFileSystem::GetInstance()->openForRead(file, filePath)) + continue; + string s; string lang; - if (file) + + if (std::getline(file, s)) { - if (std::getline(file, s)) - { - lang = getLang(s); - } - file.close(); + lang = getLang(s); } + + file.close(); + if (lang.size()) { langChoices = true; - string filen = mDit->d_name; + string filen = langFiles[i]; langs.push_back(filen.substr(0, filen.size() - 4)); subMenuController->Add(langs.size(), lang.c_str()); } } - resetDirectory(); LOG("GameStateMenu::loadLangMenu - Done"); } void GameStateMenu::listPrimitives() { LOG("GameStateMenu::listPrimitives"); - resetDirectory(); - if (!mDip) - { - mDip = opendir(JGE_GET_RES("sets/primitives/").c_str()); - } + vector primitiveFiles = JFileSystem::GetInstance()->scanfolder("sets/primitives/"); - if (!mDip) + if (!primitiveFiles.size()) { DebugTrace("GameStateMenu.cpp:WARNING:Primitives folder is missing"); primitivesLoadCounter = 0; return; } - while ((mDit = readdir(mDip))) + for (size_t i = 0; i < primitiveFiles.size(); ++i) { - string filename = JGE_GET_RES("sets/primitives/"); - filename += mDit->d_name; - wagic::ifstream file(filename.c_str()); - if (!file) + string filename = "sets/primitives/"; + filename.append(primitiveFiles[i]); + izfstream file; + if (! JFileSystem::GetInstance()->openForRead(file, filename)) continue; + file.close(); primitives.push_back(filename); } - resetDirectory(); primitivesLoadCounter = 0; LOG("GameStateMenu::listPrimitives - Done"); } @@ -513,13 +501,13 @@ void GameStateMenu::Update(float dt) primitivesLoadCounter = primitives.size() + 1; if (mReadConf) { - MTGCollection()->load(mCurrentSetFileName, mCurrentSetName); + MTGCollection()->load(mCurrentSetFileName.c_str(), mCurrentSetName.c_str()); } else { mReadConf = 1; } - if (!nextDirectory(JGE_GET_RES("sets/").c_str(), "_cards.dat")) + if (!nextSetFolder("sets/", "_cards.dat")) { //Remove temporary translations Translator::GetInstance()->tempValues.clear(); @@ -537,10 +525,8 @@ void GameStateMenu::Update(float dt) splashTex = NULL; //check for deleted collection / first-timer - wagic::ifstream file(options.profileFile(PLAYER_COLLECTION).c_str()); - if (file) + if (JFileSystem::GetInstance()->FileExists(options.profileFile(PLAYER_COLLECTION))) { - file.close(); currentState = MENU_STATE_MAJOR_MAINMENU; } else @@ -551,7 +537,6 @@ void GameStateMenu::Update(float dt) //Reload list of unlocked sets, now that we know about the sets. options.reloadProfile(); genNbCardsStr(); - resetDirectory(); //All major things have been loaded, resize the cache to use it as efficiently as possible WResourceManager::Instance()->ResetCacheLimits(); } @@ -736,9 +721,9 @@ void GameStateMenu::Render() } char text[512]; - if (mCurrentSetName[0]) + if (mCurrentSetName.size()) { - sprintf(text, _("LOADING SET: %s").c_str(), mCurrentSetName); + sprintf(text, _("LOADING SET: %s").c_str(), mCurrentSetName.c_str()); } else { @@ -929,8 +914,6 @@ ostream& GameStateMenu::toString(ostream& out) const << " ; currentState : " << currentState << " ; mVolume : " << mVolume << " ; nbcardsStr : " << nbcardsStr - << " ; mDip : " << mDip - << " ; mDit : " << mDit << " ; mCurrentSetName : " << mCurrentSetName << " ; mCurrentSetFileName : " << mCurrentSetFileName << " ; mReadConf : " << mReadConf diff --git a/projects/mtg/src/GameStateShop.cpp b/projects/mtg/src/GameStateShop.cpp index 4e1da3592..f8a1e0da1 100644 --- a/projects/mtg/src/GameStateShop.cpp +++ b/projects/mtg/src/GameStateShop.cpp @@ -106,7 +106,7 @@ void GameStateShop::Start() MTGAllCards * ac = MTGCollection(); playerdata = NEW PlayerData(ac); myCollection = NEW DeckDataWrapper(playerdata->collection); - pricelist = NEW PriceList(JGE_GET_RES("settings/prices.dat").c_str(), ac); + pricelist = NEW PriceList("settings/prices.dat", ac); for (int i = 0; i < SHOP_SLOTS; i++) { WGuiCardDistort * dist; diff --git a/projects/mtg/src/GameStateStory.cpp b/projects/mtg/src/GameStateStory.cpp index bc4863191..d641a086f 100644 --- a/projects/mtg/src/GameStateStory.cpp +++ b/projects/mtg/src/GameStateStory.cpp @@ -22,24 +22,17 @@ void GameStateStory::loadStoriesMenu(const char * root) { SAFE_DELETE(menu); stories.clear(); - DIR *mDip; - struct dirent *mDit; + vectorsubFolders = JFileSystem::GetInstance()->scanfolder(root); - mDip = opendir(root); - - while ((mDit = readdir(mDip))) + for (size_t i = 0; i < subFolders.size(); ++i) { - char buffer[4096]; - sprintf(buffer, "%s%s/story.xml", root, mDit->d_name); - wagic::ifstream file(buffer); - if (file) + string filename = root + subFolders[i] + "story.xml"; + if (FileExists(filename)) { - string fname = mDit->d_name; - stories.push_back(fname); - file.close(); + subFolders[i].resize(subFolders[i].length() - 1); //remove trailing slash + stories.push_back(subFolders[i]); } } - closedir(mDip); switch (stories.size()) { @@ -63,7 +56,7 @@ void GameStateStory::Start() { flow = NULL; menu = NULL; - loadStoriesMenu(JGE_GET_RES("campaigns/").c_str()); + loadStoriesMenu("campaigns/"); } void GameStateStory::Update(float dt) diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index 43234ffaa..af710f828 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -1047,6 +1047,7 @@ JSample * MTGCardInstance::getSample() for (int i = types.size() - 1; i > 0; i--) { string type = Subtypes::subtypesList->find(types[i]); + std::transform(type.begin(), type.end(), type.begin(), ::tolower); type = type + ".wav"; js = WResourceManager::Instance()->RetrieveSample(type); if (js) diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index 907310af1..24bc364a3 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -311,41 +311,6 @@ void MTGAllCards::init() initCounters(); } -void MTGAllCards::loadPrimitives(const char *root_directory) -{ - DIR *dir = opendir(root_directory); - struct dirent *dit; - - while ((dit = readdir(dir))) - { - char fullname[1000]; - sprintf(fullname, "%s/%s", root_directory, dit->d_name); - wagic::ifstream file(fullname); - if (!file) - continue; - file.close(); - MTGCollection()->load(fullname); - } - closedir(dir); -} - -void MTGAllCards::loadSets(const char *root_directory, const char* filename) -{ - DIR *dir = opendir(root_directory); - struct dirent *dit; - - while ((dit = readdir(dir))) - { - char fullname[1000]; - sprintf(fullname, "%s/%s/%s", root_directory, dit->d_name, filename); - wagic::ifstream file(fullname); - if (!file) - continue; - file.close(); - MTGCollection()->load(fullname, dit->d_name); - } - closedir(dir);} - int MTGAllCards::load(const char * config_file, const char * set_name, int autoload) { conf_read_mode = 0; @@ -353,17 +318,10 @@ int MTGAllCards::load(const char * config_file, const char * set_name, int autol MTGSetInfo *si = setlist.getInfo(set_id); int lineNumber = 0; - wagic::ifstream setFile(config_file, ios::in | ios::ate); - if (!setFile) return total_cards; - - streampos fileSize = setFile.tellg(); - setFile.seekg(0, ios::beg); - std::string contents; - contents.resize((std::string::size_type) fileSize); - setFile.read(&contents[0], fileSize); + if (!JFileSystem::GetInstance()->readIntoString(config_file, contents)) + return total_cards; std::stringstream stream(contents); - string s; while (true) @@ -379,7 +337,14 @@ int MTGAllCards::load(const char * config_file, const char * set_name, int autol if (s[0] == '[') { currentGrade = Constants::GRADE_SUPPORTED; // Default value - conf_read_mode = ('m' == s[1]) ? MTGAllCards::READ_METADATA : MTGAllCards::READ_CARD; // M for metadata. + if (s.size() < 2) + { + DebugTrace("FATAL: Card file incorrect"); + } + else + { + conf_read_mode = ('m' == s[1]) ? MTGAllCards::READ_METADATA : MTGAllCards::READ_CARD; // M for metadata. + } } else { @@ -679,7 +644,7 @@ MTGDeck::MTGDeck(MTGAllCards * _allcards) int MTGDeck::totalPrice() { int total = 0; - PriceList * pricelist = NEW PriceList(JGE_GET_RES("settings/prices.dat").c_str(), MTGCollection()); + PriceList * pricelist = NEW PriceList("settings/prices.dat", MTGCollection()); map::iterator it; for (it = cards.begin(); it != cards.end(); it++) { @@ -699,14 +664,16 @@ MTGDeck::MTGDeck(const char * config_file, MTGAllCards * _allcards, int meta_onl size_t dot = filename.find("."); meta_name = filename.substr(slash + 1, dot - slash - 1); meta_id = atoi(meta_name.substr(4).c_str()); - wagic::ifstream file(config_file); - std::string s; - if (file) + std::string contents; + if (JFileSystem::GetInstance()->readIntoString(config_file, contents)) { - while (std::getline(file, s)) + std::stringstream stream(contents); + std::string s; + while (std::getline(stream, s)) { if (!s.size()) continue; if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files + if (!s.size()) continue; if (s[0] == '#') { size_t found = s.find("NAME:"); @@ -773,11 +740,10 @@ MTGDeck::MTGDeck(const char * config_file, MTGAllCards * _allcards, int meta_onl DebugTrace("could not find Card matching name: " << s); } } - file.close(); } else { - //TODO Error management + DebugTrace("FATAL:MTGDeck.cpp:MTGDeck - can't load deck file"); } } @@ -979,10 +945,10 @@ int MTGDeck::save(const string& destFileName, bool useExpandedDescriptions, cons { string tmp = destFileName; tmp.append(".tmp"); //not thread safe - std::ofstream file(tmp.c_str()); - char writer[512]; - if (file) + std::ofstream file; + if (JFileSystem::GetInstance()->openForWrite(file, tmp)) { + char writer[512]; DebugTrace("Saving Deck: " << deckTitle << " to " << destFileName ); if (meta_name.size()) { @@ -1025,8 +991,7 @@ int MTGDeck::save(const string& destFileName, bool useExpandedDescriptions, cons } } file.close(); - std::remove(destFileName.c_str()); - rename(tmp.c_str(), destFileName.c_str()); + JFileSystem::GetInstance()->Rename(tmp, destFileName); } return 1; } @@ -1272,7 +1237,7 @@ MTGSetInfo::MTGSetInfo(string _id) counts[i] = 0; char myFilename[4096]; - sprintf(myFilename, JGE_GET_RES("sets/%s/booster.txt").c_str(), id.c_str()); + sprintf(myFilename, "sets/%s/booster.txt", id.c_str()); mPack = NEW MTGPack(myFilename); if (!mPack->isValid()) { diff --git a/projects/mtg/src/MTGPack.cpp b/projects/mtg/src/MTGPack.cpp index 82ca37672..1e439a87c 100644 --- a/projects/mtg/src/MTGPack.cpp +++ b/projects/mtg/src/MTGPack.cpp @@ -287,18 +287,15 @@ MTGPack * MTGPacks::randomPack(int key) } void MTGPacks::loadAll() { - DIR *mDip = opendir(JGE_GET_RES("packs/").c_str()); - struct dirent *mDit; - if (!mDip) - return; - - while ((mDit = readdir(mDip))) + vectorpackFiles = JFileSystem::GetInstance()->scanfolder("packs/"); + for (size_t i = 0; i < packFiles.size(); ++i) { + string relative = packFiles[i]; char myFilename[4096]; - sprintf(myFilename, JGE_GET_RES("packs/%s").c_str(), mDit->d_name); - if (mDit->d_name[0] == '.') + sprintf(myFilename, "packs/%s",relative.c_str()); + if (relative[0] == '.') continue; - if (!strcmp(mDit->d_name, "default_booster.txt")) + if (!strcmp(relative.c_str(), "default_booster.txt")) continue; MTGPack * p = NEW MTGPack(myFilename); if (!p->isValid()) @@ -308,7 +305,6 @@ void MTGPacks::loadAll() } packs.push_back(p); } - closedir(mDip); } string MTGPack::getName() { @@ -356,7 +352,7 @@ MTGPack * MTGPacks::getDefault() { if (!defaultBooster.isValid()) { - defaultBooster.load(JGE_GET_RES("packs/default_booster.txt")); + defaultBooster.load("packs/default_booster.txt"); defaultBooster.unlockStatus = 1; if (!defaultBooster.isValid()) { diff --git a/projects/mtg/src/ModRules.cpp b/projects/mtg/src/ModRules.cpp index 6f1395d24..2a935bd48 100644 --- a/projects/mtg/src/ModRules.cpp +++ b/projects/mtg/src/ModRules.cpp @@ -10,24 +10,15 @@ ModRules gModRules; bool ModRules::load(string filename) { - JFileSystem *fileSystem = JFileSystem::GetInstance(); - if (!fileSystem) return false; - - if (!fileSystem->OpenFile(filename.c_str())) + std::string xmlBuffer; + if (! JFileSystem::GetInstance()->readIntoString(filename, xmlBuffer)) { - DebugTrace("FATAL: " << filename << "Does not exist"); + DebugTrace("FATAL: cannot find modrules.xml"); return false; } - int size = fileSystem->GetFileSize(); - char *xmlBuffer = NEW char[size]; - fileSystem->ReadFile(xmlBuffer, size); - TiXmlDocument doc; - doc.Parse(xmlBuffer); - - fileSystem->CloseFile(); - delete[] xmlBuffer; + doc.Parse(xmlBuffer.c_str()); for (TiXmlNode* node = doc.FirstChild(); node; node = node->NextSibling()) { diff --git a/projects/mtg/src/OptionItem.cpp b/projects/mtg/src/OptionItem.cpp index 35dc98c3d..eec98d077 100644 --- a/projects/mtg/src/OptionItem.cpp +++ b/projects/mtg/src/OptionItem.cpp @@ -108,7 +108,7 @@ void OptionSelect::addSelection(string s) //OptionProfile const string OptionProfile::DIRTESTER = "collection.dat"; OptionProfile::OptionProfile(GameApp * _app, JGuiListener * jgl) : - OptionDirectory(JGE_GET_RES("profiles"), Options::ACTIVE_PROFILE, "Profile", DIRTESTER) + OptionDirectory("profiles/", Options::ACTIVE_PROFILE, "Profile", DIRTESTER) { app = _app; listener = jgl; @@ -165,16 +165,16 @@ void OptionProfile::populate() PlayerData * pdata = NEW PlayerData(MTGCollection()); int unlocked = 0, sets = setlist.size(); - wagic::ifstream file(options.profileFile(PLAYER_SETTINGS).c_str()); - std::string s; - if (file) + std::string contents; + if (JFileSystem::GetInstance()->readIntoString(options.profileFile(PLAYER_SETTINGS), contents)) { - while (std::getline(file, s)) + std::stringstream stream(contents); + std::string s; + while (std::getline(stream, s)) { if (s.substr(0, 9) == "unlocked_") unlocked++; } - file.close(); } options[Options::ACTIVE_PROFILE] = temp; @@ -321,47 +321,44 @@ void OptionLanguage::confirmChange(bool confirmed) void OptionLanguage::Reload() { - struct dirent *mDit; - DIR *mDip; - mDip = opendir(JGE_GET_RES("lang").c_str()); - - while ((mDit = readdir(mDip))) + vector langFiles = JFileSystem::GetInstance()->scanfolder("lang/"); + for (size_t i = 0; i < langFiles.size(); ++i) { - string filename = JGE_GET_RES("lang/"); - filename += mDit->d_name; - wagic::ifstream file(filename.c_str()); + izfstream file; + string filePath = "lang/"; + filePath.append(langFiles[i]); + if (! JFileSystem::GetInstance()->openForRead(file, filePath)) + continue; + string s; string lang; - if (file) + + if (std::getline(file, s)) { - if (std::getline(file, s)) + if (!s.size()) { - if (!s.size()) - { - lang = ""; - } - else - { - if (s[s.size() - 1] == '\r') - s.erase(s.size() - 1); //Handle DOS files - size_t found = s.find("#LANG:"); - if (found != 0) - lang = ""; - else - lang = s.substr(6); - } + lang = ""; + } + else + { + if (s[s.size() - 1] == '\r') + s.erase(s.size() - 1); //Handle DOS files + size_t found = s.find("#LANG:"); + if (found != 0) + lang = ""; + else + lang = s.substr(6); } - file.close(); } + file.close(); if (lang.size()) { - string filen = mDit->d_name; + string filen = langFiles[i]; addSelection(filen.substr(0, filen.size() - 4), lang); } } - closedir(mDip); initSelections(); } @@ -398,59 +395,39 @@ bool OptionLanguage::Selectable() //OptionDirectory void OptionDirectory::Reload() { - DIR *mDip; - struct dirent *mDit; - char buf[PATH_MAX]; - mDip = opendir(root.c_str()); - - if (!mDip) - return; - - while ((mDit = readdir(mDip))) + vector subfolders = JFileSystem::GetInstance()->scanfolder(root); + for (size_t i = 0; i < subfolders.size(); ++i) { - sprintf(buf, "%s/%s/%s", root.c_str(), mDit->d_name, type.c_str()); - wagic::ifstream file(buf); - if (!file) + string filename = root + "/" + subfolders[i] + "/" + type; + if (!JFileSystem::GetInstance()->FileExists(filename)) continue; - file.close(); - if (find(selections.begin(), selections.end(), mDit->d_name) == selections.end()) - addSelection(mDit->d_name); + if (find(selections.begin(), selections.end(), subfolders[i]) == selections.end()) + addSelection(subfolders[i]); } - - closedir(mDip); - mDip = NULL; initSelections(); } OptionDirectory::OptionDirectory(string root, int id, string displayValue, string type) : OptionSelect(id, displayValue), root(root), type(type) { - DIR *mDip; - struct dirent *mDit; - char buf[PATH_MAX]; - - mDip = opendir(root.c_str()); - if (!mDip) - return; - - while ((mDit = readdir(mDip))) + vector subfolders = JFileSystem::GetInstance()->scanfolder(root); + + for (size_t i = 0; i < subfolders.size(); ++i) { - sprintf(buf, "%s/%s/%s", root.c_str(), mDit->d_name, type.c_str()); - wagic::ifstream file(buf); - if (!file) - continue; - file.close(); - addSelection(mDit->d_name); + string subfolder = subfolders[i].substr(0, subfolders[i].length() - 1); //remove trailing "/" + vector path; + path.push_back(root); + path.push_back(subfolder); + string filePath = buildFilePath(path, type); + if (JFileSystem::GetInstance()->FileExists(filePath)) + addSelection(subfolder); } - - closedir(mDip); - mDip = NULL; initSelections(); } const string OptionTheme::DIRTESTER = "preview.png"; OptionTheme::OptionTheme(OptionThemeStyle * style) : - OptionDirectory(JGE_GET_RES("themes"), Options::ACTIVE_THEME, "Current Theme", DIRTESTER) + OptionDirectory("themes", Options::ACTIVE_THEME, "Current Theme", DIRTESTER) { addSelection("Default"); sort(selections.begin(), selections.end()); @@ -492,20 +469,20 @@ void OptionTheme::Render() author = ""; bChecked = true; if (selections[value] == "Default") - sprintf(buf, "%s", JGE_GET_RES("graphics/themeinfo.txt").c_str()); + sprintf(buf, "%s", "graphics/themeinfo.txt"); else - sprintf(buf, "%s%s", JGE_GET_RES("themes/%s/themeinfo.txt").c_str(), selections[value].c_str()); - wagic::ifstream file(buf); - if (file) + sprintf(buf, "themes/%s/themeinfo.txt", selections[value].c_str()); + string contents; + if (JFileSystem::GetInstance()->readIntoString(buf, contents)) { + std::stringstream stream(contents); string temp; - std::getline(file, temp); + std::getline(stream, temp); for (unsigned int x = 0; x < 17 && x < temp.size(); x++) { if (isprint(temp[x])) //Clear stuff that breaks mFont->DrawString, cuts to 16 chars. author += temp[x]; } - file.close(); } } sprintf(buf, _("Theme: %s").c_str(), selections[value].c_str()); diff --git a/projects/mtg/src/PlayerData.cpp b/projects/mtg/src/PlayerData.cpp index 61384cf3f..1d214b548 100644 --- a/projects/mtg/src/PlayerData.cpp +++ b/projects/mtg/src/PlayerData.cpp @@ -24,11 +24,12 @@ void PlayerData::init() //CREDITS credits = 3000; //Default value - wagic::ifstream file(options.profileFile(PLAYER_SAVEFILE).c_str()); - std::string s; - if (file) + std::string contents; + if (JFileSystem::GetInstance()->readIntoString(options.profileFile(PLAYER_SAVEFILE), contents)) { - if (std::getline(file, s)) + std::stringstream stream(contents); + std::string s; + if (std::getline(stream, s)) { credits = atoi(s.c_str()); } @@ -38,7 +39,7 @@ void PlayerData::init() } //Story Saves - while (std::getline(file, s)) + while (std::getline(stream, s)) { if (!s.size()) continue; if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files @@ -54,7 +55,6 @@ void PlayerData::init() key = key.substr(2); storySaves[key] = value; } - file.close(); } taskList = NEW TaskList(options.profileFile(PLAYER_TASKS).c_str()); @@ -62,10 +62,10 @@ void PlayerData::init() int PlayerData::save() { - std::ofstream file(options.profileFile(PLAYER_SAVEFILE).c_str()); - char writer[512]; - if (file) + std::ofstream file; + if (JFileSystem::GetInstance()->openForWrite(file, options.profileFile(PLAYER_SAVEFILE))) { + char writer[512]; sprintf(writer, "%i\n", credits); file << writer; diff --git a/projects/mtg/src/PriceList.cpp b/projects/mtg/src/PriceList.cpp index cd2d132f0..4e25d9c73 100644 --- a/projects/mtg/src/PriceList.cpp +++ b/projects/mtg/src/PriceList.cpp @@ -10,17 +10,17 @@ PriceList::PriceList(const char * _filename, MTGAllCards * _collection) : collection(_collection) { filename = _filename; - wagic::ifstream file(_filename); - std::string cardid; - std::string price; - if (file) + std::string contents; + if (JFileSystem::GetInstance()->readIntoString(filename, contents)) { - while (std::getline(file, cardid)) + std::stringstream stream(contents); + std::string cardid; + std::string price; + while (std::getline(stream, cardid)) { - std::getline(file, price); + std::getline(stream, price); prices[atoi(cardid.c_str())] = atoi(price.c_str()); } - file.close(); } if (randomKey == 0) randomKey = rand(); } @@ -31,10 +31,10 @@ PriceList::~PriceList() int PriceList::save() { - std::ofstream file(filename.c_str()); - char writer[20]; - if (file) + std::ofstream file; + if (JFileSystem::GetInstance()->openForWrite(file, filename)) { + char writer[20]; map::iterator it = prices.begin(); while (it != prices.end()) { diff --git a/projects/mtg/src/Rules.cpp b/projects/mtg/src/Rules.cpp index 8f8e47c81..efbe2859d 100644 --- a/projects/mtg/src/Rules.cpp +++ b/projects/mtg/src/Rules.cpp @@ -13,7 +13,6 @@ #include "AIPlayer.h" #include - vector Rules::RulesList = vector(); //Sorting by dissplayName @@ -35,13 +34,11 @@ Rules * Rules::getRulesByFilename(string _filename) int Rules::loadAllRules() { - DIR *dip = opendir(JGE_GET_RES("rules").c_str()); - struct dirent *dit; - - while ((dit = readdir(dip))) + vector rulesFiles = JFileSystem::GetInstance()->scanfolder("rules"); + for (size_t i = 0; i < rulesFiles.size(); ++i) { Rules * rules = NEW Rules(); - if (rules->load(dit->d_name)) + if (rules->load(rulesFiles[i])) { RulesList.push_back(rules); } @@ -53,7 +50,6 @@ int Rules::loadAllRules() //Kind of a hack here, we sort Rules alphabetically because it turns out to be matching // The historical order of Game modes: Classic, Momir Basic, Random 1, Random 2, Story std::sort(RulesList.begin(),RulesList.end(),RulesMenuCmp_); - closedir(dip); return 1; } @@ -597,22 +593,23 @@ int Rules::load(string _filename) } else { - sprintf(c_filename, JGE_GET_RES("rules/%s").c_str(), _filename.c_str()); + sprintf(c_filename, "rules/%s", _filename.c_str()); } - wagic::ifstream file(c_filename); + std::string contents; + if (!JFileSystem::GetInstance()->readIntoString(c_filename, contents)) + return 0; + std::stringstream stream(contents); std::string s; int state = PARSE_UNDEFINED; - // std::cout << std::endl << std::endl << "!!!" << file << std::endl << std::endl; - if (!file) return 0; - cleanup(); - while (std::getline(file, s)) + while (std::getline(stream, s)) { if (!s.size()) continue; if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files + if (!s.size()) continue; if (s[0] == '#') continue; string scopy = s; std::transform(s.begin(), s.end(), s.begin(), ::tolower); @@ -689,7 +686,6 @@ int Rules::load(string _filename) break; } } - file.close(); return 1; } diff --git a/projects/mtg/src/StoryFlow.cpp b/projects/mtg/src/StoryFlow.cpp index 80f6fdb43..e73817265 100644 --- a/projects/mtg/src/StoryFlow.cpp +++ b/projects/mtg/src/StoryFlow.cpp @@ -302,7 +302,7 @@ void StoryDuel::init() Player * players[2]; char folder[255], deckFile[255], deckFileSmall[255]; - sprintf(folder, JGE_GET_RES(CAMPAIGNS_FOLDER"%s/%s").c_str(), mParent->folder.c_str(), pageId.c_str()); + sprintf(folder, CAMPAIGNS_FOLDER"%s/%s", mParent->folder.c_str(), pageId.c_str()); sprintf(deckFile, "%s/deck.txt", folder); sprintf(deckFileSmall, "campaign_%s", mParent->folder.c_str()); diff --git a/projects/mtg/src/StyleManager.cpp b/projects/mtg/src/StyleManager.cpp index ccf2d8bff..e2005a7c5 100644 --- a/projects/mtg/src/StyleManager.cpp +++ b/projects/mtg/src/StyleManager.cpp @@ -45,9 +45,15 @@ void StyleManager::loadRules() { killRules(); //TODO Placeholder until XML format available. - string filename = JGE_GET_RES(WResourceManager::Instance()->graphicsFile("style.txt")); - TiXmlDocument xmlfile(filename.c_str()); - if (!xmlfile.LoadFile()) return; + string filename = WResourceManager::Instance()->graphicsFile("style.txt"); + + std::string xmlBuffer; + if (! JFileSystem::GetInstance()->readIntoString(filename, xmlBuffer)) + return; + + TiXmlDocument xmlfile; + xmlfile.Parse(xmlBuffer.c_str()); + TiXmlHandle hDoc(&xmlfile); TiXmlElement * pRule; for (pRule = hDoc.FirstChildElement().Element(); pRule != NULL; pRule = pRule->NextSiblingElement()) diff --git a/projects/mtg/src/Tasks.cpp b/projects/mtg/src/Tasks.cpp index 2399931a0..2999b5025 100644 --- a/projects/mtg/src/Tasks.cpp +++ b/projects/mtg/src/Tasks.cpp @@ -160,7 +160,7 @@ void Task::LoadAIDeckNames() { found = 0; std::ostringstream stream; - stream << JGE_GET_RES("ai/baka") << "/deck" << nbDecks + 1 << ".txt"; + stream << "ai/baka" << "/deck" << nbDecks + 1 << ".txt"; if (fileExists(stream.str().c_str())) { found = 1; @@ -281,8 +281,8 @@ int TaskList::save(string _fileName) return -1; } - std::ofstream file(fileName.c_str()); - if (file) + std::ofstream file; + if (JFileSystem::GetInstance()->openForWrite(file, fileName)) { #if defined (WIN32) || defined (LINUX) DebugTrace("\nsaving tasks\n"); @@ -309,48 +309,39 @@ int TaskList::load(string _fileName) } if (fileName == "") { -#if defined (WIN32) || defined (LINUX) DebugTrace("\nTaskList::load: No filename specified\n"); -#endif return -1; } - wagic::ifstream file(fileName.c_str()); - std::string s; - - if (file) + std::string contents; + if (!JFileSystem::GetInstance()->readIntoString(fileName, contents)) { - while (std::getline(file, s)) - { - if (!s.size()) continue; - if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files - if (s[0] == '#') - { - continue; - } - - task = Task::createFromStr(s); - if (task) - { - this->addTask(task); - } - else - { -#if defined (WIN32) || defined (LINUX) - DebugTrace("\nTaskList::load: error creating task\n"); -#endif - } - } - file.close(); - } - else - { -#if defined (WIN32) || defined (LINUX) DebugTrace("\nTaskList::load: Failed to open file\n"); -#endif return -1; } + std::stringstream stream(contents); + std::string s; + while (std::getline(stream, s)) + { + if (!s.size()) continue; + if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files + if (s[0] == '#') + { + continue; + } + + task = Task::createFromStr(s); + if (task) + { + this->addTask(task); + } + else + { + DebugTrace("\nTaskList::load: error creating task\n"); + } + } + return 1; } diff --git a/projects/mtg/src/TestSuiteAI.cpp b/projects/mtg/src/TestSuiteAI.cpp index b434f3070..fb708aeb1 100644 --- a/projects/mtg/src/TestSuiteAI.cpp +++ b/projects/mtg/src/TestSuiteAI.cpp @@ -436,8 +436,8 @@ DebugTrace("TESTUITE Init Game Done !"); } int TestSuite::Log(const char * text) { - ofstream file(JGE_GET_RES("test/results.html").c_str(), ios_base::app); - if (file) + ofstream file; + if (JFileSystem::GetInstance()->openForWrite(file, "test/results.html", ios_base::app)) { file << text; file << "\n"; @@ -555,7 +555,7 @@ TestSuite::TestSuite(const char * filename, MTGAllCards* _collection) { collection = _collection; timerLimit = 0; - wagic::ifstream file(filename); + std::string s; nbfiles = 0; currentfile = 0; @@ -567,9 +567,12 @@ TestSuite::TestSuite(const char * filename, MTGAllCards* _collection) seed = 0; forceAbility = false; aiMaxCalls = -1; - if (file) + + std::string contents; + if (JFileSystem::GetInstance()->readIntoString(filename, contents)) { - while (std::getline(file, s)) + std::stringstream stream(contents); + while (std::getline(stream, s)) { if (!s.size()) continue; if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files @@ -581,11 +584,10 @@ TestSuite::TestSuite(const char * filename, MTGAllCards* _collection) } if (s[0] == '*' && s[1] == '/') comment = 0; } - file.close(); } - ofstream file2(JGE_GET_RES("/test/results.html").c_str()); - if (file2) + ofstream file2; + if (JFileSystem::GetInstance()->openForWrite(file2, "/test/results.html")) { file2 << ""; #ifdef WIN32 @@ -662,18 +664,20 @@ int TestSuite::load(const char * _filename) forceAbility = false; gameType = GAME_TYPE_CLASSIC; char filename[4096]; - sprintf(filename, JGE_GET_RES("/test/%s").c_str(), _filename); - wagic::ifstream file(filename); + sprintf(filename, "test/%s", _filename); + std::string s; loadRandValues(""); int state = -1; - // std::cout << std::endl << std::endl << "!!!" << file << std::endl << std::endl; - if (file) + std::string contents; + if (JFileSystem::GetInstance()->readIntoString(filename, contents)) { + std::stringstream stream(contents); + cleanup(); - while (std::getline(file, s)) + while (std::getline(stream, s)) { if (!s.size()) continue; if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files @@ -786,7 +790,6 @@ int TestSuite::load(const char * _filename) break; } } - file.close(); } else { diff --git a/projects/mtg/src/Translate.cpp b/projects/mtg/src/Translate.cpp index 1fc634a9d..cf0b1a37b 100644 --- a/projects/mtg/src/Translate.cpp +++ b/projects/mtg/src/Translate.cpp @@ -42,10 +42,10 @@ Translator::~Translator() { #if defined DEBUG_TRANSLATE if (!checkMisses) return; - std::ofstream file(JGE_GET_RES("lang/missing.txt").c_str()); - char writer[4096]; - if (file) + std::ofstream file; + if (JFileSystem::GetInstance()->openForWrite(file, "lang/missing.txt")) { + char writer[4096]; map::iterator it; for (it = missingValues.begin(); it!=missingValues.end(); it++) { @@ -65,16 +65,18 @@ Translator::Translator() void Translator::load(string filename, map * dictionary) { - wagic::ifstream file(filename.c_str()); - if (file) + std::string contents; + if (JFileSystem::GetInstance()->readIntoString(filename, contents)) { + std::stringstream stream(contents); string s; + initDone = true; #if defined DEBUG_TRANSLATE checkMisses = 1; #endif - while (std::getline(file, s)) + while (std::getline(stream, s)) { if (!s.size()) continue; if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files @@ -84,17 +86,16 @@ void Translator::load(string filename, map * dictionary) string s2 = s.substr(found + 1); (*dictionary)[s1] = s2; } - file.close(); } #if defined DEBUG_TRANSLATE if (!checkMisses) return; - wagic::ifstream file2(JGE_GET_RES("lang/dontcare.txt").c_str()); - if(file2) + if (JFileSystem::GetInstance()->readIntoString("lang/dontcare.txt", contents)) { + std::stringstream stream(contents); string s; - while(std::getline(file2,s)) + while(std::getline(stream,s)) { if (!s.size()) continue; if (s[s.size()-1] == '\r') s.erase(s.size()-1); //Handle DOS files @@ -103,7 +104,6 @@ void Translator::load(string filename, map * dictionary) s = s.substr(0,found); dontCareValues[s] = 1; } - file2.close(); } #endif } @@ -112,7 +112,7 @@ void Translator::initCards() { string lang = options[Options::LANG].str; if (!lang.size()) return; - string cards_dict = JGE_GET_RES("lang/") + lang + "_cards.txt"; + string cards_dict = "lang/" + lang + "_cards.txt"; load(cards_dict, &tempValues); } @@ -120,15 +120,16 @@ void Translator::initDecks() { string lang = options[Options::LANG].str; if (!lang.size()) return; - string decks_dict = JGE_GET_RES("lang/") + lang + "_decks.txt"; + string decks_dict = "lang/" + lang + "_decks.txt"; // Load file - wagic::ifstream file(decks_dict.c_str()); - if (file) + std::string contents; + if (JFileSystem::GetInstance()->readIntoString(decks_dict, contents)) { + std::stringstream stream(contents); string s; initDone = true; - while (std::getline(file, s)) + while (std::getline(stream, s)) { if (!s.size()) continue; if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files @@ -143,7 +144,6 @@ void Translator::initDecks() string s2 = s.substr(found + 1); deckValues[s1] = s2; } - file.close(); } } @@ -154,7 +154,7 @@ void Translator::init() #endif string lang = options[Options::LANG].str; if (!lang.size()) return; - string name = JGE_GET_RES("lang/") + lang + ".txt"; + string name = "lang/" + lang + ".txt"; if (fileExists(name.c_str())) { diff --git a/projects/mtg/src/WCachedResource.cpp b/projects/mtg/src/WCachedResource.cpp index 2b1464c7e..de6c14be1 100644 --- a/projects/mtg/src/WCachedResource.cpp +++ b/projects/mtg/src/WCachedResource.cpp @@ -349,7 +349,7 @@ bool WCachedParticles::Attempt(const string& filename, int submode, int & error) // we're actually trying to read more than the file size now, but it's no problem. // Note that this fix is only to avoid the largest problems, filling a structure // by directly reading a file, is really a bad idea ... - fileSys->ReadFile(&(particles->nEmission), sizeof(hgeParticleSystemInfo)); + fileSys->ReadFile(&(particles->nEmission), sizeof(hgeParticleSystemInfo) - 4); fileSys->CloseFile(); particles->sprite = NULL; diff --git a/projects/mtg/src/WDataSrc.cpp b/projects/mtg/src/WDataSrc.cpp index 7f693fc67..aa817e202 100644 --- a/projects/mtg/src/WDataSrc.cpp +++ b/projects/mtg/src/WDataSrc.cpp @@ -550,7 +550,7 @@ int WSrcDeck::getCount(int count) int WSrcDeck::totalPrice() { int total = 0; - PriceList * pricelist = NEW PriceList(JGE_GET_RES("settings/prices.dat").c_str(), MTGCollection()); + PriceList * pricelist = NEW PriceList("settings/prices.dat", MTGCollection()); map::iterator it; for (it = copies.begin(); it != copies.end(); it++) { diff --git a/projects/mtg/src/WResourceManager.cpp b/projects/mtg/src/WResourceManager.cpp index 33d5a1637..2b00baa55 100644 --- a/projects/mtg/src/WResourceManager.cpp +++ b/projects/mtg/src/WResourceManager.cpp @@ -561,14 +561,14 @@ string ResourceManagerImpl::graphicsFile(const string& filename) if (ws) { sprintf(buf, "themes/%s/%s", theme.c_str(), ws->stylized(filename).c_str()); - if (fileOK(buf, true)) return buf; + if (fileOK(buf)) return buf; } } if (theme != "" && theme != "Default") { sprintf(buf, "themes/%s/%s", theme.c_str(), filename.c_str()); - if (fileOK(buf, true)) return buf; + if (fileOK(buf)) return buf; } /* //FIXME Put back when we're using modes. @@ -584,15 +584,15 @@ string ResourceManagerImpl::graphicsFile(const string& filename) //Failure. Check graphics char graphdir[512]; sprintf(graphdir, "graphics/%s", filename.c_str()); - if (fileOK(graphdir, true)) return graphdir; + if (fileOK(graphdir)) return graphdir; //Failure. Check sets. sprintf(buf, "sets/%s", filename.c_str()); - if (fileOK(buf, true)) return buf; + if (fileOK(buf)) return buf; //Failure. Check raw faile. sprintf(buf, "%s", filename.c_str()); - if (fileOK(buf, true)) return buf; + if (fileOK(buf)) return buf; //Complete abject failure. Probably a crash... return graphdir; @@ -608,12 +608,12 @@ string ResourceManagerImpl::avatarFile(const string& filename) if (profile != "" && profile != "Default") { sprintf(buf, "profiles/%s/%s", profile.c_str(), filename.c_str()); - if (fileOK(buf, true)) return buf; + if (fileOK(buf)) return buf; } else { sprintf(buf, "player/%s", filename.c_str()); - if (fileOK(buf, true)) return buf; + if (fileOK(buf)) return buf; } //Check the theme folder. @@ -622,7 +622,7 @@ string ResourceManagerImpl::avatarFile(const string& filename) if (theme != "" && theme != "Default") { sprintf(buf, "themes/%s/%s", theme.c_str(), filename.c_str()); - if (fileOK(buf, true)) return buf; + if (fileOK(buf)) return buf; } /* //FIXME Put back when we're using modes. @@ -638,15 +638,15 @@ string ResourceManagerImpl::avatarFile(const string& filename) //Failure. Check Baka sprintf(buf, "ai/baka/avatars/%s", filename.c_str()); - if (fileOK(buf, true)) return buf; + if (fileOK(buf)) return buf; //Failure. Check graphics sprintf(buf, "graphics/%s", filename.c_str()); - if (fileOK(buf, true)) return buf; + if (fileOK(buf)) return buf; //Failure. Check raw faile. sprintf(buf, "%s", filename.c_str()); - if (fileOK(buf, true)) return buf; + if (fileOK(buf)) return buf; //Complete abject failure. Probably a crash... return ""; @@ -678,12 +678,12 @@ string ResourceManagerImpl::cardFile(const string& filename) if (set.size()) { char zipname[512]; - sprintf(zipname, JGE_GET_RES("themes/%s/sets/%s/%s.zip").c_str(), theme.c_str(), set.c_str(), set.c_str()); + sprintf(zipname, "themes/%s/sets/%s/%s.zip", theme.c_str(), set.c_str(), set.c_str()); if (fs->AttachZipFile(zipname)) return filename.substr(i + 1); } sprintf(buf, "themes/%s/sets/%s", theme.c_str(), filename.c_str()); - if (fileOK(buf, true)) return buf; //Themed, unzipped. + if (fileOK(buf)) return buf; //Themed, unzipped. } } @@ -712,14 +712,14 @@ string ResourceManagerImpl::cardFile(const string& filename) if (set.size()) { char zipname[512]; - sprintf(zipname, JGE_GET_RES("sets/%s/%s.zip").c_str(), set.c_str(), set.c_str()); + sprintf(zipname, "sets/%s/%s.zip", set.c_str(), set.c_str()); if (fs->AttachZipFile(zipname)) return filename.substr(i + 1); } //Failure. Check for unzipped file in sets char defdir[512]; sprintf(defdir, "sets/%s", filename.c_str()); - if (fileOK(defdir, true)) return defdir; + if (fileOK(defdir)) return defdir; //Complete failure. return ""; @@ -735,7 +735,7 @@ string ResourceManagerImpl::musicFile(const string& filename) if (theme != "" && theme != "Default") { sprintf(buf, "themes/%s/sound/%s", theme.c_str(), filename.c_str()); - if (fileOK(buf, true)) return buf; + if (fileOK(buf)) return buf; } /* @@ -752,11 +752,11 @@ string ResourceManagerImpl::musicFile(const string& filename) //Failure. Check sound char defdir[512]; sprintf(defdir, "sound/%s", filename.c_str()); - if (fileOK(defdir, true)) return defdir; + if (fileOK(defdir)) return defdir; //Failure. Check raw faile. sprintf(defdir, "%s", filename.c_str()); - if (fileOK(defdir, true)) return defdir; + if (fileOK(defdir)) return defdir; //Complete abject failure. Probably a crash... return ""; @@ -772,7 +772,7 @@ string ResourceManagerImpl::sfxFile(const string& filename) if (theme != "" && theme != "Default") { sprintf(buf, "themes/%s/sound/sfx/%s", theme.c_str(), filename.c_str()); - if (fileOK(buf, true)) return buf; + if (fileOK(buf)) return buf; } /* @@ -788,49 +788,20 @@ string ResourceManagerImpl::sfxFile(const string& filename) //Failure. Check sound char defdir[512]; sprintf(defdir, "sound/sfx/%s", filename.c_str()); - if (fileOK(defdir, true)) return defdir; + if (fileOK(defdir)) return defdir; //Complete abject failure. Probably a crash... return ""; } -int ResourceManagerImpl::dirOK(const string& dirname) +bool ResourceManagerImpl::dirOK(const string& dirname) { - char fname[512]; - -#if defined (WIN32) - sprintf(fname,JGE_GET_RES(dirname).c_str()); - - struct _stat statBuffer; - return (_stat(fname, &statBuffer) >= 0 && // make sure it exists - statBuffer.st_mode & S_IFDIR); // and it's not a file -#else - sprintf(fname, "%s", JGE_GET_RES(dirname).c_str()); - struct stat st; - if (stat(fname, &st) == 0) return 1; -#endif - return 0; + return JFileSystem::GetInstance()->DirExists(dirname); } -int ResourceManagerImpl::fileOK(const string& filename, bool relative) +bool ResourceManagerImpl::fileOK(const string& filename) { - wagic::ifstream * fp = NULL; - if (relative) - { - fp = NEW wagic::ifstream(JGE_GET_RES(filename).c_str()); - } - else - fp = NEW wagic::ifstream(filename.c_str()); - - int result = 0; - if (fp) - { - if (*fp) result = 1; - fp->close(); - delete fp; - } - - return result; + return JFileSystem::GetInstance()->FileExists(filename); } void ResourceManagerImpl::InitFonts(const std::string& inLang) diff --git a/projects/mtg/src/utils.cpp b/projects/mtg/src/utils.cpp index 592f85a73..ee7215d54 100644 --- a/projects/mtg/src/utils.cpp +++ b/projects/mtg/src/utils.cpp @@ -78,62 +78,16 @@ int filesize(const char * filename) return file_size; } - -// check to see if a file exists on the file system. -int fileExists(const char * filename) +bool fileExists(const char * filename) { - wagic::ifstream fichier(filename); - if (fichier) - { - fichier.close(); - return 1; - } - - wagic::ifstream fichier2(JGE_GET_RES(filename).c_str()); - if (fichier2) - { - fichier2.close(); - return 1; - } - return 0; + return JFileSystem::GetInstance()->FileExists(filename); } -// check to see if a file exists on the file system. -// this can be used to extract last modified date of a file. -bool FileExists(const string& strFilename) -{ - struct stat stFileInfo; - bool blnReturn = false; - int intStat; - - // Attempt to get the file attributes - intStat = stat(strFilename.c_str(),&stFileInfo); - if(intStat == 0) - { - // We were able to get the file attributes - // so the file obviously exists. - blnReturn = true; - } - else - { - // We were not able to get the file attributes. - // This may mean that we don't have permission to - // access the folder which contains this file. If you - // need to do that level of checking, lookup the - // return values of stat which will give you - // more details on why stat failed. - - // try to search in the resource directory - if ( stat( JGE_GET_RES(strFilename).c_str(), &stFileInfo ) == 0) - blnReturn = true; - else - blnReturn = false; - } - - return(blnReturn); +bool FileExists(const string & filename) +{ + return JFileSystem::GetInstance()->FileExists(filename); } - /* #ifdef LINUX @@ -396,4 +350,21 @@ unsigned long hash_djb2(const char *str) hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ return hash; +} + +std::string buildFilePath(const vector & folders, const string & filename) +{ + string result = ""; + for (size_t i = 0; i < folders.size(); ++i) + { + result.append(folders[i]); + if (result[result.length()-1] != '/') + { + result.append("/"); + } + } + + result.append(filename); + return result; + } \ No newline at end of file diff --git a/projects/mtg/template.vcxproj b/projects/mtg/template.vcxproj index e9d983dd9..c450c0bbc 100644 --- a/projects/mtg/template.vcxproj +++ b/projects/mtg/template.vcxproj @@ -156,7 +156,7 @@ Disabled - ./include;$(MTGEXTRAS);../../JGE/include;../../JGE/Dependencies/include;../../Boost;../../JGE/Dependencies/SDL/include;%(AdditionalIncludeDirectories) + ./include;$(MTGEXTRAS);../../JGE/include;../../JGE/Dependencies/include;../../Boost;../../JGE/Dependencies/SDL/include;../../JGE/src/zipFS;%(AdditionalIncludeDirectories) SDL_CONFIG;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks @@ -181,7 +181,7 @@ glu32.lib;opengl32.lib;odbc32.lib;odbccp32.lib;SDL.lib;libpngd.lib;fmodvc.lib;libjpeg-static-mt-debug.lib;freetype.lib;%(AdditionalDependencies) true - ..\..\JGE\Dependencies\lib;..\..\JGE\lib\win;..\..\Boost\lib;%(AdditionalLibraryDirectories) + ..\..\zipFS;..\..\JGE\Dependencies\lib;..\..\JGE\lib\win;..\..\Boost\lib;%(AdditionalLibraryDirectories) LIBCD;LIBC;MSVCRT;LIBCMTD;%(IgnoreSpecificDefaultLibraries) true .\Debug/template.pdb diff --git a/projects/mtg/wagic-SDL.pro b/projects/mtg/wagic-SDL.pro index 4377b80bc..f640ab5b2 100644 --- a/projects/mtg/wagic-SDL.pro +++ b/projects/mtg/wagic-SDL.pro @@ -30,7 +30,7 @@ unix:INCLUDEPATH += /usr/include/GL unix:INCLUDEPATH += /usr/local/include/SDL macx:INCLUDEPATH += /opt/include INCLUDEPATH += ../../JGE/include -INCLUDEPATH += ../../JGE/include/unzip +INCLUDEPATH += ../../JGE/src/zipFS INCLUDEPATH += ../../Boost INCLUDEPATH += include OBJECTS_DIR = objs @@ -297,9 +297,9 @@ SOURCES += \ ../../JGE/src/hge/hgeparticle.cpp\ ../../JGE/src/hge/hgerect.cpp\ ../../JGE/src/hge/hgevector.cpp\ - ../../JGE/src/unzip/ioapi.c\ - ../../JGE/src/unzip/mztools.c\ - ../../JGE/src/unzip/unzip.c\ + ../../JGE/src/zipFS/zfsystem.cpp\ + ../../JGE/src/zipFS/ziphdr.cpp\ + ../../JGE/src/zipFS/zstream.cpp\ ../../JGE/src/pc/JSfx.cpp\ ../../JGE/src/pc/JGfx.cpp\ ../../JGE/src/JNetwork.cpp\ diff --git a/projects/mtg/wagic-qt.pro b/projects/mtg/wagic-qt.pro index 5b14d0da5..12f175eac 100644 --- a/projects/mtg/wagic-qt.pro +++ b/projects/mtg/wagic-qt.pro @@ -34,6 +34,7 @@ windows:INCLUDEPATH += extra unix:!symbian:INCLUDEPATH += /usr/include/GL macx:INCLUDEPATH += /opt/include INCLUDEPATH += ../../JGE/include +INCLUDEPATH += ../../JGE/src/zipFS INCLUDEPATH += ../../Boost INCLUDEPATH += include OBJECTS_DIR = objs @@ -292,9 +293,9 @@ SOURCES += \ ../../JGE/src/hge/hgeparticle.cpp\ ../../JGE/src/hge/hgerect.cpp\ ../../JGE/src/hge/hgevector.cpp\ - ../../JGE/src/unzip/ioapi.c\ - ../../JGE/src/unzip/mztools.c\ - ../../JGE/src/unzip/unzip.c\ + ../../JGE/src/zipFS/zfsystem.cpp\ + ../../JGE/src/zipFS/ziphdr.cpp\ + ../../JGE/src/zipFS/zstream.cpp\ ../../JGE/src/pc/JSfx.cpp\ ../../JGE/src/pc/JGfx.cpp