Source

lrc / src / compiler / RIFParser.cxx

Full commit
//      RIFParser.cxx
//
//      Copyright 2011 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 <tinyxml.h>
#include "../StatusCodes.hxx"
#include "../Utils.hxx"
#include "RIFParser.hxx"


RIFParser::RIFParser(char *p_filename) throw (lrcFileNotFoundException)
	: InFileParser(p_filename)
{
}

int RIFParser::parse(void)
{
	TiXmlDocument *rifData;
	TiXmlElement *rootElem, *resElem;
	TiXmlNode *runElem = nullptr;
	const char *resIdent, *tmpStr;
	unsigned char *password;
	lrc::EncryptionType resEnc = lrc::NoneEncryption;
	lrc::CompressionType resComp = lrc::NoneCompression;
	ResourceData *entry;


	rifData = new TiXmlDocument(m_filename);
	if (!rifData->LoadFile()) {
		DEBUG_PRINT(("Error loading %s\n", m_filename))

		delete rifData;

		m_lastError = ERROR_FILE_OPEN;
		return ERROR_FILE_OPEN;
	};

	rootElem = rifData->RootElement();
	if (strcmp(rootElem->Value(), "Resources")) {
		DEBUG_PRINT(("Didn't find root element. Expected: \"Resources\"; found: \"%s\"\n", rootElem->Value()))

		m_lastError = ERROR_PARSE;
		m_internalError = ieInvalidElement;
		std::get<0>(m_errorPosition) = rootElem->Row();
		std::get<1>(m_errorPosition) = rootElem->Column();

		delete rifData;

		return ERROR_PARSE;
	};

	while (runElem = rootElem->IterateChildren(runElem)) {
		if (runElem->Type() != TiXmlNode::TINYXML_ELEMENT) {
			DEBUG_PRINT(("Skipped a non-element XML node: %s\n", runElem->Value()))
			continue;
		};

		if (strcmp(runElem->Value(), "Resource")) {
			DEBUG_PRINT(("Invalid element found: %s\n", runElem->Value()))

			m_lastError = ERROR_PARSE;
			m_internalError = ieInvalidElement;
			std::get<0>(m_errorPosition) = runElem->Row();
			std::get<1>(m_errorPosition) = runElem->Column();

			delete rifData;

			return ERROR_PARSE;
		};

		resElem = runElem->ToElement();

		resIdent = resElem->Attribute("id");
		if (!resIdent) {
			DEBUG_PRINT(("Didn't find attribute \"id\"\n"))

			m_lastError = ERROR_PARSE;
			m_internalError = ieIdentNotFound;
			std::get<0>(m_errorPosition) = resElem->Row();
			std::get<1>(m_errorPosition) = resElem->Column();

			delete rifData;

			return ERROR_PARSE;
		};

		DEBUG_PRINT(("ID: %s", resIdent))

		tmpStr = resElem->Attribute("encryption");
		if (tmpStr) {
			DEBUG_PRINT(("; encryption: %s; ", tmpStr))
			resEnc = this->eval_encryption_type(tmpStr);

			if (resEnc != lrc::NoneEncryption) {
				password = nullptr;
				tmpStr = resElem->Attribute("password");
				if (tmpStr) {
					DEBUG_PRINT((" (Password un-handled): %s", tmpStr))
				} else {
					DEBUG_PRINT((" (Password un-handled): None found!"))
				};

				try {
					password = this->get_password(tmpStr);
				} catch (lrcFileNotFoundException const &fnfEx) {
					m_lastError = ERROR_PARSE;
					m_internalError = iePasswordFileNotFound;
					std::get<0>(m_errorPosition) = resElem->Row();
					std::get<1>(m_errorPosition) = resElem->Column();
					delete rifData;
					return ERROR_PARSE;
				};

				if (!password) {
					m_lastError = ERROR_PARSE;
					m_internalError = ieMissingPassword;
					std::get<0>(m_errorPosition) = resElem->Row();
					std::get<1>(m_errorPosition) = resElem->Column();

					delete rifData;

					return ERROR_PARSE;
				};
			} else {
				if (password) {
					delete[] password;
					password = nullptr;
				};
			};
		};

		tmpStr = resElem->Attribute("compression");
		DEBUG_PRINT(("; compression: %s", tmpStr))
		if (tmpStr) {
			resComp = this->eval_compression_type(tmpStr);
		};

		tmpStr = resElem->GetText();
		DEBUG_PRINT(("; filename: %s\n", tmpStr))

		if (!tmpStr) {
			m_lastError = ERROR_PARSE;
			m_internalError = ieFilenameNotFound;
			std::get<0>(m_errorPosition) = resElem->Row();
			std::get<1>(m_errorPosition) = resElem->Column();

			delete rifData;

			return ERROR_PARSE;
		};

		entry = new ResourceData();
		entry->set_ident(resIdent);
		entry->set_file(tmpStr);
		entry->set_encryption(resEnc, password);
		entry->set_compression(resComp);
		entry->set_rc_position(resElem->Row(), resElem->Column());
		m_resEntries->push_back(entry);

		if (password) {
			DEBUG_PRINT(("Deleting password: %s\n", password))
			delete[] password;
			password = nullptr;
		};
	};

	delete rifData;

	this->clear_internal_error();
	return NO_ERROR;
}