diff options
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/llapp.cpp | 11 | ||||
-rw-r--r-- | indra/llcommon/llapr.cpp | 8 | ||||
-rw-r--r-- | indra/llcommon/llfile.cpp | 27 | ||||
-rw-r--r-- | indra/llcommon/llfile.h | 9 | ||||
-rw-r--r-- | indra/llcommon/llsdserialize.cpp | 761 | ||||
-rw-r--r-- | indra/llcommon/llsdserialize.h | 232 | ||||
-rw-r--r-- | indra/llcommon/llsdserialize_xml.cpp | 23 | ||||
-rw-r--r-- | indra/llcommon/llstreamtools.cpp | 27 | ||||
-rw-r--r-- | indra/llcommon/llstreamtools.h | 7 |
9 files changed, 814 insertions, 291 deletions
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 2347ac9cd9..6591bbc070 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -166,7 +166,16 @@ bool LLApp::parseCommandOptions(int argc, char** argv) // we found another option after this one or we have // reached the end. simply record that this option was // found and continue. - commands[name] = true; + int flag = name.compare("logfile"); + if (0 == flag) + { + commands[name] = "log"; + } + else + { + commands[name] = true; + } + continue; } ++ii; diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index be3a52da0d..861cf814e2 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -292,7 +292,7 @@ bool ll_apr_file_remove(const LLString& filename, apr_pool_t* pool) s = apr_file_remove(filename.c_str(), pool); if (s != APR_SUCCESS) { - llwarns << "ll_apr_file_remove failed on file: " << filename << llendl; + lldebugs << "ll_apr_file_remove failed on file: " << filename << llendl; return false; } return true; @@ -305,7 +305,7 @@ bool ll_apr_file_rename(const LLString& filename, const LLString& newname, apr_p s = apr_file_rename(filename.c_str(), newname.c_str(), pool); if (s != APR_SUCCESS) { - llwarns << "ll_apr_file_rename failed on file: " << filename << llendl; + lldebugs << "ll_apr_file_rename failed on file: " << filename << llendl; return false; } return true; @@ -361,7 +361,7 @@ bool ll_apr_dir_make(const LLString& dirname, apr_pool_t* pool) s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool); if (s != APR_SUCCESS) { - llwarns << "ll_apr_file_remove failed on file: " << dirname << llendl; + lldebugs << "ll_apr_dir_make failed on file: " << dirname << llendl; return false; } return true; @@ -374,7 +374,7 @@ bool ll_apr_dir_remove(const LLString& dirname, apr_pool_t* pool) s = apr_file_remove(dirname.c_str(), pool); if (s != APR_SUCCESS) { - llwarns << "ll_apr_file_remove failed on file: " << dirname << llendl; + lldebugs << "ll_apr_dir_remove failed on file: " << dirname << llendl; return false; } return true; diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index eb76b20d23..241b13f84f 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -291,3 +291,30 @@ llofstream::~llofstream() #endif // #if USE_LLFILESTREAMS +/************** helper functions ********************************/ + +std::streamsize llifstream_size(llifstream& ifstr) +{ + if(!ifstr.is_open()) return 0; + std::streampos pos_old = ifstr.tellg(); + ifstr.seekg(0, ios_base::beg); + std::streampos pos_beg = ifstr.tellg(); + ifstr.seekg(0, ios_base::end); + std::streampos pos_end = ifstr.tellg(); + ifstr.seekg(pos_old, ios_base::beg); + return pos_end - pos_beg; +} + +std::streamsize llofstream_size(llofstream& ofstr) +{ + if(!ofstr.is_open()) return 0; + std::streampos pos_old = ofstr.tellp(); + ofstr.seekp(0, ios_base::beg); + std::streampos pos_beg = ofstr.tellp(); + ofstr.seekp(0, ios_base::end); + std::streampos pos_end = ofstr.tellp(); + ofstr.seekp(pos_old, ios_base::beg); + return pos_end - pos_beg; +} + + diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index f51cea9219..7a1542a6fa 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -168,5 +168,14 @@ private: #endif +/** + * @breif filesize helpers. + * + * The file size helpers are not considered particularly efficient, + * and should only be used for config files and the like -- not in a + * loop. + */ +std::streamsize llifstream_size(llifstream& fstr); +std::streamsize llofstream_size(llofstream& fstr); #endif // not LL_LLFILE_H diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 5ab94715c5..02152cfe79 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -45,26 +45,18 @@ #include "lldate.h" #include "llsd.h" +#include "llstring.h" #include "lluri.h" // File constants static const int MAX_HDR_LEN = 20; static const char LEGACY_NON_HEADER[] = "<llsd>"; +const std::string LLSD_BINARY_HEADER("LLSD/Binary"); +const std::string LLSD_XML_HEADER("LLSD/XML"); -//static -const char* LLSDSerialize::LLSDBinaryHeader = "LLSD/Binary"; - -//static -const char* LLSDSerialize::LLSDXMLHeader = "LLSD/XML"; - -// virtual -LLSDParser::~LLSDParser() -{ } - -// virtual -LLSDNotationParser::~LLSDNotationParser() -{ } - +/** + * LLSDSerialize + */ // static void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type, U32 options) @@ -74,12 +66,12 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize switch (type) { case LLSD_BINARY: - str << "<? " << LLSDBinaryHeader << " ?>\n"; + str << "<? " << LLSD_BINARY_HEADER << " ?>\n"; f = new LLSDBinaryFormatter; break; case LLSD_XML: - str << "<? " << LLSDXMLHeader << " ?>\n"; + str << "<? " << LLSD_XML_HEADER << " ?>\n"; f = new LLSDXMLFormatter; break; @@ -94,7 +86,7 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize } // static -bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str) +bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes) { LLPointer<LLSDParser> p = NULL; char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */ @@ -102,8 +94,8 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str) int inbuf = 0; bool legacy_no_header = false; bool fail_if_not_legacy = false; - std::string header = ""; - + std::string header; + /* * Get the first line before anything. */ @@ -155,15 +147,15 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str) */ if (legacy_no_header) { - LLSDXMLParser *x = new LLSDXMLParser; + LLSDXMLParser* x = new LLSDXMLParser; x->parsePart(hdr_buf, inbuf); p = x; } - else if (header == LLSDBinaryHeader) + else if (header == LLSD_BINARY_HEADER) { p = new LLSDBinaryParser; } - else if (header == LLSDXMLHeader) + else if (header == LLSD_XML_HEADER) { p = new LLSDXMLParser; } @@ -174,7 +166,7 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str) if (p.notNull()) { - p->parse(str, sd); + p->parse(str, sd, max_bytes); return true; } @@ -230,11 +222,69 @@ F64 ll_ntohd(F64 netdouble) /** * Local functions. */ -bool deserialize_string(std::istream& str, std::string& value); -bool deserialize_string_delim(std::istream& str, std::string& value, char d); -bool deserialize_string_raw(std::istream& str, std::string& value); +/** + * @brief Figure out what kind of string it is (raw or delimited) and handoff. + * + * @param istr The stream to read from. + * @param value [out] The string which was found. + * @param max_bytes The maximum possible length of the string. + * @return Returns number of bytes read off of the stream. Returns + * PARSE_FAILURE (-1) on failure. + */ +int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes); + +/** + * @brief Parse a delimited string. + * + * @param istr The stream to read from, with the delimiter already popped. + * @param value [out] The string which was found. + * @param d The delimiter to use. + * @return Returns number of bytes read off of the stream. Returns + * PARSE_FAILURE (-1) on failure. + */ +int deserialize_string_delim(std::istream& istr, std::string& value, char d); + +/** + * @brief Read a raw string off the stream. + * + * @param istr The stream to read from, with the (len) parameter + * leading the stream. + * @param value [out] The string which was found. + * @param d The delimiter to use. + * @param max_bytes The maximum possible length of the string. + * @return Returns number of bytes read off of the stream. Returns + * PARSE_FAILURE (-1) on failure. + */ +int deserialize_string_raw( + std::istream& istr, + std::string& value, + S32 max_bytes); + +/** + * @brief helper method for dealing with the different notation boolean format. + * + * @param istr The stream to read from with the leading character stripped. + * @param data [out] the result of the parse. + * @param compare The string to compare the boolean against + * @param vale The value to assign to data if the parse succeeds. + * @return Returns number of bytes read off of the stream. Returns + * PARSE_FAILURE (-1) on failure. + */ +int deserialize_boolean( + std::istream& istr, + LLSD& data, + const std::string& compare, + bool value); + +/** + * @brief Do notation escaping of a string to an ostream. + * + * @param value The string to escape and serialize + * @param str The stream to serialize to. + */ void serialize_string(const std::string& value, std::ostream& str); + /** * Local constants. */ @@ -244,20 +294,96 @@ static const std::string NOTATION_FALSE_SERIAL("false"); static const char BINARY_TRUE_SERIAL = '1'; static const char BINARY_FALSE_SERIAL = '0'; -static const S32 NOTATION_PARSE_FAILURE = -1; /** * LLSDParser */ -LLSDParser::LLSDParser() +LLSDParser::LLSDParser() : mCheckLimits(true), mMaxBytesLeft(0) +{ +} + +// virtual +LLSDParser::~LLSDParser() +{ } + +S32 LLSDParser::parse(std::istream& istr, LLSD& data, S32 max_bytes) +{ + mCheckLimits = (LLSDSerialize::SIZE_UNLIMITED == max_bytes) ? false : true; + mMaxBytesLeft = max_bytes; + return doParse(istr, data); +} + + +int LLSDParser::get(std::istream& istr) const +{ + if(mCheckLimits) --mMaxBytesLeft; + return istr.get(); +} + +std::istream& LLSDParser::get( + std::istream& istr, + char* s, + std::streamsize n, + char delim) const +{ + istr.get(s, n, delim); + if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); + return istr; +} + +std::istream& LLSDParser::get( + std::istream& istr, + std::streambuf& sb, + char delim) const +{ + istr.get(sb, delim); + if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); + return istr; +} + +std::istream& LLSDParser::ignore(std::istream& istr) const { + istr.ignore(); + if(mCheckLimits) --mMaxBytesLeft; + return istr; } +std::istream& LLSDParser::putback(std::istream& istr, char c) const +{ + istr.putback(c); + if(mCheckLimits) ++mMaxBytesLeft; + return istr; +} + +std::istream& LLSDParser::read( + std::istream& istr, + char* s, + std::streamsize n) const +{ + istr.read(s, n); + if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); + return istr; +} + +void LLSDParser::account(S32 bytes) const +{ + if(mCheckLimits) mMaxBytesLeft -= bytes; +} + + /** * LLSDNotationParser */ +LLSDNotationParser::LLSDNotationParser() +{ +} + +// virtual +LLSDNotationParser::~LLSDNotationParser() +{ } + // virtual -S32 LLSDNotationParser::parse(std::istream& istr, LLSD& data) const +S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const { // map: { string:object, string:object } // array: [ object, object, object ] @@ -275,7 +401,7 @@ S32 LLSDNotationParser::parse(std::istream& istr, LLSD& data) const while(isspace(c)) { // pop the whitespace. - c = istr.get(); + c = get(istr); c = istr.peek(); continue; } @@ -287,107 +413,142 @@ S32 LLSDNotationParser::parse(std::istream& istr, LLSD& data) const switch(c) { case '{': - parse_count += parseMap(istr, data); - if(istr.fail()) + { + S32 child_count = parseMap(istr, data); + if((child_count == PARSE_FAILURE) || data.isUndefined()) { - llinfos << "STREAM FAILURE reading map." << llendl; + parse_count = PARSE_FAILURE; } - if(data.isUndefined()) + else { - parse_count = NOTATION_PARSE_FAILURE; + parse_count += child_count; + } + if(istr.fail()) + { + llinfos << "STREAM FAILURE reading map." << llendl; + parse_count = PARSE_FAILURE; } break; + } case '[': - parse_count += parseArray(istr, data); - if(istr.fail()) + { + S32 child_count = parseArray(istr, data); + if((child_count == PARSE_FAILURE) || data.isUndefined()) { - llinfos << "STREAM FAILURE reading array." << llendl; + parse_count = PARSE_FAILURE; } - if(data.isUndefined()) + else { - parse_count = NOTATION_PARSE_FAILURE; + parse_count += child_count; + } + if(istr.fail()) + { + llinfos << "STREAM FAILURE reading array." << llendl; + parse_count = PARSE_FAILURE; } break; + } case '!': - c = istr.get(); + c = get(istr); data.clear(); break; case '0': - c = istr.get(); + c = get(istr); data = false; break; case 'F': case 'f': - do + ignore(istr); + c = istr.peek(); + if(isalpha(c)) { - istr.ignore(); - c = istr.peek(); - } while (isalpha(c)); - data = false; + int cnt = deserialize_boolean( + istr, + data, + NOTATION_FALSE_SERIAL, + false); + if(PARSE_FAILURE == cnt) parse_count = cnt; + else account(cnt); + } + else + { + data = false; + } if(istr.fail()) { llinfos << "STREAM FAILURE reading boolean." << llendl; + parse_count = PARSE_FAILURE; } break; case '1': - c = istr.get(); + c = get(istr); data = true; break; case 'T': case 't': - do + ignore(istr); + c = istr.peek(); + if(isalpha(c)) { - istr.ignore(); - c = istr.peek(); - } while (isalpha(c)); - data = true; + int cnt = deserialize_boolean(istr,data,NOTATION_TRUE_SERIAL,true); + if(PARSE_FAILURE == cnt) parse_count = cnt; + else account(cnt); + } + else + { + data = true; + } if(istr.fail()) { llinfos << "STREAM FAILURE reading boolean." << llendl; + parse_count = PARSE_FAILURE; } break; case 'i': { - c = istr.get(); + c = get(istr); S32 integer = 0; istr >> integer; data = integer; if(istr.fail()) { llinfos << "STREAM FAILURE reading integer." << llendl; + parse_count = PARSE_FAILURE; } break; } case 'r': { - c = istr.get(); + c = get(istr); F64 real = 0.0; istr >> real; data = real; if(istr.fail()) { llinfos << "STREAM FAILURE reading real." << llendl; + parse_count = PARSE_FAILURE; } break; } case 'u': { - c = istr.get(); + c = get(istr); LLUUID id; istr >> id; data = id; if(istr.fail()) { llinfos << "STREAM FAILURE reading uuid." << llendl; + parse_count = PARSE_FAILURE; } break; } @@ -395,126 +556,144 @@ S32 LLSDNotationParser::parse(std::istream& istr, LLSD& data) const case '\"': case '\'': case 's': - parseString(istr, data); - if(istr.fail()) + if(!parseString(istr, data)) { - llinfos << "STREAM FAILURE reading string." << llendl; + parse_count = PARSE_FAILURE; } - if(data.isUndefined()) + if(istr.fail()) { - parse_count = NOTATION_PARSE_FAILURE; + llinfos << "STREAM FAILURE reading string." << llendl; + parse_count = PARSE_FAILURE; } break; case 'l': { - c = istr.get(); // pop the 'l' - c = istr.get(); // pop the delimiter + c = get(istr); // pop the 'l' + c = get(istr); // pop the delimiter std::string str; - deserialize_string_delim(istr, str, c); - data = LLURI(str); + int cnt = deserialize_string_delim(istr, str, c); + if(PARSE_FAILURE == cnt) + { + parse_count = PARSE_FAILURE; + } + else + { + data = LLURI(str); + account(cnt); + } if(istr.fail()) { llinfos << "STREAM FAILURE reading link." << llendl; + parse_count = PARSE_FAILURE; } break; } case 'd': { - c = istr.get(); // pop the 'd' - c = istr.get(); // pop the delimiter + c = get(istr); // pop the 'd' + c = get(istr); // pop the delimiter std::string str; - deserialize_string_delim(istr, str, c); - data = LLDate(str); + int cnt = deserialize_string_delim(istr, str, c); + if(PARSE_FAILURE == cnt) + { + parse_count = PARSE_FAILURE; + } + else + { + data = LLDate(str); + account(cnt); + } if(istr.fail()) { llinfos << "STREAM FAILURE reading date." << llendl; + parse_count = PARSE_FAILURE; } break; } case 'b': - parseBinary(istr, data); - if(istr.fail()) + if(!parseBinary(istr, data)) { - llinfos << "STREAM FAILURE reading data." << llendl; + parse_count = PARSE_FAILURE; } - if(data.isUndefined()) + if(istr.fail()) { - parse_count = NOTATION_PARSE_FAILURE; + llinfos << "STREAM FAILURE reading data." << llendl; + parse_count = PARSE_FAILURE; } break; default: - data.clear(); - parse_count = NOTATION_PARSE_FAILURE; + parse_count = PARSE_FAILURE; llinfos << "Unrecognized character while parsing: int(" << (int)c - << ")" << llendl; + << ")" << llendl; break; } + if(PARSE_FAILURE == parse_count) + { + data.clear(); + } return parse_count; } -// static -LLSD LLSDNotationParser::parse(std::istream& istr) -{ - LLSDNotationParser parser; - LLSD rv; - S32 count = parser.parse(istr, rv); - lldebugs << "LLSDNotationParser::parse parsed " << count << " objects." - << llendl; - return rv; -} - S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map) const { // map: { string:object, string:object } map = LLSD::emptyMap(); S32 parse_count = 0; - char c = istr.get(); + char c = get(istr); if(c == '{') { // eat commas, white bool found_name = false; std::string name; - c = istr.get(); + c = get(istr); while(c != '}' && istr.good()) { if(!found_name) { if((c == '\"') || (c == '\'') || (c == 's')) { - istr.putback(c); + putback(istr, c); found_name = true; - deserialize_string(istr, name); + int count = deserialize_string(istr, name, mMaxBytesLeft); + if(PARSE_FAILURE == count) return PARSE_FAILURE; + account(count); } - c = istr.get(); + c = get(istr); } else { if(isspace(c) || (c == ':')) { - c = istr.get(); + c = get(istr); continue; } - istr.putback(c); + putback(istr, c); LLSD child; - S32 count = parse(istr, child); + S32 count = doParse(istr, child); if(count > 0) { + // There must be a value for every key, thus + // child_count must be greater than 0. parse_count += count; map.insert(name, child); } else { - map.clear(); - return NOTATION_PARSE_FAILURE; + return PARSE_FAILURE; } found_name = false; - c = istr.get(); + c = get(istr); } } + if(c != '}') + { + map.clear(); + return PARSE_FAILURE; + } } return parse_count; } @@ -524,52 +703,51 @@ S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array) const // array: [ object, object, object ] array = LLSD::emptyArray(); S32 parse_count = 0; - char c = istr.get(); + char c = get(istr); if(c == '[') { // eat commas, white - c = istr.get(); + c = get(istr); while((c != ']') && istr.good()) { LLSD child; if(isspace(c) || (c == ',')) { - c = istr.get(); + c = get(istr); continue; } - istr.putback(c); - S32 count = parse(istr, child); - if(count > 0) + putback(istr, c); + S32 count = doParse(istr, child); + if(PARSE_FAILURE == count) { - parse_count += count; - array.append(child); + return PARSE_FAILURE; } else { - array.clear(); - return NOTATION_PARSE_FAILURE; + parse_count += count; + array.append(child); } - c = istr.get(); + c = get(istr); + } + if(c != ']') + { + return PARSE_FAILURE; } } return parse_count; } -void LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const +bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const { std::string value; - if(deserialize_string(istr, value)) - { - data = value; - } - else - { - // failed to parse. - data.clear(); - } + int count = deserialize_string(istr, value, mMaxBytesLeft); + if(PARSE_FAILURE == count) return false; + account(count); + data = value; + return true; } -void LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const +bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const { // binary: b##"ff3120ab1" // or: b(len)"..." @@ -582,40 +760,44 @@ void LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const // need to read the base out. char buf[BINARY_BUFFER_SIZE]; /* Flawfinder: ignore */ - istr.get(buf, STREAM_GET_COUNT, '"'); - char c = istr.get(); - if((c == '"') && (0 == strncmp("b(", buf, 2))) + get(istr, buf, STREAM_GET_COUNT, '"'); + char c = get(istr); + if(c != '"') return false; + if(0 == strncmp("b(", buf, 2)) { // We probably have a valid raw binary stream. determine // the size, and read it. - // *FIX: Should we set a maximum size? S32 len = strtol(buf + 2, NULL, 0); + if(len > mMaxBytesLeft) return false; std::vector<U8> value; if(len) { value.resize(len); - fullread(istr, (char *)&value[0], len); + account(fullread(istr, (char *)&value[0], len)); } - c = istr.get(); // strip off the trailing double-quote + c = get(istr); // strip off the trailing double-quote data = value; } - else if((c == '"') && (0 == strncmp("b64", buf, 3))) + else if(0 == strncmp("b64", buf, 3)) { // *FIX: A bit inefficient, but works for now. To make the // format better, I would need to add a hint into the // serialization format that indicated how long it was. std::stringstream coded_stream; - istr.get(*(coded_stream.rdbuf()), '\"'); - c = istr.get(); + get(istr, *(coded_stream.rdbuf()), '\"'); + c = get(istr); std::string encoded(coded_stream.str()); S32 len = apr_base64_decode_len(encoded.c_str()); std::vector<U8> value; - value.resize(len); - len = apr_base64_decode_binary(&value[0], encoded.c_str()); - value.resize(len); + if(len) + { + value.resize(len); + len = apr_base64_decode_binary(&value[0], encoded.c_str()); + value.resize(len); + } data = value; } - else if((c == '"') && (0 == strncmp("b16", buf, 3))) + else if(0 == strncmp("b16", buf, 3)) { // yay, base 16. We pop the next character which is either a // double quote or base 16 data. If it's a double quote, we're @@ -626,14 +808,14 @@ void LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const U8 byte_buffer[BINARY_BUFFER_SIZE]; U8* write; std::vector<U8> value; - c = istr.get(); + c = get(istr); while(c != '"') { - istr.putback(c); + putback(istr, c); read = buf; write = byte_buffer; - istr.get(buf, STREAM_GET_COUNT, '"'); - c = istr.get(); + get(istr, buf, STREAM_GET_COUNT, '"'); + c = get(istr); while(*read != '\0') /*Flawfinder: ignore*/ { byte = hex_as_nybble(*read++); @@ -648,8 +830,9 @@ void LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const } else { - data.clear(); + return false; } + return true; } @@ -666,7 +849,7 @@ LLSDBinaryParser::~LLSDBinaryParser() } // virtual -S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const +S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const { /** * Undefined: '!'<br> @@ -685,7 +868,7 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const * notation format. */ char c; - c = istr.get(); + c = get(istr); if(!istr.good()) { return 0; @@ -694,20 +877,42 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const switch(c) { case '{': - parse_count += parseMap(istr, data); + { + S32 child_count = parseMap(istr, data); + if((child_count == PARSE_FAILURE) || data.isUndefined()) + { + parse_count = PARSE_FAILURE; + } + else + { + parse_count += child_count; + } if(istr.fail()) { llinfos << "STREAM FAILURE reading binary map." << llendl; + parse_count = PARSE_FAILURE; } break; + } case '[': - parse_count += parseArray(istr, data); + { + S32 child_count = parseArray(istr, data); + if((child_count == PARSE_FAILURE) || data.isUndefined()) + { + parse_count = PARSE_FAILURE; + } + else + { + parse_count += child_count; + } if(istr.fail()) { llinfos << "STREAM FAILURE reading binary array." << llendl; + parse_count = PARSE_FAILURE; } break; + } case '!': data.clear(); @@ -724,7 +929,7 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const case 'i': { U32 value_nbo = 0; - istr.read((char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ data = (S32)ntohl(value_nbo); if(istr.fail()) { @@ -736,7 +941,7 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const case 'r': { F64 real_nbo = 0.0; - istr.read((char*)&real_nbo, sizeof(F64)); /*Flawfinder: ignore*/ + read(istr, (char*)&real_nbo, sizeof(F64)); /*Flawfinder: ignore*/ data = ll_ntohd(real_nbo); if(istr.fail()) { @@ -748,7 +953,7 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const case 'u': { LLUUID id; - istr.read((char*)(&id.mData), UUID_BYTES); /*Flawfinder: ignore*/ + read(istr, (char*)(&id.mData), UUID_BYTES); /*Flawfinder: ignore*/ data = id; if(istr.fail()) { @@ -761,19 +966,40 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const case '"': { std::string value; - deserialize_string_delim(istr, value, c); - data = value; + int cnt = deserialize_string_delim(istr, value, c); + if(PARSE_FAILURE == cnt) + { + parse_count = PARSE_FAILURE; + } + else + { + data = value; + account(cnt); + } + if(istr.fail()) + { + llinfos << "STREAM FAILURE reading binary (notation-style) string." + << llendl; + parse_count = PARSE_FAILURE; + } break; } case 's': { std::string value; - parseString(istr, value); - data = value; + if(parseString(istr, value)) + { + data = value; + } + else + { + parse_count = PARSE_FAILURE; + } if(istr.fail()) { llinfos << "STREAM FAILURE reading binary string." << llendl; + parse_count = PARSE_FAILURE; } break; } @@ -781,11 +1007,18 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const case 'l': { std::string value; - parseString(istr, value); - data = LLURI(value); + if(parseString(istr, value)) + { + data = LLURI(value); + } + else + { + parse_count = PARSE_FAILURE; + } if(istr.fail()) { llinfos << "STREAM FAILURE reading binary link." << llendl; + parse_count = PARSE_FAILURE; } break; } @@ -793,11 +1026,12 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const case 'd': { F64 real = 0.0; - istr.read((char*)&real, sizeof(F64)); /*Flawfinder: ignore*/ + read(istr, (char*)&real, sizeof(F64)); /*Flawfinder: ignore*/ data = LLDate(real); if(istr.fail()) { llinfos << "STREAM FAILURE reading binary date." << llendl; + parse_count = PARSE_FAILURE; } break; } @@ -806,75 +1040,94 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const { // We probably have a valid raw binary stream. determine // the size, and read it. - // *FIX: Should we set a maximum size? U32 size_nbo = 0; - istr.read((char*)&size_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + read(istr, (char*)&size_nbo, sizeof(U32)); /*Flawfinder: ignore*/ S32 size = (S32)ntohl(size_nbo); - std::vector<U8> value; - if(size) + if(size > mMaxBytesLeft) { - value.resize(size); - istr.read((char*)&value[0], size); /*Flawfinder: ignore*/ + parse_count = PARSE_FAILURE; + } + else + { + std::vector<U8> value; + if(size > 0) + { + value.resize(size); + account(fullread(istr, (char*)&value[0], size)); + } + data = value; } - data = value; if(istr.fail()) { llinfos << "STREAM FAILURE reading binary." << llendl; + parse_count = PARSE_FAILURE; } break; } default: - --parse_count; + parse_count = PARSE_FAILURE; llinfos << "Unrecognized character while parsing: int(" << (int)c - << ")" << llendl; + << ")" << llendl; break; } + if(PARSE_FAILURE == parse_count) + { + data.clear(); + } return parse_count; } -// static -LLSD LLSDBinaryParser::parse(std::istream& istr) -{ - LLSDBinaryParser parser; - LLSD rv; - S32 count = parser.parse(istr, rv); - lldebugs << "LLSDBinaryParser::parse parsed " << count << " objects." - << llendl; - return rv; -} - S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map) const { map = LLSD::emptyMap(); U32 value_nbo = 0; - istr.read((char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ S32 size = (S32)ntohl(value_nbo); S32 parse_count = 0; S32 count = 0; - char c = istr.get(); + char c = get(istr); while(c != '}' && (count < size) && istr.good()) { std::string name; switch(c) { case 'k': - parseString(istr, name); + if(!parseString(istr, name)) + { + return PARSE_FAILURE; + } break; case '\'': case '"': - deserialize_string_delim(istr, name, c); + { + int cnt = deserialize_string_delim(istr, name, c); + if(PARSE_FAILURE == cnt) return PARSE_FAILURE; + account(cnt); break; } + } LLSD child; - S32 child_count = parse(istr, child); - if(child_count) + S32 child_count = doParse(istr, child); + if(child_count > 0) { + // There must be a value for every key, thus child_count + // must be greater than 0. parse_count += child_count; map.insert(name, child); } + else + { + return PARSE_FAILURE; + } ++count; - c = istr.get(); + c = get(istr); + } + if((c != '}') || (count < size)) + { + // Make sure it is correctly terminated and we parsed as many + // as were said to be there. + return PARSE_FAILURE; } return parse_count; } @@ -883,7 +1136,7 @@ S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const { array = LLSD::emptyArray(); U32 value_nbo = 0; - istr.read((char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ S32 size = (S32)ntohl(value_nbo); // *FIX: This would be a good place to reserve some space in the @@ -895,7 +1148,11 @@ S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const while((c != ']') && (count < size) && istr.good()) { LLSD child; - S32 child_count = parse(istr, child); + S32 child_count = doParse(istr, child); + if(PARSE_FAILURE == child_count) + { + return PARSE_FAILURE; + } if(child_count) { parse_count += child_count; @@ -904,22 +1161,33 @@ S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const ++count; c = istr.peek(); } - c = istr.get(); + c = get(istr); + if((c != ']') || (count < size)) + { + // Make sure it is correctly terminated and we parsed as many + // as were said to be there. + return PARSE_FAILURE; + } return parse_count; } -void LLSDBinaryParser::parseString( +bool LLSDBinaryParser::parseString( std::istream& istr, std::string& value) const { // *FIX: This is memory inefficient. U32 value_nbo = 0; - istr.read((char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ S32 size = (S32)ntohl(value_nbo); + if(size > mMaxBytesLeft) return false; std::vector<char> buf; - buf.resize(size); - istr.read(&buf[0], size); /*Flawfinder: ignore*/ - value.assign(buf.begin(), buf.end()); + if(size) + { + buf.resize(size); + account(fullread(istr, &buf[0], size)); + value.assign(buf.begin(), buf.end()); + } + return true; } @@ -1217,33 +1485,38 @@ void LLSDBinaryFormatter::formatString( /** * local functions */ -bool deserialize_string(std::istream& str, std::string& value) +int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes) { - char c = str.get(); - if (str.fail()) + char c = istr.get(); + if(istr.fail()) { - // No data in stream, bail out - return false; + // No data in stream, bail out but mention the character we + // grabbed. + return LLSDParser::PARSE_FAILURE; } - bool rv = false; + int rv = LLSDParser::PARSE_FAILURE; switch(c) { case '\'': case '"': - rv = deserialize_string_delim(str, value, c); + rv = deserialize_string_delim(istr, value, c); break; case 's': - rv = deserialize_string_raw(str, value); + // technically, less than max_bytes, but this is just meant to + // catch egregious protocol errors. parse errors will be + // caught in the case of incorrect counts. + rv = deserialize_string_raw(istr, value, max_bytes); break; default: break; } - return rv; + if(LLSDParser::PARSE_FAILURE == rv) return rv; + return rv + 1; // account for the character grabbed at the top. } -bool deserialize_string_delim( - std::istream& str, +int deserialize_string_delim( + std::istream& istr, std::string& value, char delim) { @@ -1252,16 +1525,18 @@ bool deserialize_string_delim( bool found_hex = false; bool found_digit = false; U8 byte = 0; - + int count = 0; + while (true) { - char next_char = str.get(); - - if(str.fail()) + char next_char = istr.get(); + ++count; + + if(istr.fail()) { // If our stream is empty, break out value = write_buffer.str(); - return false; + return LLSDParser::PARSE_FAILURE; } if(found_escape) @@ -1338,35 +1613,48 @@ bool deserialize_string_delim( } value = write_buffer.str(); - return true; + return count; } -bool deserialize_string_raw(std::istream& str, std::string& value) +int deserialize_string_raw( + std::istream& istr, + std::string& value, + S32 max_bytes) { - bool ok = false; + int count = 0; const S32 BUF_LEN = 20; char buf[BUF_LEN]; /* Flawfinder: ignore */ - str.get(buf, BUF_LEN - 1, ')'); - char c = str.get(); - c = str.get(); + istr.get(buf, BUF_LEN - 1, ')'); + count += istr.gcount(); + char c = istr.get(); + c = istr.get(); + count += 2; if(((c == '"') || (c == '\'')) && (buf[0] == '(')) { // We probably have a valid raw string. determine // the size, and read it. - // *FIX: Should we set a maximum size? // *FIX: This is memory inefficient. S32 len = strtol(buf + 1, NULL, 0); + if(len > max_bytes) return LLSDParser::PARSE_FAILURE; std::vector<char> buf; - buf.resize(len); - str.read(&buf[0], len); /*Flawfinder: ignore*/ - value.assign(buf.begin(), buf.end()); - c = str.get(); - if((c == '"') || (c == '\'')) + if(len) + { + buf.resize(len); + count += fullread(istr, (char *)&buf[0], len); + value.assign(buf.begin(), buf.end()); + } + c = istr.get(); + ++count; + if(!((c == '"') || (c == '\''))) { - ok = true; + return LLSDParser::PARSE_FAILURE; } } - return ok; + else + { + return LLSDParser::PARSE_FAILURE; + } + return count; } static const char* NOTATION_STRING_CHARACTERS[256] = @@ -1641,6 +1929,43 @@ void serialize_string(const std::string& value, std::ostream& str) } } +int deserialize_boolean( + std::istream& istr, + LLSD& data, + const std::string& compare, + bool value) +{ + // + // this method is a little goofy, because it gets the stream at + // the point where the t or f has already been + // consumed. Basically, parse for a patch to the string passed in + // starting at index 1. If it's a match: + // * assign data to value + // * return the number of bytes read + // otherwise: + // * set data to LLSD::null + // * return LLSDParser::PARSE_FAILURE (-1) + // + int bytes_read = 0; + std::string::size_type ii = 0; + char c = istr.peek(); + while((++ii < compare.size()) + && (tolower(c) == (int)compare[ii]) + && istr.good()) + { + istr.ignore(); + ++bytes_read; + c = istr.peek(); + } + if(compare.size() != ii) + { + data.clear(); + return LLSDParser::PARSE_FAILURE; + } + data = value; + return bytes_read; +} + std::ostream& operator<<(std::ostream& s, const LLSD& llsd) { s << LLSDNotationStreamer(llsd); diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index b4d6683c2e..26ce1dc993 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -40,7 +40,7 @@ /** * @class LLSDParser - * @brief Abstract base class for simple LLSD parsers. + * @brief Abstract base class for LLSD parsers. */ class LLSDParser : public LLRefCount { @@ -52,6 +52,14 @@ protected: public: /** + * @brief Anonymous enum to indicate parsing failure. + */ + enum + { + PARSE_FAILURE = -1 + }; + + /** * @brief Constructor */ LLSDParser(); @@ -67,12 +75,122 @@ public: * caller. * @param istr The input stream. * @param data[out] The newly parse structured data. - * @return Returns The number of LLSD objects parsed into data. + * @param max_bytes The maximum number of bytes that will be in + * the stream. Pass in LLSDSerialize::SIZE_UNLIMITED (-1) to set no + * byte limit. + * @return Returns the number of LLSD objects parsed into + * data. Returns PARSE_FAILURE (-1) on parse failure. + */ + S32 parse(std::istream& istr, LLSD& data, S32 max_bytes); + +protected: + /** + * @brief Pure virtual base for doing the parse. + * + * This method parses the istream for a structured data. This + * method assumes that the istream is a complete llsd object -- + * for example an opened and closed map with an arbitrary nesting + * of elements. This method will return after reading one data + * object, allowing continued reading from the stream by the + * caller. + * @param istr The input stream. + * @param data[out] The newly parse structured data. + * @return Returns the number of LLSD objects parsed into + * data. Returns PARSE_FAILURE (-1) on parse failure. + */ + virtual S32 doParse(std::istream& istr, LLSD& data) const = 0; + + /* @name Simple istream helper methods + * + * These helper methods exist to help correctly use the + * mMaxBytesLeft without really thinking about it for most simple + * operations. Use of the streamtools in llstreamtools.h will + * require custom wrapping. + */ + //@{ + /** + * @brief get a byte off the stream + * + * @param istr The istream to work with. + * @return returns the next character. + */ + int get(std::istream& istr) const; + + /** + * @brief get several bytes off the stream into a buffer. + * + * @param istr The istream to work with. + * @param s The buffer to get into + * @param n Extract maximum of n-1 bytes and null temrinate. + * @param delim Delimiter to get until found. + * @return Returns istr. + */ + std::istream& get( + std::istream& istr, + char* s, + std::streamsize n, + char delim) const; + + /** + * @brief get several bytes off the stream into a streambuf + * + * @param istr The istream to work with. + * @param sb The streambuf to read into + * @param delim Delimiter to get until found. + * @return Returns istr. + */ + std::istream& get( + std::istream& istr, + std::streambuf& sb, + char delim) const; + + /** + * @brief ignore the next byte on the istream + * + * @param istr The istream to work with. + * @return Returns istr. + */ + std::istream& ignore(std::istream& istr) const; + + /** + * @brief put the last character retrieved back on the stream + * + * @param istr The istream to work with. + * @param c The character to put back + * @return Returns istr. + */ + std::istream& putback(std::istream& istr, char c) const; + + /** + * @brief read a block of n characters into a buffer + * + * @param istr The istream to work with. + * @param s The buffer to read into + * @param n The number of bytes to read. + * @return Returns istr. + */ + std::istream& read(std::istream& istr, char* s, std::streamsize n) const; + //@} + +protected: + /** + * @brief Accunt for bytes read outside of the istream helpers. + * + * Conceptually const since it only modifies mutable members. + * @param bytes The number of bytes read. */ - virtual S32 parse(std::istream& istr, LLSD& data) const = 0; + void account(S32 bytes) const; protected: + /** + * @brief boolean to set if byte counts should be checked during parsing. + */ + bool mCheckLimits; + /** + * @brief The maximum number of bytes left to be parsed. + */ + mutable S32 mMaxBytesLeft; }; /** @@ -91,8 +209,9 @@ public: /** * @brief Constructor */ - LLSDNotationParser() {} + LLSDNotationParser(); +protected: /** * @brief Call this method to parse a stream for LLSD. * @@ -105,21 +224,9 @@ public: * @param istr The input stream. * @param data[out] The newly parse structured data. Undefined on failure. * @return Returns the number of LLSD objects parsed into - * data. Returns -1 on parse failure. - */ - virtual S32 parse(std::istream& istr, LLSD& data) const; - - /** - * @brief Simple notation parse. - * - * This simplified parser cannot not distinguish between a failed - * parse and a parse which yields a single undefined LLSD. You can - * use this if error checking will be implicit in the use of the - * results of the parse. - * @param istr The input stream. - * @return Returns the parsed LLSD object. + * data. Returns PARSE_FAILURE (-1) on parse failure. */ - static LLSD parse(std::istream& istr); + virtual S32 doParse(std::istream& istr, LLSD& data) const; private: /** @@ -145,16 +252,18 @@ private: * * @param istr The input stream. * @param data[out] The data to assign. + * @return Retuns true if a complete string was parsed. */ - void parseString(std::istream& istr, LLSD& data) const; + bool parseString(std::istream& istr, LLSD& data) const; /** * @brief Parse binary data from the stream. * * @param istr The input stream. * @param data[out] The data to assign. + * @return Retuns true if a complete blob was parsed. */ - void parseBinary(std::istream& istr, LLSD& data) const; + bool parseBinary(std::istream& istr, LLSD& data) const; }; /** @@ -175,6 +284,7 @@ public: */ LLSDXMLParser(); +protected: /** * @brief Call this method to parse a stream for LLSD. * @@ -186,15 +296,16 @@ public: * caller. * @param istr The input stream. * @param data[out] The newly parse structured data. - * @return Returns the number of LLSD objects parsed into data. + * @return Returns the number of LLSD objects parsed into + * data. Returns PARSE_FAILURE (-1) on parse failure. */ - virtual S32 parse(std::istream& istr, LLSD& data) const; + virtual S32 doParse(std::istream& istr, LLSD& data) const; private: class Impl; Impl& impl; - void parsePart(const char *buf, int len); + void parsePart(const char* buf, int len); friend class LLSDSerialize; }; @@ -216,6 +327,7 @@ public: */ LLSDBinaryParser(); +protected: /** * @brief Call this method to parse a stream for LLSD. * @@ -227,21 +339,10 @@ public: * caller. * @param istr The input stream. * @param data[out] The newly parse structured data. - * @return Returns the number of LLSD objects parsed into data. - */ - virtual S32 parse(std::istream& istr, LLSD& data) const; - - /** - * @brief Simple notation parse. - * - * This simplified parser cannot not distinguish between a failed - * parse and a parse which yields a single undefined LLSD. You can - * use this if error checking will be implicit in the use of the - * results of the parse. - * @param istr The input stream. - * @return Returns the parsed LLSD object. + * @return Returns the number of LLSD objects parsed into + * data. Returns -1 on parse failure. */ - static LLSD parse(std::istream& istr); + virtual S32 doParse(std::istream& istr, LLSD& data) const; private: /** @@ -267,8 +368,9 @@ private: * * @param istr The input stream. * @param value[out] The string to assign. + * @return Retuns true if a complete string was parsed. */ - void parseString(std::istream& istr, std::string& value) const; + bool parseString(std::istream& istr, std::string& value) const; }; @@ -544,7 +646,7 @@ typedef LLSDOStreamer<LLSDXMLFormatter> LLSDXMLStreamer; /** * @class LLSDSerialize - * @Serializer / deserializer for the various LLSD formats + * @brief Serializer / deserializer for the various LLSD formats */ class LLSDSerialize { @@ -554,12 +656,32 @@ public: LLSD_BINARY, LLSD_XML }; + /** + * @brief anonymouse enumeration for useful max_bytes constants. + */ + enum + { + // Setting an unlimited size is discouraged and should only be + // used when reading cin or another stream source which does + // not provide access to size. + SIZE_UNLIMITED = -1, + }; + /* * Generic in/outs */ static void serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize, U32 options = LLSDFormatter::OPTIONS_NONE); - static bool deserialize(LLSD& sd, std::istream& str); + + /** + * @breif Examine a stream, and parse 1 sd object out based on contents. + * + * @param sd [out] The data found on the stream + * @param str The incoming stream + * @param max_bytes the maximum number of bytes to parse + * @return Returns true if the stream appears to contain valid data + */ + static bool deserialize(LLSD& sd, std::istream& str, S32 max_bytes); /* * Notation Methods @@ -569,10 +691,17 @@ public: LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter; return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); } - static S32 fromNotation(LLSD& sd, std::istream& str) + static S32 fromNotation(LLSD& sd, std::istream& str, S32 max_bytes) + { + LLPointer<LLSDNotationParser> p = new LLSDNotationParser; + return p->parse(str, sd, max_bytes); + } + static LLSD fromNotation(std::istream& str, S32 max_bytes) { LLPointer<LLSDNotationParser> p = new LLSDNotationParser; - return p->parse(str, sd); + LLSD sd; + (void)p->parse(str, sd, max_bytes); + return sd; } /* @@ -588,10 +717,13 @@ public: LLPointer<LLSDXMLFormatter> f = new LLSDXMLFormatter; return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY); } + static S32 fromXML(LLSD& sd, std::istream& str) { + // no need for max_bytes since xml formatting is not + // subvertable by bad sizes. LLPointer<LLSDXMLParser> p = new LLSDXMLParser; - return p->parse(str, sd); + return p->parse(str, sd, LLSDSerialize::SIZE_UNLIMITED); } /* @@ -602,14 +734,18 @@ public: LLPointer<LLSDBinaryFormatter> f = new LLSDBinaryFormatter; return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); } - static S32 fromBinary(LLSD& sd, std::istream& str) + static S32 fromBinary(LLSD& sd, std::istream& str, S32 max_bytes) { LLPointer<LLSDBinaryParser> p = new LLSDBinaryParser; - return p->parse(str, sd); + return p->parse(str, sd, max_bytes); + } + static LLSD fromBinary(std::istream& str, S32 max_bytes) + { + LLPointer<LLSDBinaryParser> p = new LLSDBinaryParser; + LLSD sd; + (void)p->parse(str, sd, max_bytes); + return sd; } -private: - static const char *LLSDBinaryHeader; - static const char *LLSDXMLHeader; }; #endif // LL_LLSDSERIALIZE_H diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index 6232622298..b3596e8705 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -305,6 +305,7 @@ private: XML_Parser mParser; LLSD mResult; + S32 mParseCount; bool mInLLSDElement; bool mGracefullStop; @@ -411,12 +412,12 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data) } llinfos << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << llendl; data = LLSD(); - return -1; + return LLSDParser::PARSE_FAILURE; } clear_eol(input); data = mResult; - return 1; + return mParseCount; } void LLSDXMLParser::Impl::reset() @@ -428,6 +429,7 @@ void LLSDXMLParser::Impl::reset() } mResult.clear(); + mParseCount = 0; mInLLSDElement = false; mDepth = 0; @@ -472,7 +474,7 @@ LLSDXMLParser::Impl::findAttribute(const XML_Char* name, const XML_Char** pairs) return NULL; } -void LLSDXMLParser::Impl::parsePart(const char *buf, int len) +void LLSDXMLParser::Impl::parsePart(const char* buf, int len) { void * buffer = XML_GetBuffer(mParser, len); if (buffer != NULL && buf != NULL) @@ -486,7 +488,7 @@ void LLSDXMLParser::Impl::parsePart(const char *buf, int len) void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Char** attributes) { - mDepth += 1; + ++mDepth; if (mSkipping) { return; @@ -554,6 +556,7 @@ void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Ch return startSkipping(); } + ++mParseCount; switch (element) { case ELEMENT_MAP: @@ -572,7 +575,7 @@ void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Ch void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name) { - mDepth -= 1; + --mDepth; if (mSkipping) { if (mDepth < mSkipThrough) @@ -715,10 +718,10 @@ LLSDXMLParser::Impl::Element LLSDXMLParser::Impl::readElement(const XML_Char* na - - -LLSDXMLParser::LLSDXMLParser() - : impl(* new Impl) +/** + * LLSDXMLParser + */ +LLSDXMLParser::LLSDXMLParser() : impl(* new Impl) { } @@ -733,7 +736,7 @@ void LLSDXMLParser::parsePart(const char *buf, int len) } // virtual -S32 LLSDXMLParser::parse(std::istream& input, LLSD& data) const +S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data) const { return impl.parse(input, data); } diff --git a/indra/llcommon/llstreamtools.cpp b/indra/llcommon/llstreamtools.cpp index bfe1765827..8d4a3ef6b8 100644 --- a/indra/llcommon/llstreamtools.cpp +++ b/indra/llcommon/llstreamtools.cpp @@ -538,23 +538,32 @@ void get_keyword_and_value(std::string& keyword, } } -std::istream& fullread(std::istream& str, char *buf, std::streamsize requested) +std::streamsize fullread( + std::istream& istr, + char* buf, + std::streamsize requested) { std::streamsize got; std::streamsize total = 0; - str.read(buf, requested); /*Flawfinder: ignore*/ - got = str.gcount(); + istr.read(buf, requested); /*Flawfinder: ignore*/ + got = istr.gcount(); total += got; - while (got && total < requested) + while(got && total < requested) { - if (str.fail()) - str.clear(); - str.read(buf + total, requested - total); /*Flawfinder: ignore*/ - got = str.gcount(); + if(istr.fail()) + { + // If bad is true, not much we can doo -- it implies loss + // of stream integrity. Bail in that case, and otherwise + // clear and attempt to continue. + if(istr.bad()) return total; + istr.clear(); + } + istr.read(buf + total, requested - total); /*Flawfinder: ignore*/ + got = istr.gcount(); total += got; } - return str; + return total; } std::istream& operator>>(std::istream& str, const char *tocheck) diff --git a/indra/llcommon/llstreamtools.h b/indra/llcommon/llstreamtools.h index 0708447050..b024112f9f 100644 --- a/indra/llcommon/llstreamtools.h +++ b/indra/llcommon/llstreamtools.h @@ -114,7 +114,12 @@ void get_keyword_and_value(std::string& keyword, // continue to read from the stream until you really can't // read anymore or until we hit the count. Some istream // implimentations have a max that they will read. -std::istream& fullread(std::istream& str, char *buf, std::streamsize requested); +// Returns the number of bytes read. +std::streamsize fullread( + std::istream& istr, + char* buf, + std::streamsize requested); + std::istream& operator>>(std::istream& str, const char *tocheck); |