summaryrefslogtreecommitdiff
path: root/indra/llcommon/llsdserialize.cpp
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2020-05-13 16:37:12 -0400
committerNat Goodspeed <nat@lindenlab.com>2020-05-13 16:37:12 -0400
commit066fb5dafce71acc93bb04f2a271b43870a6b0bb (patch)
tree82132f120f2a104c0136d95678520defc61b7cee /indra/llcommon/llsdserialize.cpp
parent2ccb6422ea263a5bb6aadc7f8ba11048bd14ed87 (diff)
DRTVWR-476: Default LLSDNotationFormatter now OPTIONS_PRETTY_BINARY.
LLSDNotationFormatter (also LLSDNotationStreamer that uses it, plus operator<<(std::ostream&, const LLSD&) that uses LLSDNotationStreamer) is most useful for displaying LLSD to a human, e.g. for logging. Having the default dump raw binary bytes into the log file is not only suboptimal, it can truncate the output if one of those bytes is '\0'. (This is a problem with the logging subsystem, but that's a story for another day.) Use OPTIONS_PRETTY_BINARY wherever there is a default LLSDFormatter ::EFormatterOptions argument. Also, allow setting LLSDFormatter subclass boolalpha(), realFormat() and format(options) using optional constructor arguments. Naturally, each subclass that supports this must accept and forward these constructor arguments to its LLSDFormatter base class constructor. Fix a couple bugs in LLSDNotationFormatter::format_impl() for an LLSD::Binary value with OPTIONS_PRETTY_BINARY: - The code unconditionally emitted a b(len) type prefix followed by either raw binary or hex, depending on the option flag. OPTIONS_PRETTY_BINARY caused it to emit "0x" before the hex representation of the data. This is wrong in that it can't be read back by either the C++ or the Python LLSD parser. Correct OPTIONS_PRETTY_BINARY formatting consists of b16"hex digits" rather than b(len)"raw bytes". - Although the code did set hex mode, it didn't set either the field width or the fill character, so that a byte value less than 16 would emit a single digit rather than two. Instead of having one LLSDFormatter::format() method with an optional options argument, declare two overloads. The format() overload without options passes the mOptions data member to the overload accepting options. Refactor the LLSDFormatter family, hoisting the recursive format_impl() method (accepting level) to a pure virtual method at LLSDFormatter base-class level. Most subclasses therefore need not override either base-class format() method, only format_impl(). In fact the short format() overload isn't even virtual. Consistently use LLSDFormatter::EFormatterOptions enum as the options parameter wherever such options are accepted.
Diffstat (limited to 'indra/llcommon/llsdserialize.cpp')
-rw-r--r--indra/llcommon/llsdserialize.cpp74
1 files changed, 47 insertions, 27 deletions
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 79934642ae..598bec0558 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -66,7 +66,8 @@ const std::string LLSD_NOTATION_HEADER("llsd/notation");
*/
// static
-void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type, U32 options)
+void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type,
+ LLSDFormatter::EFormatterOptions options)
{
LLPointer<LLSDFormatter> f = NULL;
@@ -174,10 +175,10 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes)
{
p = new LLSDXMLParser;
}
- else if (header == LLSD_NOTATION_HEADER)
- {
- p = new LLSDNotationParser;
- }
+ else if (header == LLSD_NOTATION_HEADER)
+ {
+ p = new LLSDNotationParser;
+ }
else
{
LL_WARNS() << "deserialize request for unknown ELLSD_Serialize" << LL_ENDL;
@@ -1234,9 +1235,11 @@ bool LLSDBinaryParser::parseString(
/**
* LLSDFormatter
*/
-LLSDFormatter::LLSDFormatter() :
- mBoolAlpha(false)
+LLSDFormatter::LLSDFormatter(bool boolAlpha, const std::string& realFmt, EFormatterOptions options):
+ mOptions(options)
{
+ boolalpha(boolAlpha);
+ realFormat(realFmt);
}
// virtual
@@ -1253,6 +1256,17 @@ void LLSDFormatter::realFormat(const std::string& format)
mRealFormat = format;
}
+S32 LLSDFormatter::format(const LLSD& data, std::ostream& ostr) const
+{
+ // pass options captured by constructor
+ return format(data, ostr, mOptions);
+}
+
+S32 LLSDFormatter::format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const
+{
+ return format_impl(data, ostr, options, 0);
+}
+
void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const
{
std::string buffer = llformat(mRealFormat.c_str(), real);
@@ -1262,7 +1276,9 @@ void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const
/**
* LLSDNotationFormatter
*/
-LLSDNotationFormatter::LLSDNotationFormatter()
+LLSDNotationFormatter::LLSDNotationFormatter(bool boolAlpha, const std::string& realFormat,
+ EFormatterOptions options):
+ LLSDFormatter(boolAlpha, realFormat, options)
{
}
@@ -1278,14 +1294,8 @@ std::string LLSDNotationFormatter::escapeString(const std::string& in)
return ostr.str();
}
-// virtual
-S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
-{
- S32 rv = format_impl(data, ostr, options, 0);
- return rv;
-}
-
-S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const
+S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr,
+ EFormatterOptions options, U32 level) const
{
S32 format_count = 1;
std::string pre;
@@ -1406,21 +1416,29 @@ S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32
{
// *FIX: memory inefficient.
const std::vector<U8>& buffer = data.asBinary();
- ostr << "b(" << buffer.size() << ")\"";
- if(buffer.size())
+ if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY)
{
- if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY)
+ ostr << "b16\"";
+ if (! buffer.empty())
{
std::ios_base::fmtflags old_flags = ostr.flags();
ostr.setf( std::ios::hex, std::ios::basefield );
- ostr << "0x";
+ auto oldfill(ostr.fill('0'));
+ auto oldwidth(ostr.width());
for (int i = 0; i < buffer.size(); i++)
{
- ostr << (int) buffer[i];
+ // have to restate setw() before every conversion
+ ostr << std::setw(2) << (int) buffer[i];
}
+ ostr.width(oldwidth);
+ ostr.fill(oldfill);
ostr.flags(old_flags);
}
- else
+ }
+ else // ! OPTIONS_PRETTY_BINARY
+ {
+ ostr << "b(" << buffer.size() << ")\"";
+ if (! buffer.empty())
{
ostr.write((const char*)&buffer[0], buffer.size());
}
@@ -1437,11 +1455,12 @@ S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32
return format_count;
}
-
/**
* LLSDBinaryFormatter
*/
-LLSDBinaryFormatter::LLSDBinaryFormatter()
+LLSDBinaryFormatter::LLSDBinaryFormatter(bool boolAlpha, const std::string& realFormat,
+ EFormatterOptions options):
+ LLSDFormatter(boolAlpha, realFormat, options)
{
}
@@ -1450,7 +1469,8 @@ LLSDBinaryFormatter::~LLSDBinaryFormatter()
{ }
// virtual
-S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
+S32 LLSDBinaryFormatter::format_impl(const LLSD& data, std::ostream& ostr,
+ EFormatterOptions options, U32 level) const
{
S32 format_count = 1;
switch(data.type())
@@ -1466,7 +1486,7 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option
{
ostr.put('k');
formatString((*iter).first, ostr);
- format_count += format((*iter).second, ostr);
+ format_count += format_impl((*iter).second, ostr, options, level+1);
}
ostr.put('}');
break;
@@ -1481,7 +1501,7 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option
LLSD::array_const_iterator end = data.endArray();
for(; iter != end; ++iter)
{
- format_count += format(*iter, ostr);
+ format_count += format_impl(*iter, ostr, options, level+1);
}
ostr.put(']');
break;