diff options
author | Josh Bell <josh@lindenlab.com> | 2008-02-07 17:15:18 +0000 |
---|---|---|
committer | Josh Bell <josh@lindenlab.com> | 2008-02-07 17:15:18 +0000 |
commit | 8bd6a0b3217ea5614d2a29195e528aa8314f6342 (patch) | |
tree | be5cee5be0678bb03c7174bab9296cfc530d0102 | |
parent | 3314f78a3673c1250e47722848c60d017dafac97 (diff) |
svn merge -r 79445:79449 svn+ssh://svn.lindenlab.com/svn/linden/qa/maintenance-5-merge-79386
QAR-242 merge of maintenance-5 (QAR-203)
* DEV-6548 Copy To Inventory fail to execute without any output feedback when Notecard has changes but not saved
* DEV-7600 Deleting someone else's object in god mode crashes sim
* DEV-5329 LLSD parsers should determine and set maximum parse sizes
* DEV-7473 Resolve instant message crash report
* DEV-2904 Presence Issues not (apparently) caused by scripted attachments
* DEV-7083 Investigate Null Folder IDs Bug that caused 470K inventory items with Null Folder IDS on the Grid
* DEV-2865 Textures/Snapshots in a notecard are opened again when you click copy to inventory.
* DEV-6612 VWR-3290: Linux scons build script doesn't work with distcc
* DEV-8002 c++ llsd notation parser accepts malformed data
* DEV-8001 c++ xml parse returns wrong number of elements parsed
* DEV-8089 Double delete in statc structured data parse functions
* DEV-5326 Any viewer can request presence information for any agent
* DEV-2378 python service builder does not sort query string
* DEV-7872 Block teleport off teen grid sub-estates like Schome Park / Open University
* DEV-4465 Add a "logfile" command line option to the sim to create log files
28 files changed, 982 insertions, 401 deletions
diff --git a/doc/contributions.txt b/doc/contributions.txt index 4dea768d28..9b2719b3b7 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -33,6 +33,7 @@ Alissa Sabre VWR-1410 VWR-2116 VWR-2826 + VWR-3290 VWR-4010 Angus Boyd VWR-592 diff --git a/indra/lib/python/indra/ipc/russ.py b/indra/lib/python/indra/ipc/russ.py index 1ef5562a52..bd50569d3a 100644 --- a/indra/lib/python/indra/ipc/russ.py +++ b/indra/lib/python/indra/ipc/russ.py @@ -136,7 +136,15 @@ def _build_query_string(query_dict): @returns Returns an urlencoded query string including leading '?'. """ if query_dict: - return '?' + urllib.urlencode(query_dict) + keys = query_dict.keys() + keys.sort() + def stringize(value): + if type(value) in (str,unicode): + return value + else: + return str(value) + query_list = [urllib.quote(str(key)) + '=' + urllib.quote(stringize(query_dict[key])) for key in keys] + return '?' + '&'.join(query_list) else: return '' 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); diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index a20247866c..04b7d688e5 100755 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -117,8 +117,10 @@ void LLCrashLogger::gatherFiles() updateApplication("Gathering logs..."); // Figure out the filename of the debug log - LLString db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log").c_str(); - std::ifstream debug_log_file(db_file_name.c_str()); + std::string db_file_name = gDirUtilp->getExpandedFilename( + LL_PATH_LOGS, + "debug_info.log"); + llifstream debug_log_file(db_file_name.c_str()); // Look for it in the debug_info.log file if (debug_log_file.is_open()) diff --git a/indra/llmessage/llbuffer.h b/indra/llmessage/llbuffer.h index b251af8b35..52fc769be9 100644 --- a/indra/llmessage/llbuffer.h +++ b/indra/llmessage/llbuffer.h @@ -411,6 +411,18 @@ public: S32 countAfter(S32 channel, U8* start) const; /** + * @brief Count all bytes on channel. + * + * Helper method which just calls countAfter(). + * @param channel The channel to count. + * @return Returns the number of bytes in the channel. + */ + S32 count(S32 channel) const + { + return countAfter(channel, NULL); + } + + /** * @brief Read bytes in the buffer array on the specified channel * * You should prefer iterating over segments is possible since diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp index eac7dc11f2..88f7b1cb68 100644 --- a/indra/llmessage/llfiltersd2xmlrpc.cpp +++ b/indra/llmessage/llfiltersd2xmlrpc.cpp @@ -336,7 +336,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl( LLBufferStream stream(channels, buffer.get()); stream << XML_HEADER << XMLRPC_METHOD_RESPONSE_HEADER; LLSD sd; - LLSDSerialize::fromNotation(sd, stream); + LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); PUMP_DEBUG; LLIOPipe::EStatus rv = STATUS_ERROR; @@ -408,7 +408,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( // See if we can parse it LLBufferStream stream(channels, buffer.get()); LLSD sd; - LLSDSerialize::fromNotation(sd, stream); + LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); if(stream.fail()) { llinfos << "STREAM FAILURE reading structure data." << llendl; diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index bf5fa4073d..9f6115a0e4 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -71,8 +71,11 @@ void LLHTTPClient::Responder::result(const LLSD& content) } // virtual -void LLHTTPClient::Responder::completedRaw(U32 status, const std::string& reason, const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +void LLHTTPClient::Responder::completedRaw( + U32 status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) { LLBufferStream istr(channels, buffer.get()); LLSD content; @@ -94,7 +97,10 @@ void LLHTTPClient::Responder::completedRaw(U32 status, const std::string& reason } // virtual -void LLHTTPClient::Responder::completed(U32 status, const std::string& reason, const LLSD& content) +void LLHTTPClient::Responder::completed( + U32 status, + const std::string& reason, + const LLSD& content) { if(isGoodStatus(status)) { diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 6323defb76..983ff46e03 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -72,11 +72,18 @@ public: virtual void result(const LLSD& content); - // Override point for clients that may want to use this class when the response is some other format besides LLSD - virtual void completedRaw(U32 status, const std::string& reason, const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); - - virtual void completed(U32 status, const std::string& reason, const LLSD& content); + // Override point for clients that may want to use this class + // when the response is some other format besides LLSD + virtual void completedRaw( + U32 status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer); + + virtual void completed( + U32 status, + const std::string& reason, + const LLSD& content); /**< The default implemetnation calls either: * result(), or diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index acc38e153d..625dbb68b9 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -156,7 +156,9 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( // assume deferred unless mResponse does otherwise mResponse = Response::create(this); - // TODO: Babbage: Parameterize parser? + // *TODO: Babbage: Parameterize parser? + // *TODO: We should look at content-type and do the right + // thing. Phoenix 2007-12-31 LLBufferStream istr(channels, buffer.get()); static LLTimer timer; @@ -171,14 +173,12 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( { LLSD input; LLSDSerialize::fromXML(input, istr); - mNode.put(LLHTTPNode::ResponsePtr(mResponse), context, input); } else if(verb == HTTP_VERB_POST) { LLSD input; LLSDSerialize::fromXML(input, istr); - mNode.post(LLHTTPNode::ResponsePtr(mResponse), context, input); } else if(verb == HTTP_VERB_DELETE) diff --git a/indra/llmessage/llsdrpcclient.cpp b/indra/llmessage/llsdrpcclient.cpp index 0a12c478f9..c4738b7083 100644 --- a/indra/llmessage/llsdrpcclient.cpp +++ b/indra/llmessage/llsdrpcclient.cpp @@ -221,7 +221,7 @@ LLIOPipe::EStatus LLSDRPCClient::process_impl( // << llendl; LLBufferStream resp(channels, buffer.get()); LLSD sd; - LLSDSerialize::fromNotation(sd, resp); + LLSDSerialize::fromNotation(sd, resp, buffer->count(channels.in())); LLSDRPCResponse* response = (LLSDRPCResponse*)mResponse.get(); if (!response) { diff --git a/indra/llmessage/llsdrpcserver.cpp b/indra/llmessage/llsdrpcserver.cpp index 13ed79110f..ab1b800db8 100644 --- a/indra/llmessage/llsdrpcserver.cpp +++ b/indra/llmessage/llsdrpcserver.cpp @@ -182,7 +182,10 @@ LLIOPipe::EStatus LLSDRPCServer::process_impl( PUMP_DEBUG; LLBufferStream istr(channels, buffer.get()); mRequest.clear(); - LLSDSerialize::fromNotation(mRequest, istr); + LLSDSerialize::fromNotation( + mRequest, + istr, + buffer->count(channels.in())); // { 'method':'...', 'parameter': ... } method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString(); diff --git a/indra/llmessage/llservicebuilder.cpp b/indra/llmessage/llservicebuilder.cpp index 22e5c4af43..a3e6ee479b 100644 --- a/indra/llmessage/llservicebuilder.cpp +++ b/indra/llmessage/llservicebuilder.cpp @@ -1,33 +1,33 @@ /** -* @file llservicebuilder.cpp -* @brief Implementation of the LLServiceBuilder class. -* -* $LicenseInfo:firstyear=2007&license=viewergpl$ -* -* Copyright (c) 2007, Linden Research, Inc. -* -* Second Life Viewer Source Code -* The source code in this file ("Source Code") is provided by Linden Lab -* to you under the terms of the GNU General Public License, version 2.0 -* ("GPL"), unless you have obtained a separate licensing agreement -* ("Other License"), formally executed by you and Linden Lab. Terms of -* the GPL can be found in doc/GPL-license.txt in this distribution, or -* online at http://secondlife.com/developers/opensource/gplv2 -* -* There are special exceptions to the terms and conditions of the GPL as -* it is applied to this Source Code. View the full text of the exception -* in the file doc/FLOSS-exception.txt in this software distribution, or -* online at http://secondlife.com/developers/opensource/flossexception -* -* By copying, modifying or distributing this software, you acknowledge -* that you have read and understood your obligations described above, -* and agree to abide by those obligations. -* -* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -* COMPLETENESS OR PERFORMANCE. -* $/LicenseInfo$ -*/ + * @file llservicebuilder.cpp + * @brief Implementation of the LLServiceBuilder class. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ #include "linden_common.h" #include "llapp.h" diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 907f957bed..97f652d88d 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -390,7 +390,6 @@ static const char USAGE[] = "\n" " -set <variable> <value> specify the value of a particular\n" " configuration variable that\n" " overrides all other settings\n" -" -user <user_server_ip> specify userserver in dotted quad\n" #if !LL_RELEASE_FOR_DOWNLOAD " -sim <simulator_ip> specify the simulator ip address\n" #endif @@ -658,21 +657,6 @@ int parse_args(int argc, char **argv) gGridChoice = GRID_INFO_YAMI; sprintf(gGridName,"%s", gGridInfo[gGridChoice].mName); } - else if (!strcmp(argv[j], "-user") && (++j < argc)) - { - if (!strcmp(argv[j], "-")) - { - gGridChoice = GRID_INFO_LOCAL; - snprintf(gGridName, MAX_STRING, "%s", LOOPBACK_ADDRESS_STRING); // Flawfinder: ignore - } - else - { - gGridChoice = GRID_INFO_OTHER; - ip_string.assign( argv[j] ); - LLString::trim(ip_string); - snprintf(gGridName, MAX_STRING, "%s", ip_string.c_str()); // Flawfinder: ignore - } - } else if (!strcmp(argv[j], "-loginpage") && (++j < argc)) { LLAppViewer::instance()->setLoginPage(utf8str_trim(argv[j])); @@ -1927,17 +1911,6 @@ bool LLAppViewer::initEarlyConfiguration() { sprintf(gGridName,"%s", gGridInfo[GRID_INFO_ARUNA].mName); } - else if (!strcmp(argv[j], "-user") && (++j < argc)) - { - if (!strcmp(argv[j], "-")) - { - snprintf(gGridName, MAX_STRING, "%s", LOOPBACK_ADDRESS_STRING); // Flawfinder: ignore - } - else - { - snprintf(gGridName, MAX_STRING, "%s", argv[j]); // Flawfinder: ignore - } - } else if (!strcmp(argv[j], "-multiple")) { // Hack to detect -multiple so we can disable the marker file check (which will always fail) diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index da298c56c4..31c60d8b2d 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -1126,7 +1126,7 @@ void LLFloaterSnapshot::Impl::onCommitResolution(LLUICtrl* ctrl, void* data) std::string sdstring = combobox->getSelectedValue(); LLSD sdres; std::stringstream sstream(sdstring); - LLSDSerialize::fromNotation(sdres, sstream); + LLSDSerialize::fromNotation(sdres, sstream, sdstring.size()); S32 width = sdres[0]; S32 height = sdres[1]; diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index 660de69fb0..b0d7aa6d1b 100644 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -468,6 +468,7 @@ void LLPreview::onBtnCopyToInv(void* userdata) cb); } } + self->close(); } // static diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 20e4eee396..8df34d39c6 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1377,8 +1377,13 @@ BOOL idle_startup() const char* look_at_str = gUserAuthp->getResponse("look_at"); if (look_at_str) { - LLMemoryStream mstr((U8*)look_at_str, strlen(look_at_str)); /* Flawfinder: ignore */ - LLSD sd = LLSDNotationParser::parse(mstr); +#if !LL_WINDOWS && !LL_DARWIN + size_t len = strnlen(look_at_str, MAX_STRING); +#else + size_t len = strlen(look_at_str); +#endif + LLMemoryStream mstr((U8*)look_at_str, len); + LLSD sd = LLSDSerialize::fromNotation(mstr, len); agent_start_look_at = ll_vector3_from_sd(sd); } @@ -1399,8 +1404,13 @@ BOOL idle_startup() const char* home_location = gUserAuthp->getResponse("home"); if(home_location) { - LLMemoryStream mstr((U8*)home_location, strlen(home_location)); /* Flawfinder: ignore */ - LLSD sd = LLSDNotationParser::parse(mstr); +#if !LL_WINDOWS && !LL_DARWIN + size_t len = strnlen(home_location, MAX_STRING); +#else + size_t len = strlen(home_location); +#endif + LLMemoryStream mstr((U8*)home_location, len); + LLSD sd = LLSDSerialize::fromNotation(mstr, len); S32 region_x = sd["region_handle"][0].asInteger(); S32 region_y = sd["region_handle"][1].asInteger(); U64 region_handle = to_region_handle(region_x, region_y); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 9332a909d7..6b18fb46be 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1194,8 +1194,8 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) LLString::format_map_t args; args["[OBJECTNAME]"] = info->mDesc; // must protect against a NULL return from lookupHumanReadable() - const char* typestr = LLAssetType::lookupHumanReadable(info->mType); - if (typestr) + std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType)); + if (!typestr.empty()) { args["[OBJECTTYPE]"] = typestr; } diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index bd488577e3..871fc9702e 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -942,7 +942,13 @@ BOOL LLViewerTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) S32 dy = y - mMouseDownY; if (-2 < dx && dx < 2 && -2 < dy && dy < 2) { - openEmbeddedItem(mDragItem, mDragItemSaved); + if(mDragItemSaved) + { + openEmbeddedItem(mDragItem); + }else + { + showUnsavedAlertDialog(mDragItem); + } } } mDragItem = NULL; @@ -1311,15 +1317,23 @@ BOOL LLViewerTextEditor::openEmbeddedItemAtPos(S32 pos) if( item ) { BOOL saved = LLEmbeddedItems::getEmbeddedItemSaved( mWText[pos] ); - return openEmbeddedItem(item, saved); + if (saved) + { + return openEmbeddedItem(item); + } + else + { + showUnsavedAlertDialog(item); + } } } return FALSE; } -BOOL LLViewerTextEditor::openEmbeddedItem(LLInventoryItem* item, BOOL saved) +BOOL LLViewerTextEditor::openEmbeddedItem(LLInventoryItem* item) { + switch( item->getType() ) { case LLAssetType::AT_TEXTURE: @@ -1329,15 +1343,15 @@ BOOL LLViewerTextEditor::openEmbeddedItem(LLInventoryItem* item, BOOL saved) case LLAssetType::AT_SOUND: openEmbeddedSound( item ); return TRUE; - + case LLAssetType::AT_NOTECARD: - openEmbeddedNotecard( item, saved ); + openEmbeddedNotecard( item ); return TRUE; case LLAssetType::AT_LANDMARK: openEmbeddedLandmark( item ); return TRUE; - + case LLAssetType::AT_LSL_TEXT: case LLAssetType::AT_CLOTHING: case LLAssetType::AT_OBJECT: @@ -1345,10 +1359,11 @@ BOOL LLViewerTextEditor::openEmbeddedItem(LLInventoryItem* item, BOOL saved) case LLAssetType::AT_ANIMATION: case LLAssetType::AT_GESTURE: showCopyToInvDialog( item ); - return TRUE; + return TRUE; default: return FALSE; } + } @@ -1401,23 +1416,30 @@ void LLViewerTextEditor::openEmbeddedLandmark( LLInventoryItem* item ) open_landmark((LLViewerInventoryItem*)item, title, FALSE, item->getUUID(), TRUE); } -void LLViewerTextEditor::openEmbeddedNotecard( LLInventoryItem* item, BOOL saved ) +void LLViewerTextEditor::openEmbeddedNotecard( LLInventoryItem* item ) { - if (saved) - { + //if (saved) + //{ // An LLInventoryItem needs to be in an inventory to be opened. // This will give the item to the viewer's agent. // The callback will attempt to open it if its not already opened. - copyInventory(item, gInventoryCallbacks.registerCB(mInventoryCallback)); - } - else - { - LLNotecardCopyInfo *info = new LLNotecardCopyInfo(this, item); - gViewerWindow->alertXml("ConfirmNotecardSave", - LLViewerTextEditor::onNotecardDialog, (void*)info); - } + copyInventory(item, gInventoryCallbacks.registerCB(mInventoryCallback)); + + //} + //else + //{ + // LLNotecardCopyInfo *info = new LLNotecardCopyInfo(this, item); + // gViewerWindow->alertXml("ConfirmNotecardSave", + // LLViewerTextEditor::onNotecardDialog, (void*)info); + //} } +void LLViewerTextEditor::showUnsavedAlertDialog( LLInventoryItem* item ) +{ + LLNotecardCopyInfo *info = new LLNotecardCopyInfo(this, item); + gViewerWindow->alertXml( "ConfirmNotecardSave", + LLViewerTextEditor::onNotecardDialog, (void*)info); +} // static void LLViewerTextEditor::onNotecardDialog( S32 option, void* userdata ) { diff --git a/indra/newview/llviewertexteditor.h b/indra/newview/llviewertexteditor.h index 1ec173a5d1..02d934fc3c 100644 --- a/indra/newview/llviewertexteditor.h +++ b/indra/newview/llviewertexteditor.h @@ -107,15 +107,16 @@ protected: BOOL getEmbeddedItemToolTipAtPos(S32 pos, LLWString &wmsg); BOOL openEmbeddedItemAtPos( S32 pos ); - BOOL openEmbeddedItem(LLInventoryItem* item, BOOL saved); + BOOL openEmbeddedItem(LLInventoryItem* item); S32 insertEmbeddedItem(S32 pos, LLInventoryItem* item); void openEmbeddedTexture( LLInventoryItem* item ); void openEmbeddedSound( LLInventoryItem* item ); void openEmbeddedLandmark( LLInventoryItem* item ); - void openEmbeddedNotecard( LLInventoryItem* item, BOOL saved ); + void openEmbeddedNotecard( LLInventoryItem* item); void showCopyToInvDialog( LLInventoryItem* item ); + void showUnsavedAlertDialog( LLInventoryItem* item ); static void onCopyToInvDialog( S32 option, void* userdata ); static void onNotecardDialog( S32 option, void* userdata ); diff --git a/indra/test/io.cpp b/indra/test/io.cpp index 350fc5394b..c322522ce3 100644 --- a/indra/test/io.cpp +++ b/indra/test/io.cpp @@ -634,7 +634,7 @@ namespace tut ensure_equals("size of buffer", count, total_size); LLBufferStream istr(ch, &mBuffer); LLSD data; - count = LLSDSerialize::fromNotation(data, istr); + count = LLSDSerialize::fromNotation(data, istr, total_size); ensure("sd parsed", data.isDefined()); for(S32 j = 0; j < 3; ++j) @@ -699,7 +699,7 @@ namespace tut ensure_equals("size of buffer", count, total_size); LLBufferStream istr(ch, &mBuffer); LLSD data; - count = LLSDSerialize::fromNotation(data, istr); + count = LLSDSerialize::fromNotation(data, istr, total_size); ensure("sd parsed", data.isDefined()); } @@ -735,7 +735,10 @@ namespace tut ch = mBuffer.nextChannel(); LLBufferStream istr(ch, &mBuffer); LLSD data; - S32 count = LLSDSerialize::fromNotation(data, istr); + S32 count = LLSDSerialize::fromNotation( + data, + istr, + mBuffer.count(ch.in())); ensure("parsed something", (count > 0)); ensure("sd parsed", data.isDefined()); ensure_equals("sd type", data.type(), LLSD::TypeMap); @@ -780,7 +783,7 @@ namespace tut std::istringstream istr; istr.str(val); LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, istr); + S32 count = LLSDSerialize::fromNotation(sd, istr, val.size()); ensure_equals("parser error return value", count, -1); ensure("data undefined", sd.isUndefined()); } @@ -792,7 +795,7 @@ namespace tut std::istringstream istr; istr.str(val); LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, istr); + S32 count = LLSDSerialize::fromNotation(sd, istr, val.size()); ensure_equals("parser error return value", count, -1); ensure("data undefined", sd.isUndefined()); } @@ -1324,7 +1327,10 @@ namespace tut << "}]"; LLSD request; - S32 count = LLSDSerialize::fromNotation(request, stream); + S32 count = LLSDSerialize::fromNotation( + request, + stream, + stream.str().size()); ensure("parsed something", (count > 0)); pump_loop(request); @@ -1425,7 +1431,10 @@ namespace tut LLChannelDescriptors read_channel = buffer.nextChannel(); LLBufferStream read_stream(read_channel, &buffer); LLSD request; - S32 count = LLSDSerialize::fromNotation(request, read_stream); + S32 count = LLSDSerialize::fromNotation( + request, + read_stream, + buffer.count(read_channel.in())); ensure("parsed something", (count > 0)); ensure("deserialized", request.isDefined()); @@ -1487,7 +1496,10 @@ namespace tut str << "{'message':'" << LLSDNotationFormatter::escapeString(message) << "'}"; LLSD request; - S32 count = LLSDSerialize::fromNotation(request, str); + S32 count = LLSDSerialize::fromNotation( + request, + str, + str.str().size()); ensure_equals("parse count", count, 2); ensure_equals("request type", request.type(), LLSD::TypeMap); pump_loop(request); @@ -1510,7 +1522,7 @@ namespace tut std::istringstream istr; istr.str(val); LLSD sd; - LLSDSerialize::fromNotation(sd, istr); + LLSDSerialize::fromNotation(sd, istr, val.size()); pump_loop(sd); ensure("valid response", mResponse.isDefined()); ensure_equals("parsed type", mResponse.type(), LLSD::TypeMap); |