예제 #1
0
bool appendAtoB(const FS_NAMESPACE::path & destinationPath, const FS_NAMESPACE::path & sourcePath)
{
	// try opening the output file.
	std::fstream outStream;
	outStream.open(destinationPath.string(), std::ofstream::out | std::ofstream::binary | std::ofstream::app);
	if (outStream.is_open() && outStream.good())
	{
		if (beVerbose)
		{
			std::cout << std::endl << "Opened output file " << destinationPath << std::endl;
		}
		// seek to the end
		outStream.seekg(0, std::ios::end);
		// open input file
		std::ifstream inStream;
		inStream.open(sourcePath.string(), std::ifstream::in | std::ifstream::binary);
		if (inStream.is_open() && inStream.good())
		{
			if (beVerbose)
			{
				std::cout << "Opened input file \"" << sourcePath << "\". Appending data to output." << std::endl;
			}
			// copy data from input to output file
			while (!inStream.eof() && inStream.good())
			{
				unsigned char buffer[1024];
				std::streamsize readSize = sizeof(buffer);
				try
				{
					// try reading data from input file
					inStream.read(reinterpret_cast<char *>(&buffer), sizeof(buffer));
				}
				catch (std::ios_base::failure) { /*ignore read failure. salvage what we can.*/ }
				// store how many bytes were actually read
				readSize = inStream.gcount();
				// write to output file
				outStream.write(reinterpret_cast<const char *>(&buffer), readSize);
			}
			// close input file
			inStream.close();
		}
		else
		{
			std::cout << "Error: Failed to open input file \"" << sourcePath.string() << "\" for reading!" << std::endl;
			outStream.close();
			return false;
		}
		// close output file
		outStream.close();
		return true;
	}
	else
	{
		std::cout << "Error: Failed to open output file \"" << destinationPath.string() << "\" for writing!" << std::endl;
	}
	return false;
}
예제 #2
0
bool makeCanonical(FS_NAMESPACE::path & result, const FS_NAMESPACE::path & path)
{
	// if we use canonical the file must exits, else we get an exception.
	try
	{
		result = FS_NAMESPACE::canonical(path);
	}
	catch (...)
	{
		// an error occurred. this maybe because the file is not there yet. try without the file name
		try
		{
			result = FS_NAMESPACE::canonical(FS_NAMESPACE::path(path).remove_filename());
			// ok. this worked. add file name again
			result /= path.filename();
		}
		catch (...)
		{
			// hmm. didn't work. tell the user. at least the path should be there...
			std::cout << "The path \"" << FS_NAMESPACE::path(path).remove_filename().string() << "\" couldn't be found. Please create it." << std::endl;
			return false;
		}
	}
	return true;
}
예제 #3
0
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;
}
예제 #4
0
// Blob archive file format:
// Offset               | Type                | Description
// ---------------------+---------------------+-------------------------------------------
// START OF DATA        | char[8]             | magic number string "res2hbin"
// 08                   | uint32_t            | file format version number (currently 2)
// 12                   | uint32_t            | format flags. The lower 8 bit state the bit depth of the archive (32/64)
// 16                   | uint32_t / uint64_t | size of whole archive including checksum in bytes
// 20/24                | uint32_t            | number of directory and file entries following
// Then follows the directory:
// 24/28 + 00           | uint16_t            | file entry #0, size of internal name WITHOUT null-terminating character
// 24/28 + 02           | char[]              | file entry #0, internal name (NOT null-terminated)
// 24/28 + 02 + name    | uint32_t            | file entry #0, format flags for entry (currently 0)
// 24/28 + 06 + name    | uint32_t / uint64_t | file entry #0, size of data
// 24/28 + 10/14 + name | uint32_t / uint64_t | file entry #0, absolute offset of data in file
// 24/28 + 14/22 + name | uint32_t / uint64_t | file entry #0, Fletcher32/64 checksum of data
// Then follow other directory entries. There is some redundant information here, but that's for reading stuff faster.
// Directly after the directory the data blocks begin.
// END - 04/08       | uint32_t / uint64_t | Fletcher32/64 checksum of whole file up to this point
// Obviously with a 32bit archive you're limited to ~4GB for the whole binary file and ~4GB per data entry.
// Res2h will automagically create a 32bit archive, if data permits it, or a 64bit archive if needed.
bool createBlob(const std::vector<FileData> & fileList, const FS_NAMESPACE::path & filePath)
{
	// try opening the output file. truncate it when it exists
	std::fstream outStream;
	outStream.open(filePath.string(), std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
	if (outStream.is_open() && outStream.good())
	{
		const uint32_t nrOfEntries = static_cast<uint32_t>(fileList.size());
		// check if a 64bit archive is needed, or 32bit suffice
		uint64_t directorySize = 0;
		uint64_t maxDataSize = 0;
		uint64_t dataSize = 0;
		for (const auto & file : fileList)
		{
			dataSize += file.size;
			maxDataSize = maxDataSize < file.size ? file.size : maxDataSize;
			directorySize += file.internalName.size();
		}
		// now take worst case header and fixed directory size into account and check if we need 32 or 64 bit
		const bool mustUse64Bit = maxDataSize > UINT32_MAX || (RES2H_HEADER_SIZE_64 + directorySize + nrOfEntries * RES2H_DIRECTORY_SIZE_64 + dataSize + sizeof(uint64_t)) > UINT32_MAX;
		if (beVerbose)
		{
			std::cout << std::endl << "Creating binary " << (mustUse64Bit ? "64" : "32") << "bit archive " << filePath << std::endl;
		}
		// now that we know how many bits, add the correct amount of data for the fixed directory entries to the variable
		directorySize += nrOfEntries * (mustUse64Bit ? RES2H_DIRECTORY_SIZE_64 : RES2H_DIRECTORY_SIZE_32);
		// add magic number to file
		const unsigned char magicBytes[9] = RES2H_MAGIC_BYTES;
		outStream.write(reinterpret_cast<const char *>(&magicBytes), sizeof(magicBytes) - 1);
		// add version and format flag to file
		const uint32_t fileVersion = RES2H_ARCHIVE_VERSION;
		const uint32_t fileFlags = mustUse64Bit ? 64 : 32;
		outStream.write(reinterpret_cast<const char *>(&fileVersion), sizeof(uint32_t));
		outStream.write(reinterpret_cast<const char *>(&fileFlags), sizeof(uint32_t));
		// add dummy archive size to file
		uint64_t archiveSize = 0;
		outStream.write(reinterpret_cast<const char *>(&archiveSize), (mustUse64Bit ? sizeof(uint64_t) : sizeof(uint32_t)));
		// add number of directory entries to file
		outStream.write(reinterpret_cast<const char *>(&nrOfEntries), sizeof(uint32_t));
		// calculate data start offset behind directory
		uint64_t dataStart = mustUse64Bit ? RES2H_HEADER_SIZE_64 : RES2H_HEADER_SIZE_32;
		dataStart += directorySize;
		// add directory for all files
		for (const auto & file : fileList)
		{
			// add size of name
			if (file.internalName.size() > UINT16_MAX)
			{
				std::cout << "Error: File name \"" << file.internalName << "\" is too long!" << std::endl;
				outStream.close();
				return false;
			}
			const uint16_t nameSize = static_cast<uint16_t>(file.internalName.size());
			outStream.write(reinterpret_cast<const char *>(&nameSize), sizeof(uint16_t));
			// add name
			outStream.write(reinterpret_cast<const char *>(&file.internalName[0]), nameSize);
			// add flags
			const uint32_t entryFlags = 0;
			outStream.write(reinterpret_cast<const char *>(&entryFlags), sizeof(uint32_t));
			uint64_t fileChecksum = mustUse64Bit ? calculateFletcher<uint64_t>(file.inPath.string()) : calculateFletcher<uint32_t>(file.inPath.string());
			// add data size, offset from file start to start of data and checksum
			outStream.write(reinterpret_cast<const char *>(&file.size), (mustUse64Bit ? sizeof(uint64_t) : sizeof(uint32_t)));
			outStream.write(reinterpret_cast<const char *>(&dataStart), (mustUse64Bit ? sizeof(uint64_t) : sizeof(uint32_t)));
			outStream.write(reinterpret_cast<const char *>(&fileChecksum), (mustUse64Bit ? sizeof(uint64_t) : sizeof(uint32_t)));
			if (beVerbose)
			{
				std::cout << "Creating directory entry for \"" << file.internalName << "\"" << std::endl;
				std::cout << "Data starts at " << std::dec << std::showbase << dataStart << " bytes" << std::endl;
				std::cout << "Size is " << std::dec << file.size << " bytes" << std::endl;
				std::cout << "Fletcher" << (mustUse64Bit ? "64" : "32") << " checksum is " << std::hex << std::showbase << fileChecksum << std::endl;
			}
			// now add size of this entries data to start offset for next data block
			dataStart += file.size;
		}
		// add data for all files		
		for (const auto & file : fileList)
		{
			// try to open file
			std::ifstream inStream;
			inStream.open(file.inPath.string(), std::ifstream::in | std::ifstream::binary);
			if (inStream.is_open() && inStream.good())
			{
				if (beVerbose)
				{
					std::cout << "Adding data for \"" << file.internalName << "\"" << std::endl;
				}
				std::streamsize overallDataSize = 0;
				// copy data from input to output file
				while (!inStream.eof() && inStream.good())
				{
					unsigned char buffer[4096];
					std::streamsize readSize = sizeof(buffer);
					try
					{
						// try reading data from input file
						inStream.read(reinterpret_cast<char *>(&buffer), sizeof(buffer));
					}
					catch (std::ios_base::failure) { /*ignore read failure. salvage what we can.*/ }
					// store how many bytes were actually read
					readSize = inStream.gcount();
					// write to output file
					outStream.write(reinterpret_cast<const char *>(&buffer), readSize);
					// increase size of overall data read
					overallDataSize += readSize;
				}
				// close input file
				inStream.close();
				// check if the file was completely read
				if (overallDataSize != file.size)
				{
					std::cout << "Error: Failed to completely copy file \"" << file.inPath.string() << "\" to binary data!" << std::endl;
					outStream.close();
					return false;
				}
			}
			else
			{
				std::cout << "Error: Failed to open file \"" << file.inPath.string() << "\" for reading!" << std::endl;
				outStream.close();
				return false;
			}
		}
		// final archive size is current size + checksum. write size to the header now
		archiveSize = static_cast<uint64_t>(outStream.tellg()) + (mustUse64Bit ? sizeof(uint64_t) : sizeof(uint32_t));
		outStream.seekg(RES2H_OFFSET_ARCHIVE_SIZE);
		outStream.write(reinterpret_cast<const char *>(&archiveSize), (mustUse64Bit ? sizeof(uint64_t) : sizeof(uint32_t)));
		// close file
		outStream.close();
		if (beVerbose)
		{
			std::cout << "Binary archive creation succeeded." << std::endl;
			std::cout << "Archive has " << std::dec << archiveSize << " bytes." << std::endl;
		}
		// calculate checksum of whole file
		const uint64_t checksum = mustUse64Bit ? calculateFletcher<uint64_t>(filePath.string()) : calculateFletcher<uint32_t>(filePath.string());
		// open file again, move to end of file and append checksum
		outStream.open(filePath.string(), std::ofstream::out | std::ofstream::binary | std::ofstream::app);
		if (outStream.is_open() && outStream.good())
		{
			outStream.seekg(0, std::ios::end);
			outStream.write(reinterpret_cast<const char *>(&checksum), (mustUse64Bit ? sizeof(uint64_t) : sizeof(uint32_t)));
			// close file
			outStream.close();
		}
		else
		{
			std::cout << "Error: Failed to open file \"" << filePath.string() << "\" for writing!" << std::endl;
			return false;
		}
		if (beVerbose)
		{
			std::cout << "Archive Fletcher" << (mustUse64Bit ? "64" : "32") << " checksum is " << std::hex << std::showbase << checksum << "." << std::endl;
		}
		return true;
	}
	else
	{
		std::cout << "Error: Failed to open file \"" << filePath.string() << "\" for writing!" << std::endl;
		return false;
	}
	return false;
}
예제 #5
0
bool createCommonHeader(const std::vector<FileData> & fileList, const FS_NAMESPACE::path & commonHeaderPath, bool addUtilityFunctions = false, bool useCConstructs = false)
{
	// try opening the output file. truncate it when it exists
	std::ofstream outStream;
	outStream.open(commonHeaderPath.generic_string(), std::ofstream::out | std::ofstream::trunc);
	if (outStream.is_open() && outStream.good())
	{
		if (beVerbose)
		{
			std::cout << std::endl << "Creating common header " << commonHeaderPath;
		}
		// add message
		outStream << "// this file was auto-generated by res2h" << std::endl << std::endl;
		// add #pragma to only include once
		outStream << "#pragma once" << std::endl << std::endl;
		// add includes for C++
		if (!useCConstructs)
		{
			outStream << "#include <string>" << std::endl;
			if (addUtilityFunctions)
			{
				outStream << "#include <map>" << std::endl;
			}
			outStream << std::endl;
		}
		// add all files and check maximum size
		uint64_t maxSize = 0;
		for (auto fdIt = fileList.cbegin(); fdIt != fileList.cend(); ++fdIt)
		{
			// add size and data variable
			maxSize = maxSize < fdIt->size ? fdIt->size : maxSize;
			if (fdIt->size <= UINT16_MAX)
			{
				outStream << "extern const uint16_t ";
			}
			else if (fdIt->size <= UINT32_MAX)
			{
				outStream << "extern const uint32_t ";
			}
			else
			{
				outStream << "extern const uint64_t ";
			}
			outStream << fdIt->sizeVariableName << ";" << std::endl;
			outStream << "extern const uint8_t " << fdIt->dataVariableName << "[];" << std::endl << std::endl;
		}
		// if we want utilities, add array
		if (addUtilityFunctions)
		{
			// add resource struct
			outStream << "struct Res2hEntry {" << std::endl;
			if (useCConstructs)
			{
				outStream << "    const char * relativeFileName;" << std::endl;
			}
			else
			{
				outStream << "    const std::string relativeFileName;" << std::endl;
			}
			//  add size member depending on the determined maximum file size
			if (maxSize <= UINT16_MAX)
			{
				outStream << "    const uint16_t size;" << std::endl;
			}
			else if (maxSize <= UINT32_MAX)
			{
				outStream << "    const uint32_t size;" << std::endl;
			}
			else
			{
				outStream << "    const uint64_t size;" << std::endl;
			}
			outStream << "    const uint8_t * data;" << std::endl;
			outStream << "};" << std::endl << std::endl;
			// add list holding files
			outStream << "extern const uint32_t res2hNrOfFiles;" << std::endl;
			outStream << "extern const Res2hEntry res2hFiles[];" << std::endl << std::endl;
			if (!useCConstructs)
			{
				// add additional std::map if C++
				outStream << "typedef const std::map<const std::string, const Res2hEntry> res2hMapType;" << std::endl;
				outStream << "extern res2hMapType res2hMap;" << std::endl;
			}
		}
		// close file
		outStream.close();
		if (beVerbose)
		{
			std::cout << " - succeeded." << std::endl;
		}
		return true;
	}
	else
	{
		std::cout << "Error: Failed to open file \"" << commonHeaderPath << "\" for writing!" << std::endl;
	}
	return true;
}
예제 #6
0
bool createUtilities(std::vector<FileData> & fileList, const FS_NAMESPACE::path & utilitiesPath, const FS_NAMESPACE::path & commonHeaderPath, bool useCConstructs = false, bool addFileData = false)
{
	// try opening the output file. truncate it when it exists
	std::ofstream outStream;
	outStream.open(utilitiesPath.generic_string(), std::ofstream::out | std::ofstream::trunc);
	if (outStream.is_open() && outStream.good())
	{
		if (beVerbose)
		{
			std::cout << std::endl << "Creating utilities file " << utilitiesPath;
		}
		// add message
		outStream << "// this file was auto-generated by res2h" << std::endl << std::endl;
		// create path to include file RELATIVE to this file
		FS_NAMESPACE::path relativePath = naiveUncomplete(commonHeaderPath, utilitiesPath);
		// include header file
		outStream << "#include \"" << relativePath.string() << "\"" << std::endl << std::endl;
		// if the data should go to this file too, add it
		if (addFileData)
		{
			for (auto fdIt = fileList.begin(); fdIt != fileList.cend(); ++fdIt)
			{
				if (!convertFile(*fdIt, commonHeaderFilePath, outStream, false))
				{
					std::cout << "Error: Failed to convert all files. Aborting!" << std::endl;
					outStream.close();
					return false;
				}
			}
		}
		// begin data arrays. switch depending whether C or C++
		outStream << "const uint32_t res2hNrOfFiles = " << fileList.size() << ";" << std::endl;
		// add files
		outStream << "const Res2hEntry res2hFiles[res2hNrOfFiles] = {" << std::endl;
		outStream << "    "; // first indent
		for (auto fdIt = fileList.cbegin(); fdIt != fileList.cend();)
		{
			outStream << "{\"" << fdIt->internalName << "\", " << fdIt->sizeVariableName << ", " << fdIt->dataVariableName << "}";
			// was this the last entry?
			++fdIt;
			if (fdIt != fileList.cend())
			{
				// no. add comma.
				outStream << ",";
				// add break after every entry and add indent again
				outStream << std::endl << "    ";
			}
		}
		outStream << std::endl << "};" << std::endl;
		if (!useCConstructs)
		{
			// add files to map
			outStream << std::endl << "res2hMapType::value_type mapTemp[] = {" << std::endl;
			outStream << "    ";
			for (auto fdIt = fileList.cbegin(); fdIt != fileList.cend();)
			{
				outStream << "std::make_pair(\"" << fdIt->internalName << "\", res2hFiles[" << (fdIt - fileList.cbegin()) << "])";
				// was this the last entry?
				++fdIt;
				if (fdIt != fileList.cend())
				{
					// no. add comma.
					outStream << ",";
					// add break after every entry and add indent again
					outStream << std::endl << "    ";
				}
			}
			outStream << std::endl << "};" << std::endl << std::endl;
			// create map
			outStream << "res2hMapType res2hMap(mapTemp, mapTemp + sizeof mapTemp / sizeof mapTemp[0]);" << std::endl;
		}
		// close file
		outStream.close();
		if (beVerbose)
		{
			std::cout << " - succeeded." << std::endl;
		}
		return true;
	}
	else
	{
		std::cout << "Error: Failed to open file \"" << utilitiesPath << "\" for writing!" << std::endl;
	}
	return true;
}
예제 #7
0
// This is based on the example code found here: https:// svn.boost.org/trac/boost/ticket/1976
// but changed to not return a trailing ".." when paths only differ in their file name.
// The function still seems to be missing in boost as of 1.54.0.
FS_NAMESPACE::path naiveUncomplete(FS_NAMESPACE::path const path, FS_NAMESPACE::path const base)
{
	if (path.has_root_path())
	{
		if (path.root_path() != base.root_path())
		{
			return path;
		}
		else
		{
			return naiveUncomplete(path.relative_path(), base.relative_path());
		}
	}
	else
	{
		if (base.has_root_path())
		{
			return path;
		}
		else
		{
			auto path_it = path.begin();
			auto base_it = base.begin();
			while (path_it != path.end() && base_it != base.end())
			{
				if (*path_it != *base_it) break;
				++path_it; ++base_it;
			}
			FS_NAMESPACE::path result;
			// check if we're at the filename of the base path already
			if (*base_it != base.filename())
			{
				// add trailing ".." from path to base, but only if we're not already at the filename of the base path
				for (; base_it != base.end() && *base_it != base.filename(); ++base_it)
				{
					result /= "..";
				}
			}
			for (; path_it != path.end(); ++path_it)
			{
				result /= *path_it;
			}
			return result;
		}
	}
	return path;
}
예제 #8
0
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;
}
예제 #9
0
std::vector<FileData> getFileDataFrom(const FS_NAMESPACE::path & inPath, const FS_NAMESPACE::path & outPath, const FS_NAMESPACE::path & parentDir, const bool recurse)
{
	// get all files from directory
	std::vector<FileData> files;
	// check for infinite symlinks
	if (FS_NAMESPACE::is_symlink(inPath))
	{
		// check if the symlink points somewhere in the path. this would recurse
		if (inPath.string().find(FS_NAMESPACE::canonical(inPath).string()) == 0)
		{
			std::cout << "Warning: Path " << inPath << " contains recursive symlink! Skipping." << std::endl;
			return files;
		}
	}
	// iterate through source directory searching for files
	const FS_NAMESPACE::directory_iterator dirEnd;
	for (FS_NAMESPACE::directory_iterator fileIt(inPath); fileIt != dirEnd; ++fileIt)
	{
		FS_NAMESPACE::path filePath = (*fileIt).path();
		if (!FS_NAMESPACE::is_directory(filePath))
		{
			if (beVerbose)
			{
				std::cout << "Found input file " << filePath << std::endl;
			}
			// add file to list
			FileData temp;
			temp.inPath = filePath;
			// replace dots in file name with '_' and add a .c/.cpp extension
			std::string newFileName = filePath.filename().generic_string();
			std::replace(newFileName.begin(), newFileName.end(), '.', '_');
			if (useC)
			{
				newFileName.append(".c");
			}
			else
			{
				newFileName.append(".cpp");
			}
			// remove parent directory of file from path for internal name. This could surely be done in a safer way
			FS_NAMESPACE::path subPath(filePath.generic_string().substr(parentDir.generic_string().size() + 1));
			// add a ":/" before the name to mark internal resources (Yes. Hello Qt!)
			temp.internalName = ":/" + subPath.generic_string();
			// add subdir below parent path to name to enable multiple files with the same name
			std::string subDirString(subPath.remove_filename().generic_string());
			if (!subDirString.empty())
			{
				// replace dir separators by underscores
				std::replace(subDirString.begin(), subDirString.end(), '/', '_');
				// add in front of file name
				newFileName = subDirString + "_" + newFileName;
			}
			// build new output file name
			temp.outPath = outPath / newFileName;
			if (beVerbose)
			{
				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(filePath));
				if (beVerbose)
				{
					std::cout << "Size is " << temp.size << " bytes." << std::endl;
				}
			}
			catch (...)
			{
				std::cout << "Error: Failed to get size of " << filePath << "!" << std::endl;
				temp.size = 0;
			}
			// add file to list
			files.push_back(temp);
		}
	}
	// does the user want subdirectories?
	if (recurse)
	{
		// iterate through source directory again searching for directories
		for (FS_NAMESPACE::directory_iterator dirIt(inPath); dirIt != dirEnd; ++dirIt)
		{
			FS_NAMESPACE::path dirPath = (*dirIt).path();
			if (FS_NAMESPACE::is_directory(dirPath))
			{
				if (beVerbose)
				{
					std::cout << "Found subdirectory " << dirPath << std::endl;
				}
				// subdirectory found. recurse.
				std::vector<FileData> subFiles = getFileDataFrom(dirPath, outPath, parentDir, recurse);
				// add returned result to file list
				files.insert(files.end(), subFiles.cbegin(), subFiles.cend());
			}
		}
	}
	// return result
	return files;
}
예제 #10
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;
}
예제 #11
0
            pDevDesc ide_device::create_file_device(const std::string& device_type, const std::tr2::sys::path& filename, double width, double height) {
                auto expr = boost::format("%1%(filename='%2%', width=%3%, height=%4%)") % device_type % filename.generic_string() % width % height;

                // Create the file device via the public R API
                ParseStatus ps;
                auto result = rhost::eval::r_try_eval_str(expr.str(), R_GlobalEnv, ps);
                if (result.has_error) {
                    throw rhost::util::r_error(result.error.c_str());
                }

                pDevDesc dev_desc = nullptr;

                // Retrieve the device descriptor of the current device (the one created above)
                rhost::util::errors_to_exceptions([&] {
                    int device_num = Rf_curDevice();
                    pGEDevDesc ge_dev_desc = GEgetDevice(device_num);
                    dev_desc = ge_dev_desc->dev;
                });

                return dev_desc;
            }