diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 7a978303431cb373b46931f0aad0bf01d47c17be..1f653c159c8a06d4ecc5eb3b3b2102f79ca498b3 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -663,7 +663,8 @@ S32	LLStringOps::collate(const llwchar* a, const llwchar* b)
 
 namespace LLStringFn
 {
-	void replace_nonprintable(std::basic_string<char>& string, char replacement)
+	// NOTE - this restricts output to ascii
+	void replace_nonprintable_in_ascii(std::basic_string<char>& string, char replacement)
 	{
 		const char MIN = 0x20;
 		std::basic_string<char>::size_type len = string.size();
@@ -676,23 +677,9 @@ namespace LLStringFn
 		}
 	}
 
-	void replace_nonprintable(
-		std::basic_string<llwchar>& string,
-		llwchar replacement)
-	{
-		const llwchar MIN = 0x20;
-		const llwchar MAX = 0x7f;
-		std::basic_string<llwchar>::size_type len = string.size();
-		for(std::basic_string<llwchar>::size_type ii = 0; ii < len; ++ii)
-		{
-			if((string[ii] < MIN) || (string[ii] > MAX))
-			{
-				string[ii] = replacement;
-			}
-		}
-	}
 
-	void replace_nonprintable_and_pipe(std::basic_string<char>& str,
+	// NOTE - this restricts output to ascii
+	void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str,
 									   char replacement)
 	{
 		const char MIN  = 0x20;
@@ -707,22 +694,6 @@ namespace LLStringFn
 		}
 	}
 
-	void replace_nonprintable_and_pipe(std::basic_string<llwchar>& str,
-									   llwchar replacement)
-	{
-		const llwchar MIN  = 0x20;
-		const llwchar MAX  = 0x7f;
-		const llwchar PIPE = 0x7c;
-		std::basic_string<llwchar>::size_type len = str.size();
-		for(std::basic_string<llwchar>::size_type ii = 0; ii < len; ++ii)
-		{
-			if( (str[ii] < MIN) || (str[ii] > MAX) || (str[ii] == PIPE) )
-			{
-				str[ii] = replacement;
-			}
-		}
-	}
-
 	// https://wiki.lindenlab.com/wiki/Unicode_Guidelines has details on
 	// allowable code points for XML. Specifically, they are:
 	// 0x09, 0x0a, 0x0d, and 0x20 on up.  JC
@@ -748,6 +719,23 @@ namespace LLStringFn
 		return output;
 	}
 
+	/**
+	 * @brief Replace all control characters (c < 0x20) with replacement in
+	 * string.
+	 */
+	void replace_ascii_controlchars(std::basic_string<char>& string, char replacement)
+	{
+		const unsigned char MIN = 0x20;
+		std::basic_string<char>::size_type len = string.size();
+		for(std::basic_string<char>::size_type ii = 0; ii < len; ++ii)
+		{
+			const unsigned char c = (unsigned char) string[ii];
+			if(c < MIN)
+			{
+				string[ii] = replacement;
+			}
+		}
+	}
 }
 
 
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 4b62fbe70eb8df2d5fd326b2fc86e5c02014f7fa..8f6626b501dc32220f963608361dc56915b23bb6 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -487,48 +487,29 @@ namespace LLStringFn
 	/**
 	 * @brief Replace all non-printable characters with replacement in
 	 * string.
+	 * NOTE - this will zap non-ascii
 	 *
 	 * @param [in,out] string the to modify. out value is the string
 	 * with zero non-printable characters.
 	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
 	 */
-	void replace_nonprintable(
+	void replace_nonprintable_in_ascii(
 		std::basic_string<char>& string,
 		char replacement);
 
-	/**
-	 * @brief Replace all non-printable characters with replacement in
-	 * a wide string.
-	 *
-	 * @param [in,out] string the to modify. out value is the string
-	 * with zero non-printable characters.
-	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
-	 */
-	void replace_nonprintable(
-		std::basic_string<llwchar>& string,
-		llwchar replacement);
 
 	/**
 	 * @brief Replace all non-printable characters and pipe characters
 	 * with replacement in a string.
+	 * NOTE - this will zap non-ascii
 	 *
 	 * @param [in,out] the string to modify. out value is the string
 	 * with zero non-printable characters and zero pipe characters.
 	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
 	 */
-	void replace_nonprintable_and_pipe(std::basic_string<char>& str,
+	void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str,
 									   char replacement);
 
-	/**
-	 * @brief Replace all non-printable characters and pipe characters
-	 * with replacement in a wide string.
-	 *
-	 * @param [in,out] the string to modify. out value is the string
-	 * with zero non-printable characters and zero pipe characters.
-	 * @param The replacement wide character. use LL_UNKNOWN_CHAR if unsure.
-	 */
-	void replace_nonprintable_and_pipe(std::basic_string<llwchar>& str,
-									   llwchar replacement);
 
 	/**
 	 * @brief Remove all characters that are not allowed in XML 1.0.
@@ -536,6 +517,19 @@ namespace LLStringFn
 	 * Works with US ASCII and UTF-8 encoded strings.  JC
 	 */
 	std::string strip_invalid_xml(const std::string& input);
+
+
+	/**
+	 * @brief Replace all control characters (0 <= c < 0x20) with replacement in
+	 * string.   This is safe for utf-8
+	 *
+	 * @param [in,out] string the to modify. out value is the string
+	 * with zero non-printable characters.
+	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
+	 */
+	void replace_ascii_controlchars(
+		std::basic_string<char>& string,
+		char replacement);
 }
 
 ////////////////////////////////////////////////////////////
diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp
index bbf3f4af3bbf192b84039398f71ba0513a6a4c41..6fa5c9076ef2c0bc9dc7f75fef11a2f3423ecf9a 100644
--- a/indra/llinventory/llparcel.cpp
+++ b/indra/llinventory/llparcel.cpp
@@ -278,7 +278,7 @@ void LLParcel::setName(const std::string& name)
     // The escaping here must match the escaping in the database
     // abstraction layer.
     mName = name;
-    LLStringFn::replace_nonprintable(mName, LL_UNKNOWN_CHAR);
+    LLStringFn::replace_nonprintable_in_ascii(mName, LL_UNKNOWN_CHAR);
 }
 
 void LLParcel::setDesc(const std::string& desc)
@@ -296,7 +296,7 @@ void LLParcel::setMusicURL(const std::string& url)
     // abstraction layer.
     // This should really filter the url in some way. Other than
     // simply requiring non-printable.
-    LLStringFn::replace_nonprintable(mMusicURL, LL_UNKNOWN_CHAR);
+    LLStringFn::replace_nonprintable_in_ascii(mMusicURL, LL_UNKNOWN_CHAR);
 }
 
 void LLParcel::setMediaURL(const std::string& url)
@@ -306,7 +306,7 @@ void LLParcel::setMediaURL(const std::string& url)
     // abstraction layer if it's ever added.
     // This should really filter the url in some way. Other than
     // simply requiring non-printable.
-    LLStringFn::replace_nonprintable(mMediaURL, LL_UNKNOWN_CHAR);
+    LLStringFn::replace_nonprintable_in_ascii(mMediaURL, LL_UNKNOWN_CHAR);
 }
 
 void LLParcel::setMediaDesc(const std::string& desc)
diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp
index 21c0e579acdf6d3f10b9e24a988d1b38e7f2f64b..776f2b1535815f8c7fcf1e38a3ff8d70564ba8f4 100644
--- a/indra/llmessage/llcachename.cpp
+++ b/indra/llmessage/llcachename.cpp
@@ -894,7 +894,7 @@ void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup)
 		else
 		{	// is group
 			msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, entry->mGroupName, i);
-			LLStringFn::replace_nonprintable(entry->mGroupName, LL_UNKNOWN_CHAR);
+			LLStringFn::replace_ascii_controlchars(entry->mGroupName, LL_UNKNOWN_CHAR);
 		}
 
 		if (!isGroup)