// ============================================================== // This file is part of Glest Shared Library (www.glest.org) // // Copyright (C) 2001-2010 MartiƱo Figueroa and others // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published // by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version // ============================================================== #ifndef FILE_READER_H #define FILE_READER_H #include "platform_util.h" #include #include #include #include #include #include using std::map; using std::string; using std::vector; using std::ifstream; using std::ios; using std::runtime_error; using Shared::Platform::extractExtension; namespace Shared{ // ===================================================== // class FileReader // ===================================================== template class FileReader { protected: string const * extensions; /**Creates a filereader being able to possibly load files * from the specified extension **/ FileReader(string const * extensions); public: /*Return the - existing and initialized - fileReadersMap */ static map const * >* >& getFileReadersMap() { static map const * >* > fileReaderByExtension; return fileReaderByExtension; } static vector const * > fileReaders; public: /**Tries to read a file * This method tries to read the file with the specified filepath. * If it fails, either null is returned or an exception * is thrown*/ static T* readPath(const string& filepath); /**Tries to read a file from an object * This method tries to read the file with the specified filepath. * If it fails, either null is returned or an exception * is thrown*/ static T* readPath(const string& filepath, T* object); /**Gives a quick estimation of whether the specified file * can be read or not depending on the filename*/ virtual bool canRead(const string& filepath) const; /**Gives a better estimation of whether the specified file * can be read or not depending on the file content*/ virtual bool canRead(ifstream& file) const; /**Reads a file * This method tries to read the file with the specified filepath * If it fails, either null is returned or an exception * is thrown */ virtual T* read(const string& filepath) const; /**Reads a file to an object * This method tries to read the file with the specified filepath * If it fails, either null is returned or an exception * is thrown */ virtual T* read(const string& filepath, T* object) const; /**Reads a file * This method tries to read the specified file * If it failes, either null is returned or an exception * Default implementation generates an object using T() * is thrown */ virtual T* read(ifstream& file, const string& path) const { T* obj = new T(); T* ret = read(file,path,obj); if (obj != ret) { delete obj; } return ret; } /**Reads a file onto the specified object * This method tries to read the specified file * If it failes, either null is returned or an exception * is thrown */ virtual T* read(ifstream& file, const string& path, T* former) const = 0; virtual ~FileReader() { /*for (typename vector const * >::const_iterator i = fileReaders.begin(); i != fileReaders.end(); ++i) { delete const_cast* >(*i); //Segfault }*/ }; //Well ... these objects aren't supposed to be destroyed }; template static inline T* readFromFileReaders(vector const *>* readers, const string& filepath) { for (typename vector const *>::const_iterator i = readers->begin(); i != readers->end(); ++i) { try { FileReader const * reader = *i; T* ret = reader->read(filepath); //It is guaranteed that at least the filepath matches ... if (ret != NULL) { return ret; } } catch (...) { //TODO: Specific exceptions } } return NULL; } template static inline T* readFromFileReaders(vector const *>* readers, const string& filepath, T* object) { for (typename vector const *>::const_iterator i = readers->begin(); i != readers->end(); ++i) { try { FileReader const * reader = *i; T* ret = reader->read(filepath, object); //It is guaranteed that at least the filepath matches ... if (ret != NULL) { return ret; } } catch (...) { //TODO: Specific exceptions } } std::cerr << "Could not parse filepath: " << filepath << std::endl; return NULL; } /**Tries to read a file * This method tries to read the file with the specified filepath. * If it fails, either null is returned or an exception * is thrown*/ template T* FileReader::readPath(const string& filepath) { const string& extension = extractExtension(filepath); vector const * >* possibleReaders = (getFileReadersMap())[extension]; if (possibleReaders != NULL) { //Search in these possible readers T* ret = readFromFileReaders(possibleReaders, filepath); if (ret != NULL) { return ret; } } T* ret = readFromFileReaders(&fileReaders, filepath); //Try all other return ret; } /**Tries to read a file * This method tries to read the file with the specified filepath. * If it fails, either null is returned or an exception * is thrown*/ template T* FileReader::readPath(const string& filepath, T* object) { const string& extension = extractExtension(filepath); vector const * >* possibleReaders = (getFileReadersMap())[extension]; if (possibleReaders != NULL) { //Search in these possible readers T* ret = readFromFileReaders(possibleReaders, filepath, object); if (ret != NULL) { return ret; } } T* ret = readFromFileReaders(&fileReaders, filepath, object); //Try all other return ret; } template vector const * > FileReader::fileReaders; template FileReader::FileReader(string const * extensions): extensions(extensions) { fileReaders.push_back(this); string const * nextExtension = extensions; while (((*nextExtension) != "")) { vector const* >* curPossibleReaders = (getFileReadersMap())[*nextExtension]; if (curPossibleReaders == NULL) { (getFileReadersMap())[*nextExtension] = (curPossibleReaders = new vector const *>()); } curPossibleReaders->push_back(this); ++nextExtension; } } /**Gives a quick estimation of whether the specified file * can be read or not depending on the filename*/ template bool FileReader::canRead(const string& filepath) const { const string& realExtension = extractExtension(filepath); const string* haveExtension = extensions; while (*haveExtension != "") { if (realExtension == *haveExtension) { return true; } ++haveExtension; } return false; } /**Gives a better estimation of whether the specified file * can be read or not depending on the file content*/ template bool FileReader::canRead(ifstream& file) const { try { T* wouldRead = read(file,"unknown file"); bool ret = (wouldRead != NULL); delete wouldRead; return ret; } catch (...) { return false; } } /**Reads a file * This method tries to read the file with the specified filepath * If it fails, either null is returned or an exception * is thrown */ template T* FileReader::read(const string& filepath) const { ifstream file(filepath.c_str(), ios::in | ios::binary); if (!file.is_open()) { //An error occured; TODO: Which one - throw an exception, print error message? throw runtime_error("Could not open file " + filepath); } return read(file,filepath); } /**Reads a file * This method tries to read the file with the specified filepath * If it fails, either null is returned or an exception * is thrown */ template T* FileReader::read(const string& filepath, T* object) const { ifstream file(filepath.c_str(), ios::in | ios::binary); if (!file.is_open()) { //An error occured; TODO: Which one - throw an exception, print error message? throw runtime_error("Could not open file " + filepath); } return read(file,filepath,object); } } //end namespace #endif