Stricter parsing of XML array attributes.

PiperOrigin-RevId: 451456510
Change-Id: I2556d4365762378261c04d3c9f1942166fbd156e
This commit is contained in:
Alessio Quaglino
2022-05-27 12:50:09 -07:00
committed by Copybara-Service
parent 0741273c86
commit f3453cf87f
4 changed files with 120 additions and 172 deletions
+27 -170
View File
@@ -19,6 +19,7 @@
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <ostream>
#include <sstream>
#include <string>
#include <vector>
@@ -549,8 +550,9 @@ string mjXUtil::FindValue(const mjMap* map, int mapsz, int value) {
// "len" is the number of floats or doubles to be read
// the content is returned in "text", the numeric data in "data"
// return true if attribute found, false if not found and not required
int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, const int len,
double* data, string& text, bool required, bool exact) {
template<typename T>
int mjXUtil::ReadAttrCpp(XMLElement* elem, const char* attr, const int len,
T* data, string& text, bool required, bool exact) {
const char* pstr = elem->Attribute(attr);
// check if attribute exists
@@ -567,34 +569,27 @@ int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, const int len,
// get input stream
istringstream strm(text);
std::string token;
// read numbers
int i;
for (i=0; i<len; i++) {
strm >> data[i];
if (strm.eof()) {
i++;
break;
} else if (strm.bad()) {
int i = 0;
while (!strm.eof() && i < len) {
strm >> token;
istringstream token_strm(token);
token_strm >> data[i++];
if (token_strm.fail() || !token_strm.eof()) {
throw mjXError(elem, "problem reading attribute '%s'", attr);
}
}
strm >> std::ws;
// determine available length
int available = i;
if (strm.good()) {
double dummy;
strm >> dummy;
if (!strm.bad() && !strm.fail()) {
available++;
}
}
// check
if (exact && available<len) {
// check if there is not enough data
if (exact && i < len) {
throw mjXError(elem, "attribute '%s' does not have enough data", attr);
}
if (available>len) {
// check if there is too much data
if (!strm.eof()) {
throw mjXError(elem, "attribute '%s' has too much data", attr);
}
@@ -603,58 +598,17 @@ int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, const int len,
int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, const int len,
double* data, string& text, bool required, bool exact) {
return ReadAttrCpp(elem, attr, len, data, text, required, exact);
}
// float version
int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, const int len,
float* data, string& text, bool required, bool exact) {
const char* pstr = elem->Attribute(attr);
// check if attribute exists
if (!pstr) {
if (required) {
throw mjXError(elem, "required attribute missing: '%s'", attr);
} else {
return 0;
}
}
// convert to string, remove trailing white space
text = string(pstr);
text.erase(text.find_last_not_of(" \t\n\r\f\v") + 1);
// get input stream
istringstream strm(text);
// read numbers
int i;
for (i=0; i<len; i++) {
strm >> data[i];
if (strm.eof()) {
i++;
break;
} else if (strm.bad()) {
throw mjXError(elem, "problem reading attribute '%s'", attr);
}
}
// determine available length
int available = i;
if (strm.good()) {
float dummy;
strm >> dummy;
if (!strm.bad() && !strm.fail()) {
available++;
}
}
// check
if (exact && available<len) {
throw mjXError(elem, "attribute '%s' does not have enough data", attr);
}
if (available>len) {
throw mjXError(elem, "attribute '%s' has too much data", attr);
}
return i;
return ReadAttrCpp(elem, attr, len, data, text, required, exact);
}
@@ -662,55 +616,7 @@ int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, const int len,
// int version
int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, const int len,
int* data, string& text, bool required, bool exact) {
const char* pstr = elem->Attribute(attr);
// check if attribute exists
if (!pstr) {
if (required) {
throw mjXError(elem, "required attribute missing: '%s'", attr);
} else {
return 0;
}
}
// convert to string, remove trailing white space
text = string(pstr);
text.erase(text.find_last_not_of(" \t\n\r\f\v") + 1);
// get input stream
istringstream strm(text);
// read numbers
int i;
for (i=0; i<len; i++) {
strm >> data[i];
if (strm.eof()) {
i++;
break;
} else if (strm.bad()) {
throw mjXError(elem, "problem reading attribute '%s'", attr);
}
}
// determine available length
int available = i;
if (strm.good()) {
mjtByte dummy;
strm >> dummy;
if (!strm.bad() && !strm.fail()) {
available++;
}
}
// check
if (exact && available<len) {
throw mjXError(elem, "attribute '%s' does not have enough data", attr);
}
if (available>len) {
throw mjXError(elem, "attribute '%s' has too much data", attr);
}
return i;
return ReadAttrCpp(elem, attr, len, data, text, required, exact);
}
@@ -718,56 +624,7 @@ int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, const int len,
// byte version
int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, const int len,
mjtByte* data, string& text, bool required, bool exact) {
const char* pstr = elem->Attribute(attr);
// check if attribute exists
if (!pstr) {
if (required) {
throw mjXError(elem, "required attribute missing: '%s'", attr);
} else {
return 0;
}
}
// convert to string, remove trailing white space
text = string(pstr);
text.erase(text.find_last_not_of(" \t\n\r\f\v") + 1);
// get input stream
istringstream strm(text);
// read numbers
int i, tmp;
for (i=0; i<len; i++) {
strm >> tmp;
data[i] = (mjtByte)(tmp & 0xFF);
if (strm.eof()) {
i++;
break;
} else if (strm.bad()) {
throw mjXError(elem, "problem reading attribute '%s'", attr);
}
}
// determine available length
int available = i;
if (strm.good()) {
mjtByte dummy;
strm >> dummy;
if (!strm.bad() && !strm.fail()) {
available++;
}
}
// check
if (exact && available<len) {
throw mjXError(elem, "attribute '%s' does not have enough data", attr);
}
if (available>len) {
throw mjXError(elem, "attribute '%s' has too much data", attr);
}
return i;
return ReadAttrCpp(elem, attr, len, data, text, required, exact);
}
+6
View File
@@ -98,6 +98,12 @@ class mjXUtil {
// find value in map, return key ("": not found)
static std::string FindValue(const mjMap* map, int mapsz, int value);
// read any type from attribute, return number read
template<typename T>
static int ReadAttrCpp(tinyxml2::XMLElement* elem, const char* attr, const int len,
T* data, std::string& text,
bool required = false, bool exact = true);
// read DOUBLE array from attribute, return number read
static int ReadAttr(tinyxml2::XMLElement* elem, const char* attr, const int len,
double* data, std::string& text,