bool convertFile(FileData & fileData, const FS_NAMESPACE::path & commonHeaderPath, std::ofstream & outStream = badOfStream, bool addHeader = true) { if (FS_NAMESPACE::exists(fileData.inPath)) { // try to open the input file std::ifstream inStream; inStream.open(fileData.inPath.string(), std::ifstream::in | std::ifstream::binary); if (inStream.is_open() && inStream.good()) { if (beVerbose) { std::cout << "Converting input file " << fileData.inPath; } // try getting size of data inStream.seekg(0, std::ios::end); fileData.size = static_cast<uint64_t>(inStream.tellg()); inStream.seekg(0); // check if the caller passed and output stream and use that bool closeOutStream = false; if (!outStream.is_open() || !outStream.good()) { if (!fileData.outPath.empty()) { // try opening the output stream. truncate it when it exists outStream.open(fileData.outPath.string(), std::ofstream::out | std::ofstream::trunc); } else { std::cout << "Error: No output stream passed, but output path for \"" << fileData.inPath.filename().string() << "\" is empty! Skipping." << std::endl; return false; } closeOutStream = true; } // now write to stream if (outStream.is_open() && outStream.good()) { // check if caller want to add a header if (addHeader) { // add message outStream << "// this file was auto-generated from \"" << fileData.inPath.filename().string() << "\" by res2h" << std::endl << std::endl; // add header include if (!commonHeaderPath.empty()) { // common header path must be relative to destination directory FS_NAMESPACE::path relativeHeaderPath = naiveUncomplete(commonHeaderPath, fileData.outPath); outStream << "#include \"" << relativeHeaderPath.generic_string() << "\"" << std::endl << std::endl; } } // create names for variables fileData.dataVariableName = fileData.outPath.filename().stem().string() + "_data"; fileData.sizeVariableName = fileData.outPath.filename().stem().string() + "_size"; // add size and data variable if (fileData.size <= UINT16_MAX) { outStream << "const uint16_t "; } else if (fileData.size <= UINT32_MAX) { outStream << "const uint32_t "; } else { outStream << "const uint64_t "; } outStream << fileData.sizeVariableName << " = " << std::dec << fileData.size << ";" << std::endl; outStream << "const uint8_t " << fileData.dataVariableName << "[" << std::dec << fileData.size << "] = {" << std::endl; outStream << " "; // first indent // now add content uint64_t breakCounter = 0; while (!inStream.eof()) { // read byte from source unsigned char dataByte; inStream.read((char *)&dataByte, 1); // check if we have actually read something if (inStream.gcount() != 1 || inStream.eof()) { // we failed to read. break the read loop and close the file. break; } // write to destination in hex with a width of 2 and '0' as padding // we do not use showbase as it doesn't work with zero values outStream << "0x" << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)dataByte; // was this the last character? if (!inStream.eof() && fileData.size > static_cast<uint64_t>(inStream.tellg())) { // no. add comma. outStream << ","; // add break after 10 bytes and add indent again if (++breakCounter % 10 == 0) { outStream << std::endl << " "; } } } // close curly braces outStream << std::endl << "};" << std::endl << std::endl; // close files if (closeOutStream) { outStream.close(); } inStream.close(); if (beVerbose) { std::cout << " - succeeded." << std::endl; } return true; } else { std::cout << "Error: Failed to open file \"" << fileData.outPath.string() << "\" for writing!" << std::endl; return false; } } else { std::cout << "Error: Failed to open file \"" << fileData.inPath.string() << "\" for reading!" << std::endl; return false; } } else { std::cout << "Error: File \"" << fileData.inPath.string() << "\" does not exist!" << std::endl; } return false; }
int main(int argc, const char * argv[]) { printVersion(); // check number of arguments and if all arguments can be read if (argc < 3 || !readArguments(argc, argv)) { printUsage(); return -1; } // check if the input path exist if (!FS_NAMESPACE::exists(inFilePath)) { std::cout << "Error: Invalid input file/directory \"" << inFilePath.string() << "\"!" << std::endl; return -2; } if (createBinary) { // check if argument 2 is a file if (FS_NAMESPACE::is_directory(outFilePath)) { std::cout << "Error: Output must be a file if -b is used!" << std::endl; return -2; } } else if (appendFile) { // check if argument 2 is a file if (FS_NAMESPACE::is_directory(outFilePath)) { std::cout << "Error: Output must be a file if -a is used!" << std::endl; return -2; } } else if (FS_NAMESPACE::is_directory(inFilePath) != FS_NAMESPACE::is_directory(outFilePath)) { // check if output directory exists if (FS_NAMESPACE::is_directory(outFilePath) && !FS_NAMESPACE::exists(outFilePath)) { std::cout << "Error: Invalid output directory \"" << outFilePath.string() << "\"!" << std::endl; return -2; } // check if arguments 1 and 2 are both files or both directories std::cout << "Error: Input and output file must be both either a file or a directory!" << std::endl; return -2; } if (appendFile) { // append file a to b if (!appendAtoB(outFilePath, inFilePath)) { std::cout << "Error: Failed to append data to executable!" << std::endl; return -3; } } else { // build list of files to process std::vector<FileData> fileList; if (FS_NAMESPACE::is_directory(inFilePath) && FS_NAMESPACE::is_directory(inFilePath)) { // both files are directories, build file ist fileList = getFileDataFrom(inFilePath, outFilePath, inFilePath, useRecursion); if (fileList.empty()) { std::cout << "Error: No files to convert!" << std::endl; return -3; } } else { // just add single input/output file FileData temp; temp.inPath = inFilePath; temp.outPath = outFilePath; temp.internalName = inFilePath.filename().string(); // remove all, but the file name and extension if (beVerbose) { std::cout << "Found input file " << inFilePath << std::endl; std::cout << "Internal name will be \"" << temp.internalName << "\"" << std::endl; std::cout << "Output path is " << temp.outPath << std::endl; } // get file size try { temp.size = static_cast<uint64_t>(FS_NAMESPACE::file_size(inFilePath)); if (beVerbose) { std::cout << "Size is " << temp.size << " bytes." << std::endl; } } catch (...) { std::cout << "Error: Failed to get size of " << inFilePath << "!" << std::endl; temp.size = 0; } fileList.push_back(temp); } // does the user want an binary file? if (createBinary) { // yes. build it. if (!createBlob(fileList, outFilePath)) { std::cout << "Error: Failed to convert to binary file!" << std::endl; return -4; } } else { // no. convert files to .c/.cpp. loop through list, converting files for (auto fdIt = fileList.begin(); fdIt != fileList.cend(); ++fdIt) { if (!convertFile(*fdIt, commonHeaderFilePath)) { std::cout << "Error: Failed to convert all files. Aborting!" << std::endl; return -4; } } // do we need to write a header file? if (!commonHeaderFilePath.empty()) { if (!createCommonHeader(fileList, commonHeaderFilePath, !utilitiesFilePath.empty(), useC)) { return -5; } // do we need to create utilities? if (!utilitiesFilePath.empty()) { if (!createUtilities(fileList, utilitiesFilePath, commonHeaderFilePath, useC, combineResults)) { return -6; } } } } } // if (!appendFile) { // profit!!! std::cout << "res2h succeeded." << std::endl; return 0; }
bool readArguments(int argc, const char * argv[]) { bool pastFiles = false; for (int i = 1; i < argc; ++i) { // read argument from list std::string argument = argv[i]; // check what it is if (argument == "-a") { if (!commonHeaderFilePath.empty() || !utilitiesFilePath.empty()) { std::cout << "Error: Option -a can not be combined with -h or -u!" << std::endl; return false; } else if (createBinary) { std::cout << "Error: Option -a can not be combined with -b!" << std::endl; return false; } else if (combineResults) { std::cout << "Error: Option -a can not be combined with -1!" << std::endl; return false; } appendFile = true; pastFiles = true; } else if (argument == "-1") { // -u must be used for this to work. check if specified for (int j = 1; j < argc; ++j) { // read argument from list std::string argument = argv[j]; if (argument == "-u") { combineResults = true; pastFiles = true; break; } } if (!combineResults) { // -u not specified. complain to user. std::cout << "Error: Option -1 has to be combined with -u!" << std::endl; return false; } } else if (argument == "-b") { if (!commonHeaderFilePath.empty() || !utilitiesFilePath.empty()) { std::cout << "Error: Option -b can not be combined with -h or -u!" << std::endl; return false; } else if (appendFile) { std::cout << "Error: Option -b can not be combined with -a!" << std::endl; return false; } else if (combineResults) { std::cout << "Warning: Creating binary archive. Option -1 ignored!" << std::endl; return false; } createBinary = true; pastFiles = true; } else if (argument == "-c") { useC = true; pastFiles = true; } else if (argument == "-s") { useRecursion = true; pastFiles = true; } else if (argument == "-v") { beVerbose = true; pastFiles = true; } else if (argument == "-h") { if (createBinary) { std::cout << "Error: Option -h can not be combined with -b!" << std::endl; return false; } else if (appendFile) { std::cout << "Error: Option -h can not be combined with -a!" << std::endl; return false; } // try getting next argument as header file name i++; if (i < argc && argv[i] != nullptr) { if (!makeCanonical(commonHeaderFilePath, FS_NAMESPACE::path(argv[i]))) { return false; } } else { std::cout << "Error: Option -h specified, but no file name found!" << std::endl; return false; } pastFiles = true; } else if (argument == "-u") { if (createBinary) { std::cout << "Error: Option -u can not be combined with -b!" << std::endl; return false; } else if (appendFile) { std::cout << "Error: Option -u can not be combined with -a!" << std::endl; return false; } // try getting next argument as utility file name i++; if (i < argc && argv[i] != nullptr) { if (!makeCanonical(utilitiesFilePath, FS_NAMESPACE::path(argv[i]))) { return false; } } else { std::cout << "Error: Option -u specified, but no file name found!" << std::endl; return false; } if (!utilitiesFilePath.empty() && commonHeaderFilePath.empty()) { std::cout << "Warning: -u does not make much sense without -h..." << std::endl; } pastFiles = true; } // none of the options was matched until here... else if (!pastFiles) { // if no files/directories have been found yet this is probably a file/directory if (inFilePath.empty()) { if (!makeCanonical(inFilePath, FS_NAMESPACE::path(argument))) { return false; } } else if (outFilePath.empty()) { if (!makeCanonical(outFilePath, FS_NAMESPACE::path(argument))) { return false; } pastFiles = true; } } else { std::cout << "Error: Unknown argument \"" << argument << "\"!" << std::endl; return false; } } return true; }