// ============================================================== // 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 #include #include #include "leak_dumper.h" using std::map; using std::string; using std::vector; using std::ifstream; using std::ios; using std::runtime_error; using Shared::PlatformCommon::extractExtension; #define AS_STRING(...) #__VA_ARGS__ namespace Shared{ // ===================================================== // class FileReader // ===================================================== template class FileReader { public: //string const * extensions; std::vector extensions; /**Creates a filereader being able to possibly load files * from the specified extension **/ //FileReader(string const * extensions); FileReader(std::vector extensions); /**Creates a low-priority filereader **/ FileReader(); public: /*Return the - existing and initialized - fileReadersMap */ static map const * >* >& getFileReadersMap() { static map const * >* > fileReaderByExtension; return fileReaderByExtension; } static vector const * >& getFileReaders() { static vector const*> fileReaders; return fileReaders; }; static vector const * >& getLowPriorityFileReaders() { static vector const*> lowPriorityFileReaders; return lowPriorityFileReaders; }; 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) { //try to assign file 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); } for (typename vector const *>::const_iterator i = readers->begin(); i != readers->end(); ++i) { T* ret = NULL; file.seekg(0, ios::beg); //Set position to first try { FileReader const * reader = *i; ret = reader->read(file, filepath); //It is guaranteed that at least the filepath matches ... } catch (...) { //TODO: Specific exceptions continue; } if (ret != NULL) { return ret; } } return NULL; } template static inline T* readFromFileReaders(vector const *>* readers, const string& filepath, T* object) { //try to assign file 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); } for (typename vector const *>::const_iterator i = readers->begin(); i != readers->end(); ++i) { T* ret = NULL; file.seekg(0, ios::beg); //Set position to first try { FileReader const * reader = *i; ret = reader->read(file, filepath, object); //It is guaranteed that at least the filepath matches ... } catch (...) { //TODO: Specific exceptions continue; } if (ret != NULL) { return ret; } } 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(&(getFileReaders()), filepath); //Try all other if (ret == NULL) { std::cerr << "Could not parse filepath: " << filepath << std::endl; ret = readFromFileReaders(&(getLowPriorityFileReaders()), filepath); //Try to get dummy file } 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(&(getFileReaders()), filepath, object); //Try all other if (ret == NULL) { std::cerr << "Could not parse filepath: " << filepath << std::endl; ret = readFromFileReaders(&(getLowPriorityFileReaders()), filepath); //Try to get dummy file if (ret == NULL) { throw runtime_error(string("Could not parse ") + filepath + " as object of type " + typeid(T).name()); } } return ret; } template FileReader::FileReader(std::vector extensions): extensions(extensions) { getFileReaders().push_back(this); //string const * nextExtension = extensions; std::vector nextExtension = extensions; //while (((*nextExtension) != "")) { for(int i = 0; i < nextExtension.size(); ++i) { //vector const* >* curPossibleReaders = (getFileReadersMap())[*nextExtension]; vector const* >* curPossibleReaders = (getFileReadersMap())[nextExtension[i]]; if (curPossibleReaders == NULL) { //(getFileReadersMap())[*nextExtension] = (curPossibleReaders = new vector const *>()); (getFileReadersMap())[nextExtension[i]] = (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; std::vector haveExtension = extensions; //while (*haveExtension != "") { for(int i = 0; i < haveExtension.size(); ++i) { //if (realExtension == *haveExtension) { if (realExtension == haveExtension[i]) { 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