diff --git a/src/Mst.cpp b/src/Mst.cpp index ada4fda..ad3f19f 100644 --- a/src/Mst.cpp +++ b/src/Mst.cpp @@ -13,6 +13,7 @@ // C includes. (C++ namespace) #include +#include #include #include #include @@ -404,8 +405,6 @@ int Mst::loadXML(FILE *fp, std::vector *pVecErrs) return xml.ErrorID(); } - // TODO: Load m_vDiffOffTbl. - // Get the root element: "mst06" XMLElement *const xml_mst06 = xml.FirstChildElement("mst06"); if (!xml_mst06) { @@ -559,6 +558,13 @@ int Mst::loadXML(FILE *fp, std::vector *pVecErrs) // TODO: Check for missing message indexes. + // Load the differential offset table. + // TODO: Error message if not found? + XMLElement *const xml_diffOffTbl = xml_mst06->FirstChildElement("DiffOffTbl"); + if (xml_diffOffTbl) { + unescapeDiffOffTbl(m_vDiffOffTbl, xml_diffOffTbl->GetText()); + } + // Document processed. return 0; } @@ -1167,3 +1173,74 @@ string Mst::escapeDiffOffTbl(const uint8_t *diffOffTbl, size_t len) } return ret; } + +/** + * Unescape an XML-compatible differential offset table. + * @param vDiffOffTbl [out] Vector for the unescaped table. + * @param s_diffOffTbl [in] Differential offset table string. + * @return 0 on success; non-zero on error. + */ +int Mst::unescapeDiffOffTbl(std::vector &vDiffOffTbl, const char *s_diffOffTbl) +{ + vDiffOffTbl.clear(); + if (!s_diffOffTbl) { + return -EINVAL; + } + + // TODO: Default reservation size instead of strlen()? + vDiffOffTbl.reserve(strlen(s_diffOffTbl)); + + for (; s_diffOffTbl[0] != '\0'; s_diffOffTbl++) { + // Check for an escape sequence. + if (s_diffOffTbl[0] == '\\') { + // Found a backslash. + switch (s_diffOffTbl[1]) { + case '\\': + vDiffOffTbl.push_back('\\'); + s_diffOffTbl++; + break; + case 'n': + vDiffOffTbl.push_back('\n'); + s_diffOffTbl++; + break; + case 'f': + vDiffOffTbl.push_back('\f'); + s_diffOffTbl++; + break; + case 'x': + // Next two characters must be hexadecimal digits. + if (!isxdigit(s_diffOffTbl[2]) || !isxdigit(s_diffOffTbl[3])) { + // Invalid sequence. + // Skip over the "\\x" and continue. + // TODO: Return an error? + s_diffOffTbl++; + } else { + // Valid sequence. Convert to uint8_t. + char buf[3]; + buf[0] = s_diffOffTbl[2]; + buf[1] = s_diffOffTbl[3]; + buf[2] = 0; + vDiffOffTbl.push_back(strtoul(buf, nullptr, 16)); + s_diffOffTbl += 3; + } + break; + default: + // Unrecognized escape character. + // Handle the escape as a regular backslash. + // TODO: Return an error? + vDiffOffTbl.push_back('\\'); + break; + } + } else { + // Regular character. + vDiffOffTbl.push_back(static_cast(s_diffOffTbl[0])); + } + } + + // Make sure the table is DWORD-aligned. + if (vDiffOffTbl.size() & 3) { + vDiffOffTbl.resize((vDiffOffTbl.size() + 4) & ~(3ULL)); + } + + return 0; +} diff --git a/src/Mst.hpp b/src/Mst.hpp index e4fa62a..8867dea 100644 --- a/src/Mst.hpp +++ b/src/Mst.hpp @@ -209,6 +209,14 @@ class Mst */ static std::string escapeDiffOffTbl(const uint8_t *diffTbl, size_t len); + /** + * Unescape an XML-compatible differential offset table. + * @param vDiffOffTbl [out] Vector for the unescaped table. + * @param s_diffOffTbl [in] Differential offset table string. + * @return 0 on success; non-zero on error. + */ + static int unescapeDiffOffTbl(std::vector &vDiffOffTbl, const char *s_diffOffTbl); + private: // MST information. char m_version; // MST version number. ('1')