mirror of https://github.com/SeanOMik/libki.git
dml: Add more robust error reporting
This commit is contained in:
parent
bba2aae43b
commit
9034c893a7
|
@ -1,7 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "FieldBase.h"
|
#include "FieldBase.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "exception.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
|
@ -69,7 +71,7 @@ namespace dml
|
||||||
* Example: <FieldName TYPE="STR">Value</FieldName>
|
* Example: <FieldName TYPE="STR">Value</FieldName>
|
||||||
*
|
*
|
||||||
* If the field in the XML data does not have the same type
|
* If the field in the XML data does not have the same type
|
||||||
* as this field, then an exception is thrown.
|
* as this field, then a value_error is thrown.
|
||||||
*/
|
*/
|
||||||
void from_xml(const rapidxml::xml_node<> *node) final
|
void from_xml(const rapidxml::xml_node<> *node) final
|
||||||
{
|
{
|
||||||
|
@ -82,12 +84,15 @@ namespace dml
|
||||||
attr; attr = attr->next_attribute())
|
attr; attr = attr->next_attribute())
|
||||||
{
|
{
|
||||||
const std::string name = attr->name();
|
const std::string name = attr->name();
|
||||||
if (name != "TYPE")
|
if (name == "TYPE")
|
||||||
{
|
{
|
||||||
const std::string value = attr->value();
|
const std::string value = attr->value();
|
||||||
if (value != get_type_name())
|
if (value != get_type_name())
|
||||||
{
|
{
|
||||||
// TODO: Exceptions
|
std::ostringstream oss;
|
||||||
|
oss << "XML Field node has incorrect TYPE attribute value. ";
|
||||||
|
oss << "(value=\"" << value << "\", expected=\"" << get_type_name() << "\". ";
|
||||||
|
throw value_error(oss.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (name == "NOXFER")
|
else if (name == "NOXFER")
|
||||||
|
@ -97,7 +102,9 @@ namespace dml
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: Exceptions
|
std::ostringstream oss;
|
||||||
|
oss << "XML Field node has unknown attribute \"" << name << "\".";
|
||||||
|
throw value_error(oss.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +147,11 @@ namespace dml
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: Exceptions
|
std::ostringstream oss;
|
||||||
|
oss << "Tried to copy value from " <<
|
||||||
|
other->get_type_name() << " field to " <<
|
||||||
|
get_type_name() << " field.";
|
||||||
|
throw value_error(oss.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
#pragma once
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace dml
|
||||||
|
{
|
||||||
|
class runtime_error : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
runtime_error(std::string message) : std::runtime_error(message) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
class parse_error : public runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
parse_error(std::string message) : runtime_error(message) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
class value_error : public runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
value_error(std::string message) : runtime_error(message) { }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,8 +33,9 @@ namespace dml
|
||||||
auto *type_attr = node->first_attribute("TYPE");
|
auto *type_attr = node->first_attribute("TYPE");
|
||||||
if (!type_attr)
|
if (!type_attr)
|
||||||
{
|
{
|
||||||
// TODO: Exceptions
|
std::ostringstream oss;
|
||||||
return nullptr;
|
oss << "XML Field node is missing required TYPE attribute (" << node->name() << ").";
|
||||||
|
throw value_error(oss.str());
|
||||||
}
|
}
|
||||||
const std::string type = type_attr->value();
|
const std::string type = type_attr->value();
|
||||||
|
|
||||||
|
@ -63,8 +64,9 @@ namespace dml
|
||||||
field = new GidField("", record);
|
field = new GidField("", record);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: Exceptions
|
std::ostringstream oss;
|
||||||
return nullptr;
|
oss << "Unknown DML type \"" << type << "\" in XML Field node: " << node->name() << ".";
|
||||||
|
throw value_error(oss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
field->from_xml(node);
|
field->from_xml(node);
|
||||||
|
|
|
@ -94,8 +94,9 @@ namespace dml
|
||||||
const std::string node_name = node->name();
|
const std::string node_name = node->name();
|
||||||
if (node_name != "RECORD")
|
if (node_name != "RECORD")
|
||||||
{
|
{
|
||||||
// TODO: Exceptions
|
std::ostringstream oss;
|
||||||
return;
|
oss << "Expected <RECORD> node but got <" << node->name() << ">.";
|
||||||
|
throw value_error(oss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Every child node inside a <RECORD> element is a Field.
|
// Every child node inside a <RECORD> element is a Field.
|
||||||
|
|
|
@ -18,6 +18,12 @@ namespace dml
|
||||||
{
|
{
|
||||||
ValueBytes<BYT> data;
|
ValueBytes<BYT> data;
|
||||||
istream.read(data.buff, sizeof(BYT));
|
istream.read(data.buff, sizeof(BYT));
|
||||||
|
if (istream.fail())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Not enough data was available to read BYT value (" << m_name << ").";
|
||||||
|
throw parse_error(oss.str());
|
||||||
|
}
|
||||||
m_value = data.value;
|
m_value = data.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,24 +9,34 @@ namespace dml
|
||||||
template <>
|
template <>
|
||||||
void DblField::write_to(std::ostream &ostream) const
|
void DblField::write_to(std::ostream &ostream) const
|
||||||
{
|
{
|
||||||
ValueBytes<USHRT> endianness_check;
|
|
||||||
endianness_check.value = 0x0102;
|
|
||||||
ValueBytes<DBL> data;
|
ValueBytes<DBL> data;
|
||||||
data.value = m_value;
|
data.value = m_value;
|
||||||
|
|
||||||
|
ValueBytes<USHRT> endianness_check;
|
||||||
|
endianness_check.value = 0x0102;
|
||||||
if (endianness_check.buff[0] == 0x01)
|
if (endianness_check.buff[0] == 0x01)
|
||||||
std::reverse(&data.buff[0], &data.buff[8]);
|
std::reverse(&data.buff[0], &data.buff[8]);
|
||||||
|
|
||||||
ostream.write(data.buff, sizeof(DBL));
|
ostream.write(data.buff, sizeof(DBL));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void DblField::read_from(std::istream &istream)
|
void DblField::read_from(std::istream &istream)
|
||||||
{
|
{
|
||||||
ValueBytes<USHRT> endianness_check;
|
|
||||||
endianness_check.value = 0x0102;
|
|
||||||
ValueBytes<DBL> data;
|
ValueBytes<DBL> data;
|
||||||
istream.read(data.buff, sizeof(DBL));
|
istream.read(data.buff, sizeof(DBL));
|
||||||
|
if (istream.fail())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Not enough data was available to read DBL value (" << m_name << ").";
|
||||||
|
throw parse_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueBytes<USHRT> endianness_check;
|
||||||
|
endianness_check.value = 0x0102;
|
||||||
if (endianness_check.buff[0] == 0x01)
|
if (endianness_check.buff[0] == 0x01)
|
||||||
std::reverse(&data.buff[0], &data.buff[8]);
|
std::reverse(&data.buff[0], &data.buff[8]);
|
||||||
|
|
||||||
m_value = data.value;
|
m_value = data.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,22 +9,31 @@ namespace dml
|
||||||
template <>
|
template <>
|
||||||
void FltField::write_to(std::ostream &ostream) const
|
void FltField::write_to(std::ostream &ostream) const
|
||||||
{
|
{
|
||||||
ValueBytes<USHRT> endianness_check;
|
|
||||||
endianness_check.value = 0x0102;
|
|
||||||
ValueBytes<FLT> data;
|
ValueBytes<FLT> data;
|
||||||
data.value = m_value;
|
data.value = m_value;
|
||||||
|
|
||||||
|
ValueBytes<USHRT> endianness_check;
|
||||||
|
endianness_check.value = 0x0102;
|
||||||
if (endianness_check.buff[0] == 0x01)
|
if (endianness_check.buff[0] == 0x01)
|
||||||
std::reverse(&data.buff[0], &data.buff[4]);
|
std::reverse(&data.buff[0], &data.buff[4]);
|
||||||
|
|
||||||
ostream.write(data.buff, sizeof(FLT));
|
ostream.write(data.buff, sizeof(FLT));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void FltField::read_from(std::istream &istream)
|
void FltField::read_from(std::istream &istream)
|
||||||
{
|
{
|
||||||
ValueBytes<USHRT> endianness_check;
|
|
||||||
endianness_check.value = 0x0102;
|
|
||||||
ValueBytes<FLT> data;
|
ValueBytes<FLT> data;
|
||||||
istream.read(data.buff, sizeof(FLT));
|
istream.read(data.buff, sizeof(FLT));
|
||||||
|
if (istream.fail())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Not enough data was available to read FLT value (" << m_name << ").";
|
||||||
|
throw parse_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueBytes<USHRT> endianness_check;
|
||||||
|
endianness_check.value = 0x0102;
|
||||||
if (endianness_check.buff[0] == 0x01)
|
if (endianness_check.buff[0] == 0x01)
|
||||||
std::reverse(&data.buff[0], &data.buff[4]);
|
std::reverse(&data.buff[0], &data.buff[4]);
|
||||||
m_value = data.value;
|
m_value = data.value;
|
||||||
|
|
|
@ -19,12 +19,20 @@ namespace dml
|
||||||
template <>
|
template <>
|
||||||
void GidField::read_from(std::istream &istream)
|
void GidField::read_from(std::istream &istream)
|
||||||
{
|
{
|
||||||
ValueBytes<USHRT> endianness_check;
|
|
||||||
endianness_check.value = 0x0102;
|
|
||||||
ValueBytes<GID> data;
|
ValueBytes<GID> data;
|
||||||
istream.read(data.buff, sizeof(GID));
|
istream.read(data.buff, sizeof(GID));
|
||||||
|
if (istream.fail())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Not enough data was available to read GID value (" << m_name << ").";
|
||||||
|
throw parse_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueBytes<USHRT> endianness_check;
|
||||||
|
endianness_check.value = 0x0102;
|
||||||
if (endianness_check.buff[0] == 0x01)
|
if (endianness_check.buff[0] == 0x01)
|
||||||
std::reverse(&data.buff[0], &data.buff[8]);
|
std::reverse(&data.buff[0], &data.buff[8]);
|
||||||
|
|
||||||
m_value = data.value;
|
m_value = data.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,12 +19,20 @@ namespace dml
|
||||||
template <>
|
template <>
|
||||||
void IntField::read_from(std::istream &istream)
|
void IntField::read_from(std::istream &istream)
|
||||||
{
|
{
|
||||||
ValueBytes<USHRT> endianness_check;
|
|
||||||
endianness_check.value = 0x0102;
|
|
||||||
ValueBytes<INT> data;
|
ValueBytes<INT> data;
|
||||||
istream.read(data.buff, sizeof(INT));
|
istream.read(data.buff, sizeof(INT));
|
||||||
|
if (istream.fail())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Not enough data was available to read INT value (" << m_name << ").";
|
||||||
|
throw parse_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueBytes<USHRT> endianness_check;
|
||||||
|
endianness_check.value = 0x0102;
|
||||||
if (endianness_check.buff[0] == 0x01)
|
if (endianness_check.buff[0] == 0x01)
|
||||||
std::reverse(&data.buff[0], &data.buff[4]);
|
std::reverse(&data.buff[0], &data.buff[4]);
|
||||||
|
|
||||||
m_value = data.value;
|
m_value = data.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,12 +19,20 @@ namespace dml
|
||||||
template <>
|
template <>
|
||||||
void ShrtField::read_from(std::istream &istream)
|
void ShrtField::read_from(std::istream &istream)
|
||||||
{
|
{
|
||||||
ValueBytes<SHRT> endianness_check;
|
|
||||||
endianness_check.value = 0x0102;
|
|
||||||
ValueBytes<SHRT> data;
|
ValueBytes<SHRT> data;
|
||||||
istream.read(data.buff, sizeof(SHRT));
|
istream.read(data.buff, sizeof(SHRT));
|
||||||
|
if (istream.fail())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Not enough data was available to read SHRT value (" << m_name << ").";
|
||||||
|
throw parse_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueBytes<SHRT> endianness_check;
|
||||||
|
endianness_check.value = 0x0102;
|
||||||
if (endianness_check.buff[0] == 0x01)
|
if (endianness_check.buff[0] == 0x01)
|
||||||
std::reverse(&data.buff[0], &data.buff[2]);
|
std::reverse(&data.buff[0], &data.buff[2]);
|
||||||
|
|
||||||
m_value = data.value;
|
m_value = data.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,16 +21,30 @@ namespace dml
|
||||||
void StrField::read_from(std::istream &istream)
|
void StrField::read_from(std::istream &istream)
|
||||||
{
|
{
|
||||||
// Get the length
|
// Get the length
|
||||||
ValueBytes<USHRT> endianness_check;
|
|
||||||
endianness_check.value = 0x0102;
|
|
||||||
ValueBytes<USHRT> length_data;
|
ValueBytes<USHRT> length_data;
|
||||||
istream.read(length_data.buff, sizeof(USHRT));
|
istream.read(length_data.buff, sizeof(USHRT));
|
||||||
|
if (istream.fail())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Not enough data was available to read STR value (" << m_name << ").";
|
||||||
|
throw parse_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueBytes<USHRT> endianness_check;
|
||||||
|
endianness_check.value = 0x0102;
|
||||||
if (endianness_check.buff[0] == 0x01)
|
if (endianness_check.buff[0] == 0x01)
|
||||||
std::reverse(&length_data.buff[0], &length_data.buff[2]);
|
std::reverse(&length_data.buff[0], &length_data.buff[2]);
|
||||||
|
|
||||||
// Read the data into a buffer
|
// Read the data into a buffer
|
||||||
char *data = new char[length_data.value + 1] { 0 };
|
char *data = new char[length_data.value + 1] { 0 };
|
||||||
istream.read(data, length_data.value);
|
istream.read(data, length_data.value);
|
||||||
|
if (istream.fail())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Not enough data was available to read STR value (" << m_name << ").";
|
||||||
|
throw parse_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
m_value = STR(data);
|
m_value = STR(data);
|
||||||
delete[] data;
|
delete[] data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,12 @@ namespace dml
|
||||||
{
|
{
|
||||||
ValueBytes<UBYT> data;
|
ValueBytes<UBYT> data;
|
||||||
istream.read(data.buff, sizeof(UBYT));
|
istream.read(data.buff, sizeof(UBYT));
|
||||||
|
if (istream.fail())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Not enough data was available to read UBYT value (" << m_name << ").";
|
||||||
|
throw parse_error(oss.str());
|
||||||
|
}
|
||||||
m_value = data.value;
|
m_value = data.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,12 +19,20 @@ namespace dml
|
||||||
template <>
|
template <>
|
||||||
void UIntField::read_from(std::istream &istream)
|
void UIntField::read_from(std::istream &istream)
|
||||||
{
|
{
|
||||||
ValueBytes<USHRT> endianness_check;
|
|
||||||
endianness_check.value = 0x0102;
|
|
||||||
ValueBytes<UINT> data;
|
ValueBytes<UINT> data;
|
||||||
istream.read(data.buff, sizeof(UINT));
|
istream.read(data.buff, sizeof(UINT));
|
||||||
|
if (istream.fail())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Not enough data was available to read UINT value (" << m_name << ").";
|
||||||
|
throw parse_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueBytes<USHRT> endianness_check;
|
||||||
|
endianness_check.value = 0x0102;
|
||||||
if (endianness_check.buff[0] == 0x01)
|
if (endianness_check.buff[0] == 0x01)
|
||||||
std::reverse(&data.buff[0], &data.buff[4]);
|
std::reverse(&data.buff[0], &data.buff[4]);
|
||||||
|
|
||||||
m_value = data.value;
|
m_value = data.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,13 @@ namespace dml
|
||||||
endianness_check.value = 0x0102;
|
endianness_check.value = 0x0102;
|
||||||
ValueBytes<USHRT> data;
|
ValueBytes<USHRT> data;
|
||||||
istream.read(data.buff, sizeof(USHRT));
|
istream.read(data.buff, sizeof(USHRT));
|
||||||
|
if (istream.fail())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Not enough data was available to read USHRT value (" << m_name << ").";
|
||||||
|
throw parse_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
if (endianness_check.buff[0] == 0x01)
|
if (endianness_check.buff[0] == 0x01)
|
||||||
std::reverse(&data.buff[0], &data.buff[2]);
|
std::reverse(&data.buff[0], &data.buff[2]);
|
||||||
m_value = data.value;
|
m_value = data.value;
|
||||||
|
|
|
@ -23,10 +23,17 @@ namespace dml
|
||||||
void WStrField::read_from(std::istream &istream)
|
void WStrField::read_from(std::istream &istream)
|
||||||
{
|
{
|
||||||
// Get the length
|
// Get the length
|
||||||
ValueBytes<USHRT> endianness_check;
|
|
||||||
endianness_check.value = 0x0102;
|
|
||||||
ValueBytes<USHRT> length_data;
|
ValueBytes<USHRT> length_data;
|
||||||
istream.read(length_data.buff, sizeof(USHRT));
|
istream.read(length_data.buff, sizeof(USHRT));
|
||||||
|
if (istream.fail())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Not enough data was available to read WSTR value (" << m_name << ").";
|
||||||
|
throw parse_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueBytes<USHRT> endianness_check;
|
||||||
|
endianness_check.value = 0x0102;
|
||||||
if (endianness_check.buff[0] == 0x01)
|
if (endianness_check.buff[0] == 0x01)
|
||||||
std::reverse(&length_data.buff[0], &length_data.buff[2]);
|
std::reverse(&length_data.buff[0], &length_data.buff[2]);
|
||||||
|
|
||||||
|
@ -34,11 +41,21 @@ namespace dml
|
||||||
size_t length = length_data.value * sizeof(char16_t);
|
size_t length = length_data.value * sizeof(char16_t);
|
||||||
char *data = new char[length + sizeof(char16_t)]{ 0 };
|
char *data = new char[length + sizeof(char16_t)]{ 0 };
|
||||||
istream.read(data, length);
|
istream.read(data, length);
|
||||||
|
if (istream.fail())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Not enough data was available to read WSTR value (" << m_name << ").";
|
||||||
|
throw parse_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse each character from little endian to big endian
|
||||||
|
// if memory is supposed to be in big endian on this PC.
|
||||||
for (int i = 0; i < length; i += 2)
|
for (int i = 0; i < length; i += 2)
|
||||||
{
|
{
|
||||||
if (endianness_check.buff[0] == 0x01)
|
if (endianness_check.buff[0] == 0x01)
|
||||||
std::reverse(&data[i], &data[i + 2]);
|
std::reverse(&data[i], &data[i + 2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_value = WSTR((char16_t *)data);
|
m_value = WSTR((char16_t *)data);
|
||||||
delete[] data;
|
delete[] data;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue