#include "ResourceCompiler.h" ResourceCompiler::ResourceCompiler(const string inputFilename, const string outputFilename) { m_ResourceSpecFile = inputFilename; m_ResourceCodeFile = outputFilename; } ResourceCompiler::~ResourceCompiler() { } void ResourceCompiler::compile() { // parse input file (resource <-> file mapping) parseInputFile(); // load the binary files (resource <-> data mapping) loadBinaryData(); // temporary variables ostringstream resourceIdentifierInitializer; ostringstream resourceIndexInitializer; ostringstream resourceStorageInitializer; map<string, vector<unsigned char> >::iterator mapPos; vector<unsigned char>::iterator dataPos; unsigned int currentIndex = 0; // store total amount of resources resourceIndexInitializer << "{0x" << hex << m_ResourceDataMap.size() << ", 0x0},"; // iterate over all resource data mappings we have for(mapPos = m_ResourceDataMap.begin(); mapPos != m_ResourceDataMap.end(); ++mapPos) { // store identifier resourceIdentifierInitializer << "\"" << mapPos->first << "\","; // store data base index resourceIndexInitializer << "{0x" << hex << currentIndex << ","; resourceIndexInitializer << "0x" << hex << mapPos->second.size() << "},"; currentIndex += mapPos->second.size(); // iterate over the data content byte by byte for(dataPos = mapPos->second.begin(); dataPos != mapPos->second.end(); ++dataPos) { // store byte value as part of array initializer resourceStorageInitializer << "0x" << hex << (int)*dataPos << ","; } } // open the output code file ofstream outputFile(m_ResourceCodeFile.c_str(), ios::out); if(!outputFile) { cerr << "Couldn't open output file \"" << m_ResourceCodeFile << "\"!" << endl, exit(1); } // let's get some exceptions outputFile.exceptions(ios::failbit | ios::badbit); try { // write header outputFile << "#include <string>" << endl << endl; // write code file contents (remove trailing commas) string output = resourceIdentifierInitializer.str(); outputFile << "extern const std::string c_ResourceIdentifiers[] = {" << endl; outputFile << output.substr(0, output.length() - 1); outputFile << endl << "};" << endl << endl; output = resourceIndexInitializer.str(); outputFile << "extern const unsigned int c_ResourceIndex[][2] = {" << endl; outputFile << output.substr(0, output.length() - 1); outputFile << endl << "};" << endl << endl; output = resourceStorageInitializer.str(); outputFile << "extern const unsigned char c_ResourceStorage[] = {" << endl; outputFile << output.substr(0, output.length() - 1); outputFile << endl << "};" << endl << endl; } catch(const ios::failure& error) { cerr << "Error during output file processing: " << error.what() << endl; } // clean up and clode file outputFile.flush(); outputFile.close(); } void ResourceCompiler::parseInputFile() { // open input file ifstream inputFile(m_ResourceSpecFile.c_str(), ios::in); if(!inputFile) { cerr << "Couldn't open input file \"" << m_ResourceSpecFile << "\"!" << endl, exit(1); } // let's get some exceptions inputFile.exceptions(ios::failbit | ios::badbit); try { string line; // read input file line by line while(getline(inputFile, line)) { unsigned int firstCharacter = line.find_first_not_of(" \t\r\n\f"); // we (sort of) allow for empty lines and comments if(firstCharacter != string::npos && line.substr(firstCharacter, 1) != "#") { // find our token delimiter unsigned int separator = line.find("|"); // make sure there's exactly one delimiter if(separator == string::npos || separator != line.rfind("|")) { cerr << "Unexpected resource specification: " << line << endl; } else { // store tokens in resource file map m_ResourceFileMap[line.substr(0, separator)] = line.substr(separator + 1); } } } } catch(const ios::failure& error) { // check stream state for real error if(!inputFile.eof()) { cerr << "Error during input file processing: " << error.what(); } } // close input file inputFile.close(); } void ResourceCompiler::loadBinaryData() { map<string, string>::iterator pos; // iterate over all resource file mappings we have for(pos = m_ResourceFileMap.begin(); pos != m_ResourceFileMap.end(); ++pos) { // open given resource file ifstream binaryFile(pos->second.c_str(), ios::in | ios::binary); if(!binaryFile) { cerr << "Couldn't open binary file \"" << pos->second << "\"!" << endl, exit(1); } // let's get some exceptions binaryFile.exceptions(ios::failbit | ios::badbit); try { // store binary resource file using stream iterators // copy( istream_iterator<unsigned char>(binaryFile), // istream_iterator<unsigned char>(), // back_inserter(m_ResourceDataMap[pos->first]) // ); // "copy" ends prematurely, so use the crude way instead char c = 0; while(binaryFile.get(c)) { m_ResourceDataMap[pos->first].push_back(c); } } catch(const ios::failure& error) { // check stream state for real error if(!binaryFile.eof()) { cerr << "Error during binary file processing: " << error.what(); } } // close current file binaryFile.close(); } }