"Fossies" - the Fresh Open Source Software archive

Member "lrc-1.0/src/lib/ResourceManager.cxx" of archive lrc-1.0.tar.gz:


//      ResourceManager.cxx
//
//      Copyright 2011, 2012 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
//      published by the Free Software Foundation; either version 3 of the
//      License, or (at your option) any later version.
//
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//
//      You should have received a copy of the GNU Lesser General Public
//      License along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.


#include <cstring>
#include <cstdio>
#include "../Utils.hxx"
#include "../StatusCodes.hxx"
#include "../Factories.hxx"
#include "../include/ResourceManager.hxx"


int lrc::ResourceManager::load_from_file(void)
{
	const char WHOLE_FILE[] = "Whole file";

	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"))
	if (m_resData) {
		delete[] m_resData;
	};
	if (m_resEntries) {
		delete[] m_resEntries;
	};

	DEBUG_PRINT(("Getting file size of %s: ", m_resourceFile))
	rdfFileSize = file_size(m_resourceFile);
	if (rdfFileSize <= 0) {
		return ERROR_FILE_READ;
	};
	DEBUG_PRINT((": %d bytes\n", rdfFileSize))

	rdfFile = fopen(m_resourceFile, "rb");
	if (!rdfFile) {
		return ERROR_FILE_OPEN;
	};

	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) {
		delete[] rdfData;
		return ERROR_ENCRYPTION_NOT_AVAILABLE;
	};
	retVal = decryptor->decrypt(m_password, rdfData, rdfFileSize, &decryptData, decryptSize);
	delete decryptor;
	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;
}

lrc::ResourceManager::ResourceManager(const char *p_resFilename,
                                      const lrc::CompressionType p_compress,
                                      const lrc::EncryptionType p_encrypt,
                                      const unsigned char *p_key) throw (lrcFileNotFoundException)
{
	size_t len;


	if (!file_exists((char *)p_resFilename)) {
		throw(lrcFileNotFoundException((char *)p_resFilename));
	};

	len = strlen(p_resFilename);
	m_resourceFile = new char[len+1];
	memset(m_resourceFile, 0, (len+1));
	strncpy(m_resourceFile, p_resFilename, len);

	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);
}

lrc::ResourceManager::~ResourceManager(void)
{
	delete[] m_resourceFile;
}

char **lrc::ResourceManager::get_resource_ids(int &p_numRes)
{
	int retVal, sLen, i;
	char **retIDs = nullptr;


	DEBUG_PRINT(("Checking number of entries: %d\n", m_numResEntries))
	if (m_numResEntries < 0) {
		retVal = this->load_from_file();
		DEBUG_PRINT(("Reading the file returned %d\n", retVal))
		if (!success(retVal)) {
			return nullptr;
		};
	};

	DEBUG_PRINT(("Number of entries after loading the file: %d\n", m_numResEntries))
	retIDs = new char*[m_numResEntries];

	for(i=0; i<m_numResEntries; i++) {
		sLen = strlen(m_resEntries[i].resID);
		retIDs[i] = new char[sLen + 1];
		memset(retIDs[i], 0, (sLen+1));
		strncpy(retIDs[i], m_resEntries[i].resID, sLen);
	};

	p_numRes = m_numResEntries;
	return retIDs;
}

lrc::Resource *lrc::ResourceManager::get_resource(const char *p_resID, const unsigned char *p_password)
{
	int retVal, i, foundID;
	ResourceData *retEntry = nullptr;
	unsigned char *dataStart;


	DEBUG_PRINT(("Checking number of entries: %d\n", m_numResEntries))
	if (m_numResEntries < 0) {
		retVal = this->load_from_file();
		DEBUG_PRINT(("Reading the file returned %d\n", retVal))
		if (!success(retVal)) {
			return nullptr;
		};
	};

	foundID = -1;
	for (i=0; i<m_numResEntries; i++) {
		if (strcmp(m_resEntries[i].resID, p_resID) == 0) {
			foundID = i;
			break;
		};
	};
	if (foundID < 0) {
		return retEntry;
	};

	retEntry = new ResourceData();

	dataStart = m_resData + m_resEntries[foundID].startOffset;
	retVal = retEntry->get_data_from_memory(dataStart, m_resEntries[foundID], p_password);

	if (!success(retVal)) {
		delete retEntry;
		retEntry = nullptr;
	};

	return retEntry;
}

lrc::Resource *lrc::ResourceManager::get_resource(unsigned int p_resIdx, const unsigned char *p_password)
{
	int retVal;
	ResourceData *retEntry;
	unsigned char *dataStart;


	DEBUG_PRINT(("Checking the number of entries: %d\n", m_numResEntries))
	if (m_numResEntries < 0) {
		retVal = this->load_from_file();
		DEBUG_PRINT(("Resing the file returned %d\n", retVal))
		if (!success(retVal)) {
			return nullptr;
		};
	};

	if ((p_resIdx < 0) || (p_resIdx > (m_numResEntries-1))) {
		return nullptr;
	};

	retEntry = new ResourceData();

	dataStart = m_resData + m_resEntries[p_resIdx].startOffset;
	retVal = retEntry->get_data_from_memory(dataStart, m_resEntries[p_resIdx], p_password);

	if (!success(retVal)) {
		delete retEntry;
		retEntry = nullptr;
	};

	return retEntry;
}