#include <map>
#include <string>
#include <vector>
#include <fstream>
using std::map;
using std::string;
using std::vector;
using std::ifstream;
using std::ios;
char directoryChar = '/';
string getExtension(const string& filepath) {
size_t lastPoint = filepath.find_last_of('.');
size_t lastDirectory = filepath.find_last_of(directoryChar);
if (lastPoint == string::npos || (lastDirectory != string::npos && lastDirectory > lastPoint)) {
return "";
}
return filepath.substr(lastPoint+1);
}
template <class T>
class FileReader {
protected:
/**Creates a filereader being able to possibly load files
* from the specified extension
**/
FileReader(char** extensions) {
fileReaders.push_back(this);
char** nextExtension = extensions;
while (nextExtension != NULL) {
string extensionString(*nextExtension);
vector<FileReader<T> const * const>* curPossibleReaders = fileReaderByExtension[extensionString];
if (curPossibleReaders == NULL) {
fileReaderByExtension[extensionString] = (curPossibleReaders = new vector<FileReader<T> const * const>(1));
}
curPossibleReaders->push_back(this);
nextExtension = ++nextExtension;
}
}
FileReader() {
fileReaders.push_back(this);
}
private:
static map<string, vector<FileReader<T> const * const>* > fileReaderByExtension;
static vector<FileReader<T> const * const> fileReaders;
static inline T* readFromFileReaders(vector<FileReader<T> const * const>* readers, const string& filepath) {
for (vector<FileReader<T> const * const>::const_iterator i = readers->begin(); i != readers->end(); ++i) {
try {
FileReader<T> const * 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;
}
public:
/**Tries to read a file
* This method tries to read the file with the specified filepath.
* If it fails, either <code>null</code> is returned or an exception
* is thrown*/
static T* readPath(const string& filepath) {
const string& extension = getExtension(filepath);
vector<FileReader<T> const * const>* possibleReaders = fileReaderByExtension(filepath);
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;
}
/**Reads a file
* This method tries to read the file with the specified filepath
* If it fails, either <code>null</code> is returned or an exception
* is thrown
*/
virtual T* read(const string& filepath) const {
ifstream file(filepath, ios::in | ios::binary);
if (!file.is_open()) { //An error occured; TODO: Which one - throw an exception, print error message?
return NULL;
}
return read(file);
}
/**Reads a file
* This method tries to read the specified file
* If it failes, either <code>null</code> is returned or an exception
* is thrown
*/
virtual T* read(const ifstream& file) const = 0;
virtual ~FileReader() {
for (vector<FileReader<T> const * const>::const_iterator i = fileReaders.begin(); i != fileReaders.end(); ++i) {
delete const_cast<FileReader<T>* >(*i);
}
}; //Well ... these objects aren't supposed to be destroyed
};