summaryrefslogtreecommitdiff
path: root/indra/llcommon/llsdserialize_xml.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/llsdserialize_xml.cpp')
-rw-r--r--indra/llcommon/llsdserialize_xml.cpp1470
1 files changed, 735 insertions, 735 deletions
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index db61f4ae41..88cbb3b984 100644
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -1,25 +1,25 @@
-/**
+/**
* @file llsdserialize_xml.cpp
* @brief XML parsers and formatters for LLSD
*
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -58,195 +58,195 @@ LLSDXMLFormatter::~LLSDXMLFormatter()
// virtual
S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr,
- EFormatterOptions options) const
+ EFormatterOptions options) const
{
- std::streamsize old_precision = ostr.precision(25);
-
- std::string post;
- if (options & LLSDFormatter::OPTIONS_PRETTY)
- {
- post = "\n";
- }
- ostr << "<llsd>" << post;
- S32 rv = format_impl(data, ostr, options, 1);
- ostr << "</llsd>\n";
-
- ostr.precision(old_precision);
- return rv;
+ std::streamsize old_precision = ostr.precision(25);
+
+ std::string post;
+ if (options & LLSDFormatter::OPTIONS_PRETTY)
+ {
+ post = "\n";
+ }
+ ostr << "<llsd>" << post;
+ S32 rv = format_impl(data, ostr, options, 1);
+ ostr << "</llsd>\n";
+
+ ostr.precision(old_precision);
+ return rv;
}
S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr,
- EFormatterOptions options, U32 level) const
+ EFormatterOptions options, U32 level) const
{
- S32 format_count = 1;
- std::string pre;
- std::string post;
-
- if (options & LLSDFormatter::OPTIONS_PRETTY)
- {
- for (U32 i = 0; i < level; i++)
- {
- pre += " ";
- }
- post = "\n";
- }
-
- switch(data.type())
- {
- case LLSD::TypeMap:
- if(0 == data.size())
- {
- ostr << pre << "<map />" << post;
- }
- else
- {
- ostr << pre << "<map>" << post;
- LLSD::map_const_iterator iter = data.beginMap();
- LLSD::map_const_iterator end = data.endMap();
- for(; iter != end; ++iter)
- {
- ostr << pre << "<key>" << escapeString((*iter).first) << "</key>" << post;
- format_count += format_impl((*iter).second, ostr, options, level + 1);
- }
- ostr << pre << "</map>" << post;
- }
- break;
-
- case LLSD::TypeArray:
- if(0 == data.size())
- {
- ostr << pre << "<array />" << post;
- }
- else
- {
- ostr << pre << "<array>" << post;
- LLSD::array_const_iterator iter = data.beginArray();
- LLSD::array_const_iterator end = data.endArray();
- for(; iter != end; ++iter)
- {
- format_count += format_impl(*iter, ostr, options, level + 1);
- }
- ostr << pre << "</array>" << post;
- }
- break;
-
- case LLSD::TypeUndefined:
- ostr << pre << "<undef />" << post;
- break;
-
- case LLSD::TypeBoolean:
- ostr << pre << "<boolean>";
- if(mBoolAlpha ||
- (ostr.flags() & std::ios::boolalpha)
- )
- {
- ostr << (data.asBoolean() ? "true" : "false");
- }
- else
- {
- ostr << (data.asBoolean() ? 1 : 0);
- }
- ostr << "</boolean>" << post;
- break;
-
- case LLSD::TypeInteger:
- ostr << pre << "<integer>" << data.asInteger() << "</integer>" << post;
- break;
-
- case LLSD::TypeReal:
- ostr << pre << "<real>";
- if(mRealFormat.empty())
- {
- ostr << data.asReal();
- }
- else
- {
- formatReal(data.asReal(), ostr);
- }
- ostr << "</real>" << post;
- break;
-
- case LLSD::TypeUUID:
- if(data.asUUID().isNull()) ostr << pre << "<uuid />" << post;
- else ostr << pre << "<uuid>" << data.asUUID() << "</uuid>" << post;
- break;
-
- case LLSD::TypeString:
- if(data.asStringRef().empty()) ostr << pre << "<string />" << post;
- else ostr << pre << "<string>" << escapeString(data.asStringRef()) <<"</string>" << post;
- break;
-
- case LLSD::TypeDate:
- ostr << pre << "<date>" << data.asDate() << "</date>" << post;
- break;
-
- case LLSD::TypeURI:
- ostr << pre << "<uri>" << escapeString(data.asString()) << "</uri>" << post;
- break;
-
- case LLSD::TypeBinary:
- {
- const LLSD::Binary& buffer = data.asBinary();
- if(buffer.empty())
- {
- ostr << pre << "<binary />" << post;
- }
- else
- {
- // *FIX: memory inefficient.
- // *TODO: convert to use LLBase64
- ostr << pre << "<binary encoding=\"base64\">";
- int b64_buffer_length = apr_base64_encode_len(narrow<size_t>(buffer.size()));
- char* b64_buffer = new char[b64_buffer_length];
- b64_buffer_length = apr_base64_encode_binary(
- b64_buffer,
- &buffer[0],
- narrow<size_t>(buffer.size()));
- ostr.write(b64_buffer, b64_buffer_length - 1);
- delete[] b64_buffer;
- ostr << "</binary>" << post;
- }
- break;
- }
- default:
- // *NOTE: This should never happen.
- ostr << pre << "<undef />" << post;
- break;
- }
- return format_count;
+ S32 format_count = 1;
+ std::string pre;
+ std::string post;
+
+ if (options & LLSDFormatter::OPTIONS_PRETTY)
+ {
+ for (U32 i = 0; i < level; i++)
+ {
+ pre += " ";
+ }
+ post = "\n";
+ }
+
+ switch(data.type())
+ {
+ case LLSD::TypeMap:
+ if(0 == data.size())
+ {
+ ostr << pre << "<map />" << post;
+ }
+ else
+ {
+ ostr << pre << "<map>" << post;
+ LLSD::map_const_iterator iter = data.beginMap();
+ LLSD::map_const_iterator end = data.endMap();
+ for(; iter != end; ++iter)
+ {
+ ostr << pre << "<key>" << escapeString((*iter).first) << "</key>" << post;
+ format_count += format_impl((*iter).second, ostr, options, level + 1);
+ }
+ ostr << pre << "</map>" << post;
+ }
+ break;
+
+ case LLSD::TypeArray:
+ if(0 == data.size())
+ {
+ ostr << pre << "<array />" << post;
+ }
+ else
+ {
+ ostr << pre << "<array>" << post;
+ LLSD::array_const_iterator iter = data.beginArray();
+ LLSD::array_const_iterator end = data.endArray();
+ for(; iter != end; ++iter)
+ {
+ format_count += format_impl(*iter, ostr, options, level + 1);
+ }
+ ostr << pre << "</array>" << post;
+ }
+ break;
+
+ case LLSD::TypeUndefined:
+ ostr << pre << "<undef />" << post;
+ break;
+
+ case LLSD::TypeBoolean:
+ ostr << pre << "<boolean>";
+ if(mBoolAlpha ||
+ (ostr.flags() & std::ios::boolalpha)
+ )
+ {
+ ostr << (data.asBoolean() ? "true" : "false");
+ }
+ else
+ {
+ ostr << (data.asBoolean() ? 1 : 0);
+ }
+ ostr << "</boolean>" << post;
+ break;
+
+ case LLSD::TypeInteger:
+ ostr << pre << "<integer>" << data.asInteger() << "</integer>" << post;
+ break;
+
+ case LLSD::TypeReal:
+ ostr << pre << "<real>";
+ if(mRealFormat.empty())
+ {
+ ostr << data.asReal();
+ }
+ else
+ {
+ formatReal(data.asReal(), ostr);
+ }
+ ostr << "</real>" << post;
+ break;
+
+ case LLSD::TypeUUID:
+ if(data.asUUID().isNull()) ostr << pre << "<uuid />" << post;
+ else ostr << pre << "<uuid>" << data.asUUID() << "</uuid>" << post;
+ break;
+
+ case LLSD::TypeString:
+ if(data.asStringRef().empty()) ostr << pre << "<string />" << post;
+ else ostr << pre << "<string>" << escapeString(data.asStringRef()) <<"</string>" << post;
+ break;
+
+ case LLSD::TypeDate:
+ ostr << pre << "<date>" << data.asDate() << "</date>" << post;
+ break;
+
+ case LLSD::TypeURI:
+ ostr << pre << "<uri>" << escapeString(data.asString()) << "</uri>" << post;
+ break;
+
+ case LLSD::TypeBinary:
+ {
+ const LLSD::Binary& buffer = data.asBinary();
+ if(buffer.empty())
+ {
+ ostr << pre << "<binary />" << post;
+ }
+ else
+ {
+ // *FIX: memory inefficient.
+ // *TODO: convert to use LLBase64
+ ostr << pre << "<binary encoding=\"base64\">";
+ int b64_buffer_length = apr_base64_encode_len(narrow<size_t>(buffer.size()));
+ char* b64_buffer = new char[b64_buffer_length];
+ b64_buffer_length = apr_base64_encode_binary(
+ b64_buffer,
+ &buffer[0],
+ narrow<size_t>(buffer.size()));
+ ostr.write(b64_buffer, b64_buffer_length - 1);
+ delete[] b64_buffer;
+ ostr << "</binary>" << post;
+ }
+ break;
+ }
+ default:
+ // *NOTE: This should never happen.
+ ostr << pre << "<undef />" << post;
+ break;
+ }
+ return format_count;
}
// static
std::string LLSDXMLFormatter::escapeString(const std::string& in)
{
- std::ostringstream out;
- std::string::const_iterator it = in.begin();
- std::string::const_iterator end = in.end();
- for(; it != end; ++it)
- {
- switch((*it))
- {
- case '<':
- out << "&lt;";
- break;
- case '>':
- out << "&gt;";
- break;
- case '&':
- out << "&amp;";
- break;
- case '\'':
- out << "&apos;";
- break;
- case '"':
- out << "&quot;";
- break;
- default:
- out << (*it);
- break;
- }
- }
- return out.str();
+ std::ostringstream out;
+ std::string::const_iterator it = in.begin();
+ std::string::const_iterator end = in.end();
+ for(; it != end; ++it)
+ {
+ switch((*it))
+ {
+ case '<':
+ out << "&lt;";
+ break;
+ case '>':
+ out << "&gt;";
+ break;
+ case '&':
+ out << "&amp;";
+ break;
+ case '\'':
+ out << "&apos;";
+ break;
+ case '"':
+ out << "&quot;";
+ break;
+ default:
+ out << (*it);
+ break;
+ }
+ }
+ return out.str();
}
@@ -254,161 +254,161 @@ std::string LLSDXMLFormatter::escapeString(const std::string& in)
class LLSDXMLParser::Impl
{
public:
- Impl(bool emit_errors);
- ~Impl();
-
- S32 parse(std::istream& input, LLSD& data);
- S32 parseLines(std::istream& input, LLSD& data);
+ Impl(bool emit_errors);
+ ~Impl();
+
+ S32 parse(std::istream& input, LLSD& data);
+ S32 parseLines(std::istream& input, LLSD& data);
- void parsePart(const char *buf, llssize len);
-
- void reset();
+ void parsePart(const char *buf, llssize len);
+
+ void reset();
private:
- void startElementHandler(const XML_Char* name, const XML_Char** attributes);
- void endElementHandler(const XML_Char* name);
- void characterDataHandler(const XML_Char* data, int length);
-
- static void sStartElementHandler(
- void* userData, const XML_Char* name, const XML_Char** attributes);
- static void sEndElementHandler(
- void* userData, const XML_Char* name);
- static void sCharacterDataHandler(
- void* userData, const XML_Char* data, int length);
-
- void startSkipping();
-
- enum Element {
- ELEMENT_LLSD,
- ELEMENT_UNDEF,
- ELEMENT_BOOL,
- ELEMENT_INTEGER,
- ELEMENT_REAL,
- ELEMENT_STRING,
- ELEMENT_UUID,
- ELEMENT_DATE,
- ELEMENT_URI,
- ELEMENT_BINARY,
- ELEMENT_MAP,
- ELEMENT_ARRAY,
- ELEMENT_KEY,
- ELEMENT_UNKNOWN
- };
- static Element readElement(const XML_Char* name);
-
- static const XML_Char* findAttribute(const XML_Char* name, const XML_Char** pairs);
-
- bool mEmitErrors;
-
- XML_Parser mParser;
-
- LLSD mResult;
- S32 mParseCount;
-
- bool mInLLSDElement; // true if we're on LLSD
- bool mGracefullStop; // true if we found the </llsd
-
- typedef std::deque<LLSD*> LLSDRefStack;
- LLSDRefStack mStack;
-
- int mDepth;
- bool mSkipping;
- int mSkipThrough;
-
- std::string mCurrentKey; // Current XML <tag>
- std::string mCurrentContent; // String data between <tag> and </tag>
+ void startElementHandler(const XML_Char* name, const XML_Char** attributes);
+ void endElementHandler(const XML_Char* name);
+ void characterDataHandler(const XML_Char* data, int length);
+
+ static void sStartElementHandler(
+ void* userData, const XML_Char* name, const XML_Char** attributes);
+ static void sEndElementHandler(
+ void* userData, const XML_Char* name);
+ static void sCharacterDataHandler(
+ void* userData, const XML_Char* data, int length);
+
+ void startSkipping();
+
+ enum Element {
+ ELEMENT_LLSD,
+ ELEMENT_UNDEF,
+ ELEMENT_BOOL,
+ ELEMENT_INTEGER,
+ ELEMENT_REAL,
+ ELEMENT_STRING,
+ ELEMENT_UUID,
+ ELEMENT_DATE,
+ ELEMENT_URI,
+ ELEMENT_BINARY,
+ ELEMENT_MAP,
+ ELEMENT_ARRAY,
+ ELEMENT_KEY,
+ ELEMENT_UNKNOWN
+ };
+ static Element readElement(const XML_Char* name);
+
+ static const XML_Char* findAttribute(const XML_Char* name, const XML_Char** pairs);
+
+ bool mEmitErrors;
+
+ XML_Parser mParser;
+
+ LLSD mResult;
+ S32 mParseCount;
+
+ bool mInLLSDElement; // true if we're on LLSD
+ bool mGracefullStop; // true if we found the </llsd
+
+ typedef std::deque<LLSD*> LLSDRefStack;
+ LLSDRefStack mStack;
+
+ int mDepth;
+ bool mSkipping;
+ int mSkipThrough;
+
+ std::string mCurrentKey; // Current XML <tag>
+ std::string mCurrentContent; // String data between <tag> and </tag>
};
LLSDXMLParser::Impl::Impl(bool emit_errors)
- : mEmitErrors(emit_errors)
+ : mEmitErrors(emit_errors)
{
- mParser = XML_ParserCreate(NULL);
- reset();
+ mParser = XML_ParserCreate(NULL);
+ reset();
}
LLSDXMLParser::Impl::~Impl()
{
- XML_ParserFree(mParser);
+ XML_ParserFree(mParser);
}
inline bool is_eol(char c)
{
- return (c == '\n' || c == '\r');
+ return (c == '\n' || c == '\r');
}
void clear_eol(std::istream& input)
{
- char c = input.peek();
- while (input.good() && is_eol(c))
- {
- input.get(c);
- c = input.peek();
- }
+ char c = input.peek();
+ while (input.good() && is_eol(c))
+ {
+ input.get(c);
+ c = input.peek();
+ }
}
static unsigned get_till_eol(std::istream& input, char *buf, unsigned bufsize)
{
- unsigned count = 0;
- while (count < bufsize && input.good())
- {
- char c = input.get();
- buf[count++] = c;
- if (is_eol(c))
- break;
- }
- return count;
+ unsigned count = 0;
+ while (count < bufsize && input.good())
+ {
+ char c = input.get();
+ buf[count++] = c;
+ if (is_eol(c))
+ break;
+ }
+ return count;
}
S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
{
- XML_Status status;
-
- static const int BUFFER_SIZE = 1024;
- void* buffer = NULL;
- int count = 0;
- while (input.good() && !input.eof())
- {
- buffer = XML_GetBuffer(mParser, BUFFER_SIZE);
-
- /*
- * If we happened to end our last buffer right at the end of the llsd, but the
- * stream is still going we will get a null buffer here. Check for mGracefullStop.
- */
- if (!buffer)
- {
- break;
- }
- count = get_till_eol(input, (char *)buffer, BUFFER_SIZE);
- if (!count)
- {
- break;
- }
- status = XML_ParseBuffer(mParser, count, false);
-
- if (status == XML_STATUS_ERROR)
- {
- break;
- }
- }
-
- // *FIX.: This code is buggy - if the stream was empty or not
- // good, there is not buffer to parse, both the call to
- // XML_ParseBuffer and the buffer manipulations are illegal
- // futhermore, it isn't clear that the expat buffer semantics are
- // preserved
-
- status = XML_ParseBuffer(mParser, 0, true);
- if (status == XML_STATUS_ERROR && !mGracefullStop)
- {
- if (buffer)
- {
- ((char*) buffer)[count ? count - 1 : 0] = '\0';
+ XML_Status status;
+
+ static const int BUFFER_SIZE = 1024;
+ void* buffer = NULL;
+ int count = 0;
+ while (input.good() && !input.eof())
+ {
+ buffer = XML_GetBuffer(mParser, BUFFER_SIZE);
+
+ /*
+ * If we happened to end our last buffer right at the end of the llsd, but the
+ * stream is still going we will get a null buffer here. Check for mGracefullStop.
+ */
+ if (!buffer)
+ {
+ break;
+ }
+ count = get_till_eol(input, (char *)buffer, BUFFER_SIZE);
+ if (!count)
+ {
+ break;
+ }
+ status = XML_ParseBuffer(mParser, count, false);
+
+ if (status == XML_STATUS_ERROR)
+ {
+ break;
+ }
+ }
+
+ // *FIX.: This code is buggy - if the stream was empty or not
+ // good, there is not buffer to parse, both the call to
+ // XML_ParseBuffer and the buffer manipulations are illegal
+ // futhermore, it isn't clear that the expat buffer semantics are
+ // preserved
+
+ status = XML_ParseBuffer(mParser, 0, true);
+ if (status == XML_STATUS_ERROR && !mGracefullStop)
+ {
+ if (buffer)
+ {
+ ((char*) buffer)[count ? count - 1 : 0] = '\0';
if (mEmitErrors)
{
LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*)buffer << LL_ENDL;
}
- }
+ }
else
{
if (mEmitErrors)
@@ -416,159 +416,159 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR, null buffer" << LL_ENDL;
}
}
- data = LLSD();
- return LLSDParser::PARSE_FAILURE;
- }
+ data = LLSD();
+ return LLSDParser::PARSE_FAILURE;
+ }
- clear_eol(input);
- data = mResult;
- return mParseCount;
+ clear_eol(input);
+ data = mResult;
+ return mParseCount;
}
S32 LLSDXMLParser::Impl::parseLines(std::istream& input, LLSD& data)
{
- XML_Status status = XML_STATUS_OK;
-
- data = LLSD();
-
- static const int BUFFER_SIZE = 1024;
-
- //static char last_buffer[ BUFFER_SIZE ];
- //std::streamsize last_num_read;
-
- // Must get rid of any leading \n, otherwise the stream gets into an error/eof state
- clear_eol(input);
-
- while( !mGracefullStop
- && input.good()
- && !input.eof())
- {
- void* buffer = XML_GetBuffer(mParser, BUFFER_SIZE);
- /*
- * If we happened to end our last buffer right at the end of the llsd, but the
- * stream is still going we will get a null buffer here. Check for mGracefullStop.
- * -- I don't think this is actually true - zero 2008-05-09
- */
- if (!buffer)
- {
- break;
- }
-
- // Get one line
- input.getline((char*)buffer, BUFFER_SIZE);
- std::streamsize num_read = input.gcount();
-
- //memcpy( last_buffer, buffer, num_read );
- //last_num_read = num_read;
-
- if ( num_read > 0 )
- {
- if (!input.good() )
- { // Clear state that's set when we run out of buffer
- input.clear();
- }
-
- // Re-insert with the \n that was absorbed by getline()
- char * text = (char *) buffer;
- if ( text[num_read - 1] == 0)
- {
- text[num_read - 1] = '\n';
- }
- }
-
- status = XML_ParseBuffer(mParser, (int)num_read, false);
- if (status == XML_STATUS_ERROR)
- {
- break;
- }
- }
-
- if (status != XML_STATUS_ERROR
- && !mGracefullStop)
- { // Parse last bit
- status = XML_ParseBuffer(mParser, 0, true);
- }
-
- if (status == XML_STATUS_ERROR
- && !mGracefullStop)
- {
- if (mEmitErrors)
- {
- LL_INFOS() << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << LL_ENDL;
- }
- return LLSDParser::PARSE_FAILURE;
- }
-
- clear_eol(input);
- data = mResult;
- return mParseCount;
+ XML_Status status = XML_STATUS_OK;
+
+ data = LLSD();
+
+ static const int BUFFER_SIZE = 1024;
+
+ //static char last_buffer[ BUFFER_SIZE ];
+ //std::streamsize last_num_read;
+
+ // Must get rid of any leading \n, otherwise the stream gets into an error/eof state
+ clear_eol(input);
+
+ while( !mGracefullStop
+ && input.good()
+ && !input.eof())
+ {
+ void* buffer = XML_GetBuffer(mParser, BUFFER_SIZE);
+ /*
+ * If we happened to end our last buffer right at the end of the llsd, but the
+ * stream is still going we will get a null buffer here. Check for mGracefullStop.
+ * -- I don't think this is actually true - zero 2008-05-09
+ */
+ if (!buffer)
+ {
+ break;
+ }
+
+ // Get one line
+ input.getline((char*)buffer, BUFFER_SIZE);
+ std::streamsize num_read = input.gcount();
+
+ //memcpy( last_buffer, buffer, num_read );
+ //last_num_read = num_read;
+
+ if ( num_read > 0 )
+ {
+ if (!input.good() )
+ { // Clear state that's set when we run out of buffer
+ input.clear();
+ }
+
+ // Re-insert with the \n that was absorbed by getline()
+ char * text = (char *) buffer;
+ if ( text[num_read - 1] == 0)
+ {
+ text[num_read - 1] = '\n';
+ }
+ }
+
+ status = XML_ParseBuffer(mParser, (int)num_read, false);
+ if (status == XML_STATUS_ERROR)
+ {
+ break;
+ }
+ }
+
+ if (status != XML_STATUS_ERROR
+ && !mGracefullStop)
+ { // Parse last bit
+ status = XML_ParseBuffer(mParser, 0, true);
+ }
+
+ if (status == XML_STATUS_ERROR
+ && !mGracefullStop)
+ {
+ if (mEmitErrors)
+ {
+ LL_INFOS() << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << LL_ENDL;
+ }
+ return LLSDParser::PARSE_FAILURE;
+ }
+
+ clear_eol(input);
+ data = mResult;
+ return mParseCount;
}
void LLSDXMLParser::Impl::reset()
{
- mResult.clear();
- mParseCount = 0;
-
- mInLLSDElement = false;
- mDepth = 0;
-
- mGracefullStop = false;
-
- mStack.clear();
-
- mSkipping = false;
-
- mCurrentKey.clear();
-
- XML_ParserReset(mParser, "utf-8");
- XML_SetUserData(mParser, this);
- XML_SetElementHandler(mParser, sStartElementHandler, sEndElementHandler);
- XML_SetCharacterDataHandler(mParser, sCharacterDataHandler);
+ mResult.clear();
+ mParseCount = 0;
+
+ mInLLSDElement = false;
+ mDepth = 0;
+
+ mGracefullStop = false;
+
+ mStack.clear();
+
+ mSkipping = false;
+
+ mCurrentKey.clear();
+
+ XML_ParserReset(mParser, "utf-8");
+ XML_SetUserData(mParser, this);
+ XML_SetElementHandler(mParser, sStartElementHandler, sEndElementHandler);
+ XML_SetCharacterDataHandler(mParser, sCharacterDataHandler);
}
void LLSDXMLParser::Impl::startSkipping()
{
- mSkipping = true;
- mSkipThrough = mDepth;
+ mSkipping = true;
+ mSkipThrough = mDepth;
}
const XML_Char*
LLSDXMLParser::Impl::findAttribute(const XML_Char* name, const XML_Char** pairs)
{
- while (NULL != pairs && NULL != *pairs)
- {
- if(0 == strcmp(name, *pairs))
- {
- return *(pairs + 1);
- }
- pairs += 2;
- }
- return NULL;
+ while (NULL != pairs && NULL != *pairs)
+ {
+ if(0 == strcmp(name, *pairs))
+ {
+ return *(pairs + 1);
+ }
+ pairs += 2;
+ }
+ return NULL;
}
void LLSDXMLParser::Impl::parsePart(const char* buf, llssize len)
{
- if ( buf != NULL
- && len > 0 )
- {
- XML_Status status = XML_Parse(mParser, buf, len, false);
- if (status == XML_STATUS_ERROR)
- {
- LL_INFOS() << "Unexpected XML parsing error at start" << LL_ENDL;
- }
- }
+ if ( buf != NULL
+ && len > 0 )
+ {
+ XML_Status status = XML_Parse(mParser, buf, len, false);
+ if (status == XML_STATUS_ERROR)
+ {
+ LL_INFOS() << "Unexpected XML parsing error at start" << LL_ENDL;
+ }
+ }
}
// Performance testing code
-//#define XML_PARSER_PERFORMANCE_TESTS
+//#define XML_PARSER_PERFORMANCE_TESTS
#ifdef XML_PARSER_PERFORMANCE_TESTS
extern U64 totalTime();
-U64 readElementTime = 0;
+U64 readElementTime = 0;
U64 startElementTime = 0;
U64 endElementTime = 0;
U64 charDataTime = 0;
@@ -577,333 +577,333 @@ U64 parseTime = 0;
class XML_Timer
{
public:
- XML_Timer( U64 * sum ) : mSum( sum )
- {
- mStart = totalTime();
- }
- ~XML_Timer()
- {
- *mSum += (totalTime() - mStart);
- }
-
- U64 * mSum;
- U64 mStart;
+ XML_Timer( U64 * sum ) : mSum( sum )
+ {
+ mStart = totalTime();
+ }
+ ~XML_Timer()
+ {
+ *mSum += (totalTime() - mStart);
+ }
+
+ U64 * mSum;
+ U64 mStart;
};
#endif // XML_PARSER_PERFORMANCE_TESTS
void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Char** attributes)
{
- #ifdef XML_PARSER_PERFORMANCE_TESTS
- XML_Timer timer( &startElementTime );
- #endif // XML_PARSER_PERFORMANCE_TESTS
-
- ++mDepth;
- if (mSkipping)
- {
- return;
- }
-
- Element element = readElement(name);
-
- mCurrentContent.clear();
-
- switch (element)
- {
- case ELEMENT_LLSD:
- if (mInLLSDElement) { return startSkipping(); }
- mInLLSDElement = true;
- return;
-
- case ELEMENT_KEY:
- if (mStack.empty() || !(mStack.back()->isMap()))
- {
- return startSkipping();
- }
- return;
-
- case ELEMENT_BINARY:
- {
- const XML_Char* encoding = findAttribute("encoding", attributes);
- if(encoding && strcmp("base64", encoding) != 0) { return startSkipping(); }
- break;
- }
-
- default:
- // all rest are values, fall through
- ;
- }
-
-
- if (!mInLLSDElement) { return startSkipping(); }
-
- if (mStack.empty())
- {
- mStack.push_back(&mResult);
- }
- else if (mStack.back()->isMap())
- {
- if (mCurrentKey.empty()) { return startSkipping(); }
-
- LLSD& map = *mStack.back();
- LLSD& newElement = map[mCurrentKey];
- mStack.push_back(&newElement);
-
- mCurrentKey.clear();
- }
- else if (mStack.back()->isArray())
- {
- LLSD& array = *mStack.back();
- array.append(LLSD());
- LLSD& newElement = array[array.size()-1];
- mStack.push_back(&newElement);
- }
- else {
- // improperly nested value in a non-structure
- return startSkipping();
- }
-
- ++mParseCount;
- switch (element)
- {
- case ELEMENT_MAP:
- *mStack.back() = LLSD::emptyMap();
- break;
-
- case ELEMENT_ARRAY:
- *mStack.back() = LLSD::emptyArray();
- break;
-
- default:
- // all the other values will be set in the end element handler
- ;
- }
+ #ifdef XML_PARSER_PERFORMANCE_TESTS
+ XML_Timer timer( &startElementTime );
+ #endif // XML_PARSER_PERFORMANCE_TESTS
+
+ ++mDepth;
+ if (mSkipping)
+ {
+ return;
+ }
+
+ Element element = readElement(name);
+
+ mCurrentContent.clear();
+
+ switch (element)
+ {
+ case ELEMENT_LLSD:
+ if (mInLLSDElement) { return startSkipping(); }
+ mInLLSDElement = true;
+ return;
+
+ case ELEMENT_KEY:
+ if (mStack.empty() || !(mStack.back()->isMap()))
+ {
+ return startSkipping();
+ }
+ return;
+
+ case ELEMENT_BINARY:
+ {
+ const XML_Char* encoding = findAttribute("encoding", attributes);
+ if(encoding && strcmp("base64", encoding) != 0) { return startSkipping(); }
+ break;
+ }
+
+ default:
+ // all rest are values, fall through
+ ;
+ }
+
+
+ if (!mInLLSDElement) { return startSkipping(); }
+
+ if (mStack.empty())
+ {
+ mStack.push_back(&mResult);
+ }
+ else if (mStack.back()->isMap())
+ {
+ if (mCurrentKey.empty()) { return startSkipping(); }
+
+ LLSD& map = *mStack.back();
+ LLSD& newElement = map[mCurrentKey];
+ mStack.push_back(&newElement);
+
+ mCurrentKey.clear();
+ }
+ else if (mStack.back()->isArray())
+ {
+ LLSD& array = *mStack.back();
+ array.append(LLSD());
+ LLSD& newElement = array[array.size()-1];
+ mStack.push_back(&newElement);
+ }
+ else {
+ // improperly nested value in a non-structure
+ return startSkipping();
+ }
+
+ ++mParseCount;
+ switch (element)
+ {
+ case ELEMENT_MAP:
+ *mStack.back() = LLSD::emptyMap();
+ break;
+
+ case ELEMENT_ARRAY:
+ *mStack.back() = LLSD::emptyArray();
+ break;
+
+ default:
+ // all the other values will be set in the end element handler
+ ;
+ }
}
void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
{
- #ifdef XML_PARSER_PERFORMANCE_TESTS
- XML_Timer timer( &endElementTime );
- #endif // XML_PARSER_PERFORMANCE_TESTS
-
- --mDepth;
- if (mSkipping)
- {
- if (mDepth < mSkipThrough)
- {
- mSkipping = false;
- }
- return;
- }
-
- Element element = readElement(name);
-
- switch (element)
- {
- case ELEMENT_LLSD:
- if (mInLLSDElement)
- {
- mInLLSDElement = false;
- mGracefullStop = true;
- XML_StopParser(mParser, false);
- }
- return;
-
- case ELEMENT_KEY:
- mCurrentKey = mCurrentContent;
- return;
-
- default:
- // all rest are values, fall through
- ;
- }
-
- if (!mInLLSDElement) { return; }
-
- LLSD& value = *mStack.back();
- mStack.pop_back();
-
- switch (element)
- {
- case ELEMENT_UNDEF:
- value.clear();
- break;
-
- case ELEMENT_BOOL:
- value = (mCurrentContent == "true" || mCurrentContent == "1");
- break;
-
- case ELEMENT_INTEGER:
- {
- S32 i;
- // sscanf okay here with different locales - ints don't change for different locale settings like floats do.
- if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
- { // See if sscanf works - it's faster
- value = i;
- }
- else
- {
- value = LLSD(mCurrentContent).asInteger();
- }
- }
- break;
-
- case ELEMENT_REAL:
- {
- value = LLSD(mCurrentContent).asReal();
- // removed since this breaks when locale has decimal separator that isn't '.'
- // investigated changing local to something compatible each time but deemed higher
- // risk that just using LLSD.asReal() each time.
- //F64 r;
- //if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
- //{ // See if sscanf works - it's faster
- // value = r;
- //}
- //else
- //{
- // value = LLSD(mCurrentContent).asReal();
- //}
- }
- break;
-
- case ELEMENT_STRING:
- value = mCurrentContent;
- break;
-
- case ELEMENT_UUID:
- value = LLSD(mCurrentContent).asUUID();
- break;
-
- case ELEMENT_DATE:
- value = LLSD(mCurrentContent).asDate();
- break;
-
- case ELEMENT_URI:
- value = LLSD(mCurrentContent).asURI();
- break;
-
- case ELEMENT_BINARY:
- {
- // Regex is expensive, but only fix for whitespace in base64,
- // created by python and other non-linden systems - DEV-39358
- // Fortunately we have very little binary passing now,
- // so performance impact shold be negligible. + poppy 2009-09-04
- boost::regex r;
- r.assign("\\s");
- std::string stripped = boost::regex_replace(mCurrentContent, r, "");
- S32 len = apr_base64_decode_len(stripped.c_str());
- std::vector<U8> data;
- data.resize(len);
- len = apr_base64_decode_binary(&data[0], stripped.c_str());
- data.resize(len);
- value = data;
- break;
- }
-
- case ELEMENT_UNKNOWN:
- value.clear();
- break;
-
- default:
- // other values, map and array, have already been set
- break;
- }
-
- mCurrentContent.clear();
+ #ifdef XML_PARSER_PERFORMANCE_TESTS
+ XML_Timer timer( &endElementTime );
+ #endif // XML_PARSER_PERFORMANCE_TESTS
+
+ --mDepth;
+ if (mSkipping)
+ {
+ if (mDepth < mSkipThrough)
+ {
+ mSkipping = false;
+ }
+ return;
+ }
+
+ Element element = readElement(name);
+
+ switch (element)
+ {
+ case ELEMENT_LLSD:
+ if (mInLLSDElement)
+ {
+ mInLLSDElement = false;
+ mGracefullStop = true;
+ XML_StopParser(mParser, false);
+ }
+ return;
+
+ case ELEMENT_KEY:
+ mCurrentKey = mCurrentContent;
+ return;
+
+ default:
+ // all rest are values, fall through
+ ;
+ }
+
+ if (!mInLLSDElement) { return; }
+
+ LLSD& value = *mStack.back();
+ mStack.pop_back();
+
+ switch (element)
+ {
+ case ELEMENT_UNDEF:
+ value.clear();
+ break;
+
+ case ELEMENT_BOOL:
+ value = (mCurrentContent == "true" || mCurrentContent == "1");
+ break;
+
+ case ELEMENT_INTEGER:
+ {
+ S32 i;
+ // sscanf okay here with different locales - ints don't change for different locale settings like floats do.
+ if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
+ { // See if sscanf works - it's faster
+ value = i;
+ }
+ else
+ {
+ value = LLSD(mCurrentContent).asInteger();
+ }
+ }
+ break;
+
+ case ELEMENT_REAL:
+ {
+ value = LLSD(mCurrentContent).asReal();
+ // removed since this breaks when locale has decimal separator that isn't '.'
+ // investigated changing local to something compatible each time but deemed higher
+ // risk that just using LLSD.asReal() each time.
+ //F64 r;
+ //if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
+ //{ // See if sscanf works - it's faster
+ // value = r;
+ //}
+ //else
+ //{
+ // value = LLSD(mCurrentContent).asReal();
+ //}
+ }
+ break;
+
+ case ELEMENT_STRING:
+ value = mCurrentContent;
+ break;
+
+ case ELEMENT_UUID:
+ value = LLSD(mCurrentContent).asUUID();
+ break;
+
+ case ELEMENT_DATE:
+ value = LLSD(mCurrentContent).asDate();
+ break;
+
+ case ELEMENT_URI:
+ value = LLSD(mCurrentContent).asURI();
+ break;
+
+ case ELEMENT_BINARY:
+ {
+ // Regex is expensive, but only fix for whitespace in base64,
+ // created by python and other non-linden systems - DEV-39358
+ // Fortunately we have very little binary passing now,
+ // so performance impact shold be negligible. + poppy 2009-09-04
+ boost::regex r;
+ r.assign("\\s");
+ std::string stripped = boost::regex_replace(mCurrentContent, r, "");
+ S32 len = apr_base64_decode_len(stripped.c_str());
+ std::vector<U8> data;
+ data.resize(len);
+ len = apr_base64_decode_binary(&data[0], stripped.c_str());
+ data.resize(len);
+ value = data;
+ break;
+ }
+
+ case ELEMENT_UNKNOWN:
+ value.clear();
+ break;
+
+ default:
+ // other values, map and array, have already been set
+ break;
+ }
+
+ mCurrentContent.clear();
}
void LLSDXMLParser::Impl::characterDataHandler(const XML_Char* data, int length)
{
- #ifdef XML_PARSER_PERFORMANCE_TESTS
- XML_Timer timer( &charDataTime );
- #endif // XML_PARSER_PERFORMANCE_TESTS
+ #ifdef XML_PARSER_PERFORMANCE_TESTS
+ XML_Timer timer( &charDataTime );
+ #endif // XML_PARSER_PERFORMANCE_TESTS
- mCurrentContent.append(data, length);
+ mCurrentContent.append(data, length);
}
void LLSDXMLParser::Impl::sStartElementHandler(
- void* userData, const XML_Char* name, const XML_Char** attributes)
+ void* userData, const XML_Char* name, const XML_Char** attributes)
{
- ((LLSDXMLParser::Impl*)userData)->startElementHandler(name, attributes);
+ ((LLSDXMLParser::Impl*)userData)->startElementHandler(name, attributes);
}
void LLSDXMLParser::Impl::sEndElementHandler(
- void* userData, const XML_Char* name)
+ void* userData, const XML_Char* name)
{
- ((LLSDXMLParser::Impl*)userData)->endElementHandler(name);
+ ((LLSDXMLParser::Impl*)userData)->endElementHandler(name);
}
void LLSDXMLParser::Impl::sCharacterDataHandler(
- void* userData, const XML_Char* data, int length)
+ void* userData, const XML_Char* data, int length)
{
- ((LLSDXMLParser::Impl*)userData)->characterDataHandler(data, length);
+ ((LLSDXMLParser::Impl*)userData)->characterDataHandler(data, length);
}
/*
- This code is time critical
-
- This is a sample of tag occurances of text in simstate file with ~8000 objects.
- A tag pair (<key>something</key>) counts is counted as two:
-
- key - 2680178
- real - 1818362
- integer - 906078
- array - 295682
- map - 191818
- uuid - 177903
- binary - 175748
- string - 53482
- undef - 40353
- boolean - 33874
- llsd - 16332
- uri - 38
- date - 1
+ This code is time critical
+
+ This is a sample of tag occurances of text in simstate file with ~8000 objects.
+ A tag pair (<key>something</key>) counts is counted as two:
+
+ key - 2680178
+ real - 1818362
+ integer - 906078
+ array - 295682
+ map - 191818
+ uuid - 177903
+ binary - 175748
+ string - 53482
+ undef - 40353
+ boolean - 33874
+ llsd - 16332
+ uri - 38
+ date - 1
*/
LLSDXMLParser::Impl::Element LLSDXMLParser::Impl::readElement(const XML_Char* name)
{
- #ifdef XML_PARSER_PERFORMANCE_TESTS
- XML_Timer timer( &readElementTime );
- #endif // XML_PARSER_PERFORMANCE_TESTS
-
- XML_Char c = *name;
- switch (c)
- {
- case 'k':
- if (strcmp(name, "key") == 0) { return ELEMENT_KEY; }
- break;
- case 'r':
- if (strcmp(name, "real") == 0) { return ELEMENT_REAL; }
- break;
- case 'i':
- if (strcmp(name, "integer") == 0) { return ELEMENT_INTEGER; }
- break;
- case 'a':
- if (strcmp(name, "array") == 0) { return ELEMENT_ARRAY; }
- break;
- case 'm':
- if (strcmp(name, "map") == 0) { return ELEMENT_MAP; }
- break;
- case 'u':
- if (strcmp(name, "uuid") == 0) { return ELEMENT_UUID; }
- if (strcmp(name, "undef") == 0) { return ELEMENT_UNDEF; }
- if (strcmp(name, "uri") == 0) { return ELEMENT_URI; }
- break;
- case 'b':
- if (strcmp(name, "binary") == 0) { return ELEMENT_BINARY; }
- if (strcmp(name, "boolean") == 0) { return ELEMENT_BOOL; }
- break;
- case 's':
- if (strcmp(name, "string") == 0) { return ELEMENT_STRING; }
- break;
- case 'l':
- if (strcmp(name, "llsd") == 0) { return ELEMENT_LLSD; }
- break;
- case 'd':
- if (strcmp(name, "date") == 0) { return ELEMENT_DATE; }
- break;
- }
- return ELEMENT_UNKNOWN;
+ #ifdef XML_PARSER_PERFORMANCE_TESTS
+ XML_Timer timer( &readElementTime );
+ #endif // XML_PARSER_PERFORMANCE_TESTS
+
+ XML_Char c = *name;
+ switch (c)
+ {
+ case 'k':
+ if (strcmp(name, "key") == 0) { return ELEMENT_KEY; }
+ break;
+ case 'r':
+ if (strcmp(name, "real") == 0) { return ELEMENT_REAL; }
+ break;
+ case 'i':
+ if (strcmp(name, "integer") == 0) { return ELEMENT_INTEGER; }
+ break;
+ case 'a':
+ if (strcmp(name, "array") == 0) { return ELEMENT_ARRAY; }
+ break;
+ case 'm':
+ if (strcmp(name, "map") == 0) { return ELEMENT_MAP; }
+ break;
+ case 'u':
+ if (strcmp(name, "uuid") == 0) { return ELEMENT_UUID; }
+ if (strcmp(name, "undef") == 0) { return ELEMENT_UNDEF; }
+ if (strcmp(name, "uri") == 0) { return ELEMENT_URI; }
+ break;
+ case 'b':
+ if (strcmp(name, "binary") == 0) { return ELEMENT_BINARY; }
+ if (strcmp(name, "boolean") == 0) { return ELEMENT_BOOL; }
+ break;
+ case 's':
+ if (strcmp(name, "string") == 0) { return ELEMENT_STRING; }
+ break;
+ case 'l':
+ if (strcmp(name, "llsd") == 0) { return ELEMENT_LLSD; }
+ break;
+ case 'd':
+ if (strcmp(name, "date") == 0) { return ELEMENT_DATE; }
+ break;
+ }
+ return ELEMENT_UNKNOWN;
}
@@ -919,34 +919,34 @@ LLSDXMLParser::LLSDXMLParser(bool emit_errors /* = true */) : impl(* new Impl(em
LLSDXMLParser::~LLSDXMLParser()
{
- delete &impl;
+ delete &impl;
}
void LLSDXMLParser::parsePart(const char *buf, llssize len)
{
- impl.parsePart(buf, len);
+ impl.parsePart(buf, len);
}
// virtual
S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data, S32 max_depth) const
{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
- #ifdef XML_PARSER_PERFORMANCE_TESTS
- XML_Timer timer( &parseTime );
- #endif // XML_PARSER_PERFORMANCE_TESTS
+ #ifdef XML_PARSER_PERFORMANCE_TESTS
+ XML_Timer timer( &parseTime );
+ #endif // XML_PARSER_PERFORMANCE_TESTS
- if (mParseLines)
- {
- // Use line-based reading (faster code)
- return impl.parseLines(input, data);
- }
+ if (mParseLines)
+ {
+ // Use line-based reading (faster code)
+ return impl.parseLines(input, data);
+ }
- return impl.parse(input, data);
+ return impl.parse(input, data);
}
-// virtual
+// virtual
void LLSDXMLParser::doReset()
{
- impl.reset();
+ impl.reset();
}