diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 79934642ae2491cb78433dad618f6c8e0a531b69..598bec055853723349167707614fd63c84be2a5d 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;
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h
index fe0f4443ef2e6ba44ce5eed4b5aec90b77d68342..d6079fd9fa81c9cfecd29c84a7be6921432a29d9 100644
--- a/indra/llcommon/llsdserialize.h
+++ b/indra/llcommon/llsdserialize.h
@@ -435,7 +435,8 @@ class LL_COMMON_API LLSDFormatter : public LLRefCount
 	/** 
 	 * @brief Constructor
 	 */
-	LLSDFormatter();
+	LLSDFormatter(bool boolAlpha=false, const std::string& realFormat="",
+				  EFormatterOptions options=OPTIONS_PRETTY_BINARY);
 
 	/** 
 	 * @brief Set the boolean serialization format.
@@ -459,15 +460,37 @@ class LL_COMMON_API LLSDFormatter : public LLRefCount
 	void realFormat(const std::string& format);
 
 	/** 
-	 * @brief Call this method to format an LLSD to a stream.
+	 * @brief Call this method to format an LLSD to a stream with options as
+	 * set by the constructor.
+	 *
+	 * @param data The data to write.
+	 * @param ostr The destination stream for the data.
+	 * @return Returns The number of LLSD objects formatted out
+	 */
+	S32 format(const LLSD& data, std::ostream& ostr) const;
+
+	/** 
+	 * @brief Call this method to format an LLSD to a stream, passing options
+	 * explicitly.
 	 *
 	 * @param data The data to write.
 	 * @param ostr The destination stream for the data.
-	 * @return Returns The number of LLSD objects fomatted out
+	 * @param options OPTIONS_NONE to emit LLSD::Binary as raw bytes
+	 * @return Returns The number of LLSD objects formatted out
 	 */
-	virtual S32 format(const LLSD& data, std::ostream& ostr, U32 options = LLSDFormatter::OPTIONS_NONE) const = 0;
+	virtual S32 format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const;
 
 protected:
+	/** 
+	 * @brief Implementation to format the data. This is called recursively.
+	 *
+	 * @param data The data to write.
+	 * @param ostr The destination stream for the data.
+	 * @return Returns The number of LLSD objects formatted out
+	 */
+	virtual S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options,
+							U32 level) const = 0;
+
 	/** 
 	 * @brief Helper method which appropriately obeys the real format.
 	 *
@@ -476,9 +499,9 @@ class LL_COMMON_API LLSDFormatter : public LLRefCount
 	 */
 	void formatReal(LLSD::Real real, std::ostream& ostr) const;
 
-protected:
 	bool mBoolAlpha;
 	std::string mRealFormat;
+	EFormatterOptions mOptions;
 };
 
 
@@ -498,7 +521,8 @@ class LL_COMMON_API LLSDNotationFormatter : public LLSDFormatter
 	/** 
 	 * @brief Constructor
 	 */
-	LLSDNotationFormatter();
+	LLSDNotationFormatter(bool boolAlpha=false, const std::string& realFormat="",
+						  EFormatterOptions options=OPTIONS_PRETTY_BINARY);
 
 	/** 
 	 * @brief Helper static method to return a notation escaped string
@@ -512,25 +536,16 @@ class LL_COMMON_API LLSDNotationFormatter : public LLSDFormatter
 	 */
 	static std::string escapeString(const std::string& in);
 
-	/** 
-	 * @brief Call this method to format an LLSD to a stream.
-	 *
-	 * @param data The data to write.
-	 * @param ostr The destination stream for the data.
-	 * @return Returns The number of LLSD objects fomatted out
-	 */
-	virtual S32 format(const LLSD& data, std::ostream& ostr, U32 options = LLSDFormatter::OPTIONS_NONE) const;
-
 protected:
-
 	/** 
 	 * @brief Implementation to format the data. This is called recursively.
 	 *
 	 * @param data The data to write.
 	 * @param ostr The destination stream for the data.
-	 * @return Returns The number of LLSD objects fomatted out
+	 * @return Returns The number of LLSD objects formatted out
 	 */
-	S32 format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const;
+	S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options,
+					U32 level) const override;
 };
 
 
@@ -550,7 +565,8 @@ class LL_COMMON_API LLSDXMLFormatter : public LLSDFormatter
 	/** 
 	 * @brief Constructor
 	 */
-	LLSDXMLFormatter();
+	LLSDXMLFormatter(bool boolAlpha=false, const std::string& realFormat="",
+					 EFormatterOptions options=OPTIONS_PRETTY_BINARY);
 
 	/** 
 	 * @brief Helper static method to return an xml escaped string
@@ -565,20 +581,23 @@ class LL_COMMON_API LLSDXMLFormatter : public LLSDFormatter
 	 *
 	 * @param data The data to write.
 	 * @param ostr The destination stream for the data.
-	 * @return Returns The number of LLSD objects fomatted out
+	 * @return Returns The number of LLSD objects formatted out
 	 */
-	virtual S32 format(const LLSD& data, std::ostream& ostr, U32 options = LLSDFormatter::OPTIONS_NONE) const;
+	S32 format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const override;
 
-protected:
+	// also pull down base-class format() method that isn't overridden
+	using LLSDFormatter::format;
 
+protected:
 	/** 
 	 * @brief Implementation to format the data. This is called recursively.
 	 *
 	 * @param data The data to write.
 	 * @param ostr The destination stream for the data.
-	 * @return Returns The number of LLSD objects fomatted out
+	 * @return Returns The number of LLSD objects formatted out
 	 */
-	S32 format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const;
+	S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options,
+					U32 level) const override;
 };
 
 
@@ -618,18 +637,20 @@ class LL_COMMON_API LLSDBinaryFormatter : public LLSDFormatter
 	/** 
 	 * @brief Constructor
 	 */
-	LLSDBinaryFormatter();
+	LLSDBinaryFormatter(bool boolAlpha=false, const std::string& realFormat="",
+						EFormatterOptions options=OPTIONS_PRETTY_BINARY);
 
+protected:
 	/** 
-	 * @brief Call this method to format an LLSD to a stream.
+	 * @brief Implementation to format the data. This is called recursively.
 	 *
 	 * @param data The data to write.
 	 * @param ostr The destination stream for the data.
-	 * @return Returns The number of LLSD objects fomatted out
+	 * @return Returns The number of LLSD objects formatted out
 	 */
-	virtual S32 format(const LLSD& data, std::ostream& ostr, U32 options = LLSDFormatter::OPTIONS_NONE) const;
+	S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options,
+					U32 level) const override;
 
-protected:
 	/** 
 	 * @brief Helper method to serialize strings
 	 *
@@ -669,7 +690,8 @@ class LLSDOStreamer
 	/** 
 	 * @brief Constructor
 	 */
-	LLSDOStreamer(const LLSD& data, U32 options = LLSDFormatter::OPTIONS_NONE) :
+	LLSDOStreamer(const LLSD& data,
+				  LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY) :
 		mSD(data), mOptions(options) {}
 
 	/**
@@ -681,17 +703,17 @@ class LLSDOStreamer
 	 * @return Returns the stream passed in after streaming mSD.
 	 */
 	friend std::ostream& operator<<(
-		std::ostream& str,
-		const LLSDOStreamer<Formatter>& formatter)
+		std::ostream& out,
+		const LLSDOStreamer<Formatter>& streamer)
 	{
 		LLPointer<Formatter> f = new Formatter;
-		f->format(formatter.mSD, str, formatter.mOptions);
-		return str;
+		f->format(streamer.mSD, out, streamer.mOptions);
+		return out;
 	}
 
 protected:
 	LLSD mSD;
-	U32 mOptions;
+	LLSDFormatter::EFormatterOptions mOptions;
 };
 
 typedef LLSDOStreamer<LLSDNotationFormatter>	LLSDNotationStreamer;
@@ -724,7 +746,7 @@ class LL_COMMON_API LLSDSerialize
 	 * Generic in/outs
 	 */
 	static void serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize,
-		U32 options = LLSDFormatter::OPTIONS_NONE);
+						  LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY);
 
 	/**
 	 * @brief Examine a stream, and parse 1 sd object out based on contents.
@@ -752,9 +774,9 @@ class LL_COMMON_API LLSDSerialize
 	static S32 toPrettyBinaryNotation(const LLSD& sd, std::ostream& str)
 	{
 		LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter;
-		return f->format(sd, str, 
-				LLSDFormatter::OPTIONS_PRETTY | 
-				LLSDFormatter::OPTIONS_PRETTY_BINARY);
+		return f->format(sd, str,
+						 LLSDFormatter::EFormatterOptions(LLSDFormatter::OPTIONS_PRETTY | 
+														  LLSDFormatter::OPTIONS_PRETTY_BINARY));
 	}
 	static S32 fromNotation(LLSD& sd, std::istream& str, S32 max_bytes)
 	{
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index 6d0fe862b9189f8a0a41887a50f12cf54272d865..0da824d6945b1f3222b4a74ce810e86973ba98da 100644
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -45,7 +45,9 @@ extern "C"
 /**
  * LLSDXMLFormatter
  */
-LLSDXMLFormatter::LLSDXMLFormatter()
+LLSDXMLFormatter::LLSDXMLFormatter(bool boolAlpha, const std::string& realFormat,
+                                   EFormatterOptions options):
+    LLSDFormatter(boolAlpha, realFormat, options)
 {
 }
 
@@ -55,7 +57,8 @@ LLSDXMLFormatter::~LLSDXMLFormatter()
 }
 
 // virtual
-S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
+S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr,
+							 EFormatterOptions options) const
 {
 	std::streamsize old_precision = ostr.precision(25);
 
@@ -72,7 +75,8 @@ S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, U32 options)
 	return rv;
 }
 
-S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const
+S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr,
+								  EFormatterOptions options, U32 level) const
 {
 	S32 format_count = 1;
 	std::string pre;
diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp
index 6ac974e659383dfe7493595ffd648236f41066a7..642c1c387902602620114a0063afdcdee01ad535 100644
--- a/indra/llcommon/tests/llsdserialize_test.cpp
+++ b/indra/llcommon/tests/llsdserialize_test.cpp
@@ -271,10 +271,10 @@ namespace tut
 		LLSD w;
 		mParser->reset();	// reset() call is needed since test code re-uses mParser
 		mParser->parse(stream, w, stream.str().size());
-		
+
 		try
 		{
-			ensure_equals(msg.c_str(), w, v);
+			ensure_equals(msg, w, v);
 		}
 		catch (...)
 		{
@@ -432,6 +432,7 @@ namespace tut
 		
 		const char source[] = "it must be a blue moon again";
 		std::vector<U8> data;
+		// note, includes terminating '\0'
 		copy(&source[0], &source[sizeof(source)], back_inserter(data));
 		
 		v = data;
@@ -468,28 +469,36 @@ namespace tut
 		checkRoundTrip(msg + " many nested maps", v);
 	}
 	
-	typedef tut::test_group<TestLLSDSerializeData> TestLLSDSerialzeGroup;
-	typedef TestLLSDSerialzeGroup::object TestLLSDSerializeObject;
-	TestLLSDSerialzeGroup gTestLLSDSerializeGroup("llsd serialization");
+	typedef tut::test_group<TestLLSDSerializeData> TestLLSDSerializeGroup;
+	typedef TestLLSDSerializeGroup::object TestLLSDSerializeObject;
+	TestLLSDSerializeGroup gTestLLSDSerializeGroup("llsd serialization");
 
 	template<> template<> 
 	void TestLLSDSerializeObject::test<1>()
 	{
-		mFormatter = new LLSDNotationFormatter();
+		mFormatter = new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY);
 		mParser = new LLSDNotationParser();
-		doRoundTripTests("notation serialization");
+		doRoundTripTests("pretty binary notation serialization");
 	}
-	
+
 	template<> template<> 
 	void TestLLSDSerializeObject::test<2>()
+	{
+		mFormatter = new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE);
+		mParser = new LLSDNotationParser();
+		doRoundTripTests("raw binary notation serialization");
+	}
+
+	template<> template<> 
+	void TestLLSDSerializeObject::test<3>()
 	{
 		mFormatter = new LLSDXMLFormatter();
 		mParser = new LLSDXMLParser();
 		doRoundTripTests("xml serialization");
 	}
-	
+
 	template<> template<> 
-	void TestLLSDSerializeObject::test<3>()
+	void TestLLSDSerializeObject::test<4>()
 	{
 		mFormatter = new LLSDBinaryFormatter();
 		mParser = new LLSDBinaryParser();