Commits

Andreas Tscharner committed 4beb21f

Make ResourceManager ready to get resource data directly from memory

* Refactor compress/decompress and encryption/decryption into methods of its
own
* Refactor load_from_file (using new methods) and new method load_embedded
* New constructor for directly linked resource data

Comments (0)

Files changed (2)

src/include/ResourceManager.hxx

 //      ResourceManager.hxx
 //
-//      Copyright 2011, 2012 Andreas Tscharner <andy@vis.ethz.ch>
+//      Copyright 2011, 2012, 2014 Andreas Tscharner <andy@vis.ethz.ch>
 //
 //      This program is free software; you can redistribute it and/or modify
 //      it under the terms of the GNU Lesser General Public License as
  * \c liblrc
  *
  * \author Andreas Tscharner
- * \date 2013-01-06
+ * \date 2014-08-10
  */
 
 
 
 
 // Include files
-#include <stddef.h>
 #include "Resource.hxx"
 #include "../ResourceData.hxx"
 #include "../lrcExceptions.hxx"
 	 *
 	 * This is the main class of the \c liblrc library. It expects a
 	 * filename of a resource file in the constructor and handles all
-	 * resources in that given file.
+	 * resources in that given file. If the constructor with no filename
+	 * is used, it expects the resource data is directly compiled into
+	 * the executable file.
 	 */
 	class ResourceManager
 	{
 			EncryptionType m_encType;  //!< Encryption type for complete file
 			unsigned char *m_password; //!< Password is complete file is encrypted
 
+			/*! \brief Decrypt resource data
+			 *
+			 * This methods decrypts the resource data in the memory
+			 *
+			 * \param[in] p_encData Encrypted resource data for decryption
+			 * \param[in] p_encSize Size of encrypted resource data
+			 * \param[out] p_clearData Decrypted/clear resource data
+			 * \param[out] p_clearSize Size of clear resource data
+			 *
+			 * \retval NO_ERROR Data successfully decrypted
+			 * \retval ERROR_ENCRYPTION_NOT_AVAILABLE Encryption/Decryption
+			 *                                        support is not
+			 *                                        compiled in
+			 * \retval ERROR_ENCRYPTION_DECRYPT An error occurred while
+			 *                                  decrypting the data
+			 */
+			int decrypt_data(const unsigned char *, size_t, unsigned char **, size_t &);
+			/*! \brief Decompress resource data
+			 *
+			 * This method decompresses the resource data in the memory
+			 *
+			 * \param[in] p_compData Compressed resource data
+			 * \param[in] p_compSize Size of compressed resource data
+			 * \param[out] p_decompData Decompressed resource data
+			 * \param[out] p_decompSize Size of decompressed resource data
+			 *
+			 * \retval NO_ERROR Data successfully decompressed
+			 * \retval ERROR_COMPRESSION_DECOMPRESS An error occurred while
+			 *                                      decompressing the data
+			 */
+			int decompress_data(const unsigned char *, size_t, unsigned char **, size_t &);
+			/*! \brief Setup new resources
+			 *
+			 * This method sets up internal data to provide the resource
+			 * data in the memory
+			 *
+			 * \param[in] p_resData Decrypted and decompressed resource data
+			 * \param[in] p_resSize Size of resource data
+			 *
+			 * \retval NO_ERROR Internal data successfully set up
+			 */
+			int setup_resources(const unsigned char *, size_t);
+
 			/*! \brief Method to load resource file
 			 *
 			 * This method loads all data from the resource file
 			 * \retval NO_ERROR Resource file successfully loaded
 			 * \retval ERROR_FILE_READ An error occurred while reading the
 			 *                         file
+			 * \retval ERROR_ENCRYPTION_NOT_AVAILABLE Encryption/Decryption
+			 *                                        support is not
+			 *                                        compiled in
+			 * \retval ERROR_ENCRYPTION_DECRYPT An error occurred while
+			 *                                  decrypting the data
+			 * \retval ERROR_COMPRESSION_DECOMPRESS An error occurred while
+			 *                                      decompressing the data
 			 */
 			int load_from_file(void);
+			/*! \brief Method to load embedded resource
+			 *
+			 * This method loads all embedded resource data
+			 *
+			 *  \param[in] p_startAddr Start address of resource data in
+			 *                         memory
+			 *  \param[in] p_endAddr End address of resource data in memory
+			 *
+			 * \retval NO_ERROR Embedded resources successfully accessed
+			 * \retval ERROR_ENCRYPTION_NOT_AVAILABLE Encryption/Decryption
+			 *                                        support is not
+			 *                                        compiled in
+			 * \retval ERROR_ENCRYPTION_DECRYPT An error occurred while
+			 *                                  decrypting the data
+			 * \retval ERROR_COMPRESSION_DECOMPRESS An error occurred while
+			 *                                      decompressing the data
+			 */
+			int load_embedded(const unsigned char *, const unsigned char *);
 
 		public:
 			/*! \brief Constructor expecting resource file name
 			 *
 			 * The constructor expects the name of a resource file. The file
-			 * will be loaded at first use, but an exceptions will be thrown
+			 * will be loaded at first use, but an exception will be thrown
 			 * if it does not exist
 			 *
 			 * \param[in] p_resFilename Filename of resource file
 			 *                                     file does not exist
 			 */
 			ResourceManager(const char *, const CompressionType, const EncryptionType, const unsigned char *) throw (lrcFileNotFoundException);
+			/*! \brief Constructor for embedded resources
+			 *
+			 * The constructor expects the start and end address of the
+			 * resource data in memory and the compression and encryption
+			 * type if the complete resource is compressed and encrypted
+			 * respectively. If it is encrypted a password is expected.
+			 *
+			 * \param[in] p_startAddr Start address of resource data in
+			 *                        memory
+			 * \param[in] p_endAddr End address of resource data in memory
+			 * \param[in] p_compress Compression type if the complete
+			 *                       resource data is compressed
+			 * \param[in] p_encrypt Encryption type if the complete resource
+			 *                      data is encrypted
+			 * \param[in] p_key Password if the complete resource is
+			 *                  encrypted
+			 *
+			 * \remarks How to get to the start and end address in the
+			 *          linked file, see the
+			 *          [Wiki](https://bitbucket.org/StarFire/lrc/wiki/Home)
+			 *          or the man page
+			 */
+			ResourceManager(const unsigned char *, const unsigned char *, const CompressionType, const EncryptionType, const unsigned char *);
 			/*! \brief Destructor
 			 *
 			 * The destructor cleans up all the used memory of the class

src/lib/ResourceManager.cxx

 //      ResourceManager.cxx
 //
-//      Copyright 2011, 2012 Andreas Tscharner <andy@vis.ethz.ch>
+//      Copyright 2011, 2012, 2014 Andreas Tscharner <andy@vis.ethz.ch>
 //
 //      This program is free software; you can redistribute it and/or modify
 //      it under the terms of the GNU Lesser General Public License as
 #include "../include/ResourceManager.hxx"
 
 
-int lrc::ResourceManager::load_from_file(void)
+int lrc::ResourceManager::decrypt_data(const unsigned char *p_encData, size_t p_encSize,
+                                       unsigned char **p_clearData, size_t &p_clearSize)
 {
 	const char WHOLE_FILE[] = "Whole file";
 
+	EncryptDecrypt *decryptor;
+	int retVal;
+
+
+	DEBUG_PRINT(("Decrypting data with decryption type %d.", this->m_encType))
+	try {
+		decryptor = EncryptionFactory::get_encryption_class(this->m_encType, const_cast<char *>(WHOLE_FILE));
+	} catch (lrcEncryptionDisabledException const &encDisEx) {
+		return ERROR_ENCRYPTION_NOT_AVAILABLE;
+	};
+	retVal = decryptor->decrypt(this->m_password, p_encData, p_encSize, p_clearData, p_clearSize);
+	delete decryptor;
+	if (!success(retVal)) {
+		DEBUG_PRINT((" Decrypting failed with error code: %d\n", retVal))
+		return ERROR_ENCRYPTION_DECRYPT;
+	};
+	DEBUG_PRINT(("\n"))
+
+	return NO_ERROR;
+}
+
+int lrc::ResourceManager::decompress_data(const unsigned char *p_compData, size_t p_compSize,
+                                          unsigned char **p_decompData, size_t &p_decompSize)
+{
+	CompressDecompress *decompressor;
+	int retVal;
+
+
+	DEBUG_PRINT(("Decompressing data with decompressor type %d. ", this->m_compType))
+	decompressor = CompressionFactory::get_compression_class(this->m_compType);
+	retVal = decompressor->decompress(p_compData, p_compSize, p_decompData, p_decompSize);
+	delete decompressor;
+	if (!success(retVal)) {
+		DEBUG_PRINT(("Decompression failed with error code: %d\n", retVal))
+		return ERROR_COMPRESSION_DECOMPRESS;
+	};
+	DEBUG_PRINT(("Old size: %d; new size: %d\n", p_compSize, p_decompSize))
+
+	return NO_ERROR;
+}
+
+int lrc::ResourceManager::setup_resources(const unsigned char *p_resData, size_t p_resSize)
+{
+	unsigned char *bufferPos;
+	unsigned int numEntries;
+
+
+	bufferPos = const_cast<unsigned char *>(p_resData);
+
+	DEBUG_PRINT(("Getting number of entries..."))
+	memcpy(&numEntries, bufferPos, sizeof(unsigned int));
+	bufferPos += sizeof(unsigned int);
+	DEBUG_PRINT(("done (%d).\n", numEntries))
+
+	DEBUG_PRINT(("Getting all %d entries   ", numEntries))
+	this->m_resEntries = new resEntry[numEntries];
+	for (int i=0; i<numEntries; i++) {
+		memcpy(&m_resEntries[i], bufferPos, sizeof(resEntry));
+		bufferPos += sizeof(resEntry);
+		DEBUG_PRINT(("."))
+	};
+	DEBUG_PRINT(("done.\n"))
+
+	this->m_resDataSize = p_resSize - sizeof(unsigned int) - (numEntries * sizeof(resEntry));
+	DEBUG_PRINT(("Getting data for all entries (total: %d bytes)\n", this->m_resDataSize))
+	this->m_resData = new unsigned char[this->m_resDataSize];
+	memset(this->m_resData, 0, this->m_resDataSize);
+	memcpy(this->m_resData, bufferPos, this->m_resDataSize);
+
+	this->m_numResEntries = numEntries;
+
+	return NO_ERROR;
+}
+
+int lrc::ResourceManager::load_from_file(void)
+{
 	FILE *rdfFile;
 	size_t rdfFileSize;
 	size_t decompSize;
 	size_t decryptSize;
 	int retVal;
-	unsigned int numEntries;
 	size_t readItems;
 	unsigned char *rdfData;
 	unsigned char *decompData;
 	unsigned char *decryptData;
-	unsigned char *bufferPos;
-	CompressDecompress *decompressor;
-	EncryptDecrypt *decryptor;
 
 
 	DEBUG_PRINT(("Checking current data and entries\n"))
 	};
 
 	rdfData = new unsigned char[rdfFileSize];
-
 	DEBUG_PRINT(("Reading %d bytes from file %s (complete file)\n", rdfFileSize, m_resourceFile))
 	readItems = fread(rdfData, sizeof(unsigned char), rdfFileSize, rdfFile);
 	fclose(rdfFile);
 	if (readItems != rdfFileSize) {
 		DEBUG_PRINT(("Error reading file. Read %d; expected: %d\n", readItems, rdfFileSize))
 		delete[] rdfData;
-
 		return ERROR_FILE_READ;
 	};
 
-	DEBUG_PRINT(("Decrypting data with decryption type %d.", m_encType))
-	try {
-		decryptor = EncryptionFactory::get_encryption_class(m_encType, const_cast<char *>(WHOLE_FILE));
-	} catch (lrcEncryptionDisabledException const &encDisEx) {
+	retVal = this->decrypt_data(rdfData, rdfFileSize, &decryptData, decryptSize);
+	if (is_error(retVal)) {
 		delete[] rdfData;
-		return ERROR_ENCRYPTION_NOT_AVAILABLE;
+		return retVal;
 	};
-	retVal = decryptor->decrypt(m_password, rdfData, rdfFileSize, &decryptData, decryptSize);
-	delete decryptor;
+
+	retVal = this->decompress_data(decryptData, decryptSize, &decompData, decompSize);
+	if (is_error(retVal)) {
+		delete[] decryptData;
+		return retVal;
+	};
+
+	retVal = this->setup_resources(decompData, decompSize);
+
 	delete[] rdfData;
-	if (!success(retVal)) {
-		DEBUG_PRINT((" Decrypting failed with error code: %d\n", retVal))
-
-		return ERROR_ENCRYPTION_DECRYPT;
-	};
-	DEBUG_PRINT(("\n"))
-
-	DEBUG_PRINT(("Decompressing data with decompressor type %d. ", m_compType))
-	decompressor = CompressionFactory::get_compression_class(m_compType);
-	retVal = decompressor->decompress(decryptData, decryptSize, &decompData, decompSize);
-	delete decompressor;
 	delete[] decryptData;
-	if (! success(retVal)) {
-		DEBUG_PRINT(("Decompression failed with error code: %d\n", retVal))
-
-		return ERROR_COMPRESSION_DECOMPRESS;
-	};
-	DEBUG_PRINT(("Old size: %d; new size: %d\n", decryptSize, decompSize))
-
-	bufferPos = decompData;
-
-	DEBUG_PRINT(("Getting number of entries..."))
-	memcpy(&numEntries, bufferPos, sizeof(unsigned int));
-	bufferPos += sizeof(unsigned int);
-	DEBUG_PRINT(("done (%d).\n", numEntries))
-
-	DEBUG_PRINT(("Getting all %d entries   ", numEntries))
-	m_resEntries = new resEntry[numEntries];
-	for (int i=0; i<numEntries; i++) {
-		memcpy(&m_resEntries[i], bufferPos, sizeof(resEntry));
-		bufferPos += sizeof(resEntry);
-		DEBUG_PRINT(("."))
-	};
-	DEBUG_PRINT(("done.\n"))
-
-	m_resDataSize = decompSize - sizeof(unsigned int) - (numEntries * sizeof(resEntry));
-	DEBUG_PRINT(("Getting data for all entries (total: %d bytes)\n", m_resDataSize))
-	m_resData = new unsigned char[m_resDataSize];
-	memset(m_resData, 0, m_resDataSize);
-	memcpy(m_resData, bufferPos, m_resDataSize);
-
-	m_numResEntries = numEntries;
-
 	delete[] decompData;
 
-	return NO_ERROR;
+	return retVal;
+}
+
+int lrc::ResourceManager::load_embedded(const unsigned char *p_startAddr, const unsigned char *p_endAddr)
+{
+	size_t rdfDataSize;
+	size_t decompSize;
+	size_t decryptSize;
+	unsigned char *decompData;
+	unsigned char *decryptData;
+	int retVal;
+
+
+	DEBUG_PRINT(("Getting data size of embedded resource: "))
+	rdfDataSize = p_endAddr - p_startAddr;
+	DEBUG_PRINT((": %d bytes\n", rdfDataSize))
+
+	retVal = this->decrypt_data(p_startAddr, rdfDataSize, &decryptData, decryptSize);
+	if (is_error(retVal)) {
+		return retVal;
+	};
+
+	retVal = this->decompress_data(decryptData, decryptSize, &decompData, decompSize);
+	if (is_error(retVal)) {
+		delete[] decryptData;
+		return retVal;
+	};
+
+	retVal = this->setup_resources(decompData, decompSize);
+
+	delete[] decryptData;
+	delete[] decompData;
+
+	return retVal;
 }
 
 lrc::ResourceManager::ResourceManager(const char *p_resFilename,
 	m_password = const_cast<unsigned char *>(p_key);
 }
 
+lrc::ResourceManager::ResourceManager(const unsigned char *p_startAddr,
+                                      const unsigned char *p_endAddr,
+                                      const lrc::CompressionType p_compress,
+                                      const lrc::EncryptionType p_encrypt,
+                                      const unsigned char *p_key)
+{
+	this->m_resourceFile = nullptr;
+
+	m_resEntries = nullptr;
+	m_numResEntries = -1;
+	m_resData = nullptr;
+	m_resDataSize = -1;
+
+	m_compType = p_compress;
+	m_encType  = p_encrypt;
+	m_password = const_cast<unsigned char *>(p_key);
+
+	this->load_embedded(p_startAddr, p_endAddr);
+}
+
 lrc::ResourceManager::~ResourceManager(void)
 {
-	delete[] m_resourceFile;
+	if (this->m_resourceFile) {
+		delete[] this->m_resourceFile;
+	};
 }
 
 char **lrc::ResourceManager::get_resource_ids(int &p_numRes)