Source

lrc / src / ResourceData.cxx

Full commit
//      ResourceData.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 <tuple>
#include <cstring>
#include <cstdio>
#include "Utils.hxx"
#include "StatusCodes.hxx"
#include "Factories.hxx"
#include "ResourceData.hxx"


void ResourceData::set_error_msg(char *p_newErrMsg)
{
	size_t newLen;


	if (m_errorMsg) {
		delete[] m_errorMsg;
	};

	newLen = strlen(p_newErrMsg) + 1;
	m_errorMsg = new char[newLen];
	memset(m_errorMsg, 0, newLen);
	strncpy(m_errorMsg, p_newErrMsg, (newLen-1));
}

ResourceData::ResourceData(void)
{
	m_password = nullptr;
	m_filename = nullptr;
	m_encryption = lrc::NoneEncryption;
	m_compression = lrc::NoneCompression;
	m_inFilePosition = std::make_tuple(-1, -1);
	m_errorMsg = nullptr;
}

ResourceData::~ResourceData(void)
{
	if (m_password)
		delete[] m_password;
	if (m_filename)
		delete[] m_filename;
	if (m_errorMsg)
		delete[] m_errorMsg;
}

void ResourceData::set_ident(const char *p_resIdent)
{
	int sLen;


	sLen = strlen(p_resIdent);
	if (m_resID)
		delete[] m_resID;
	m_resID = new char[sLen+1];
	memset(m_resID, 0, (sLen+1));
	strncpy(m_resID, p_resIdent, sLen);
	DEBUG_PRINT(("New resource ID: %s\n", m_resID))
}

void ResourceData::set_file(const char *p_resFilename)
{
	int sLen;


	sLen = strlen(p_resFilename);
	if (m_filename)
		delete[] m_filename;
	m_filename = new char[sLen+1];
	memset(m_filename, 0, (sLen+1));
	strncpy(m_filename, p_resFilename, sLen);
	DEBUG_PRINT(("Filename for resource: %s\n", m_filename))
}

char *ResourceData::get_file(void)
{
	return m_filename;
}

void ResourceData::set_encryption(lrc::EncryptionType p_resEncryption, const unsigned char *p_password)
{
	int pLen;


	m_encryption = p_resEncryption;
	DEBUG_PRINT(("Encryption type: %u\n", m_encryption))

	if (m_password) {
		delete[] m_password;
	};
	if (p_password == nullptr) {
		m_password = nullptr;
		return;
	};
	pLen = password_len(p_password) + 1;
	m_password = new unsigned char[pLen];
	memset(m_password, 0, pLen);
	memcpy(m_password, p_password, (pLen-1));
}

lrc::EncryptionType ResourceData::get_encryption(void)
{
	return m_encryption;
}

void ResourceData::set_compression(lrc::CompressionType p_resCompression)
{
	m_compression = p_resCompression;
	DEBUG_PRINT(("Compression type: %u\n", m_compression))
}

lrc::CompressionType ResourceData::get_compression(void)
{
	return m_compression;
}

void ResourceData::set_rc_position(int p_line, int p_col)
{
	m_inFilePosition = std::make_tuple(p_line, p_col);
	DEBUG_PRINT(("InFilePosition (RC): %d/%d\n", std::get<0>(m_inFilePosition), std::get<1>(m_inFilePosition)))
}

inFilePosition ResourceData::get_rc_position(void)
{
	return m_inFilePosition;
}

int ResourceData::prepare_resource_from_file(unsigned char **p_resData, size_t &p_resSize)
{
	lrc::CompressDecompress *compressor;
	lrc::EncryptDecrypt *encryptor;
	FILE *resFileHandle;
	size_t resFileSize, actFileSize;
	int retVal;
	unsigned char *resFileBuf;
	unsigned char *compDataBuf;
	unsigned char *encDataBuf;


	if (!p_resData) {
		return ERROR_INVALID_PARAMETER;
	};

	if (!file_exists(m_filename)) {
		std::get<1>(m_inFilePosition) = 2;
		return ERROR_FILE_NOT_FOUND;
	};

	compressor = CompressionFactory::get_compression_class(m_compression);
	if (!compressor) {
		std::get<1>(m_inFilePosition) = 3;
		return ERROR_COMPRESSION_NOT_AVAILABLE;
	};

	try {
		encryptor = EncryptionFactory::get_encryption_class(m_encryption, m_resID);
	} catch (lrcEncryptionDisabledException const &encDisabledEx) {
		this->set_error_msg((char *)encDisabledEx.what());

		delete compressor;
		std::get<1>(m_inFilePosition) = 4;
		return ERROR_ENCRYPTION_NOT_AVAILABLE;
	};
	if (!encryptor) {
		delete compressor;

		std::get<1>(m_inFilePosition) = 4;
		return ERROR_ENCRYPTION_NOT_AVAILABLE;
	};

	resFileSize = file_size(m_filename);
	DEBUG_PRINT(("File %s is %d in size\n", m_filename, resFileSize))
	if (resFileSize < 0) {
		delete encryptor;
		delete compressor;

		std::get<1>(m_inFilePosition) = 2;
		return resFileSize;
	};

	resFileHandle = fopen(m_filename, "rb");
	if (!resFileHandle) {
		delete encryptor;
		delete compressor;

		std::get<1>(m_inFilePosition) = 2;
		return ERROR_FILE_OPEN;
	};

	resFileBuf = new unsigned char[resFileSize+1];
	actFileSize = fread(resFileBuf, sizeof(unsigned char), resFileSize, resFileHandle);
	DEBUG_PRINT(("%d bytes read from %s (%d expected)\n", actFileSize, m_filename, resFileSize))
	if (actFileSize != resFileSize) {
		delete[] resFileBuf;
		fclose(resFileHandle);
		delete encryptor;
		delete compressor;

		std::get<1>(m_inFilePosition) = 2;
		return ERROR_FILE_READ;
	};
	fclose(resFileHandle);

	retVal = compressor->compress(resFileBuf, resFileSize, &compDataBuf, actFileSize);
	if (!no_error(retVal)) {
		delete[] resFileBuf,
		delete encryptor;
		delete compressor;

		std::get<1>(m_inFilePosition) = 3;
		return ERROR_COMPRESSION_COMPRESS;
	};
	delete[] resFileBuf;
	delete compressor;

	retVal = encryptor->encrypt(m_password, compDataBuf, actFileSize, &encDataBuf, actFileSize);
	if (!no_error(retVal)) {
		delete encryptor;

		std::get<1>(m_inFilePosition) = 4;
		return ERROR_ENCRYPTION_ENCRYPT;
	};
	delete[] compDataBuf;
	delete encryptor;

	*p_resData = encDataBuf;
	p_resSize = actFileSize;
	return NO_ERROR;
}

int ResourceData::get_data_from_memory(unsigned char *p_dataStart,
                                       resEntry p_resEntry,
                                       const unsigned char *p_password)
{
	lrc::CompressDecompress *decompressor;
	lrc::EncryptDecrypt *decryptor;
	int retVal;
	unsigned char *decryptData;
	unsigned char *decompData;
	size_t decryptSize, decompSize;


	if ((!p_dataStart) || (!p_resEntry.resID) || (p_resEntry.resSize <= 0)) {
		return ERROR_INVALID_PARAMETER;
	};

	decompressor = CompressionFactory::get_compression_class(p_resEntry.compType);
	if (!decompressor) {
		return ERROR_COMPRESSION_NOT_AVAILABLE;
	};

	try {
		decryptor = EncryptionFactory::get_encryption_class(p_resEntry.encType, p_resEntry.resID);
	} catch (lrcEncryptionDisabledException const &encDisabledEx) {
		this->set_error_msg((char *)encDisabledEx.what());

		delete decompressor;
		return ERROR_ENCRYPTION_NOT_AVAILABLE;
	};
	if (!decryptor) {
		delete decompressor;

		return ERROR_ENCRYPTION_NOT_AVAILABLE;
	};

	retVal = decryptor->decrypt(p_password, p_dataStart, p_resEntry.resSize, &decryptData, decryptSize);
	if (!no_error(retVal)) {
		delete decryptor;
		delete decompressor;

		return ERROR_ENCRYPTION_DECRYPT;
	};
	delete decryptor;

	retVal = decompressor->decompress(decryptData, decryptSize, &decompData, decompSize);
	if (!no_error(retVal)) {
		delete[] decryptData;
		delete decompressor;

		return ERROR_COMPRESSION_DECOMPRESS;
	};
	delete[] decryptData;

	this->set_ident(p_resEntry.resID);
	m_resData = decompData;
	m_resSize = decompSize;
	this->set_compression(p_resEntry.compType);
	this->set_encryption(p_resEntry.encType, p_password);

	return NO_ERROR;
}

char *ResourceData::get_error_msg(void)
{
	size_t errMsgLen;
	char *retErrMsg;


	if (!m_errorMsg) {
		return nullptr;
	};

	errMsgLen = strlen(m_errorMsg);
	retErrMsg = new char[errMsgLen+1];
	memset(retErrMsg, 0, (errMsgLen+1));
	strncpy(retErrMsg, m_errorMsg, errMsgLen);

	delete[] m_errorMsg;
	m_errorMsg = nullptr;

	return retErrMsg;
}