Add support for Unicode strings in CMICmnLLDBUtilSBValue::GetValue (MI)

This patch includes the following changes:
# Add CMIUtilString::ConvertToASCII to convert unicode to ASCII (MI)
# Rework CMICmnLLDBUtilSBValue::GetSimpleValue to print wide/unicode char (MI)
## Add CMICmnLLDBUtilSBValue::GetSimpleValueChar
## Extend CMICmnLLDBUtilSBValue::IsCharType to accept char16_t/char32_t
## Don't ignore the fail_value in SBValue::GetValueAsUnsigned
# Rework CMIUtilString::ConvertToASCII (MI)
## Don't use templates
## Change the function signature to convert signle characters (was std::basic_string)
## Rename CMIUtilString::ConvertToASCII to CMIUtilString::ConvertToPrintableASCII
# Add CMIUtilString::ConvertToPrintableASCII for char (MI)
## Refactor CMIUtilString::Escape
## Simplify CMICmnLLDBUtilSBValue::GetSimpleValueChar for char
# Add char16_t* and char32_t* support in CMICmnLLDBUtilSBValue::GetSimpleValue (MI)
## Add CMICmnLLDBUtilSBValue::GetSimpleValueCStringPointer
## Add CMICmnLLDBUtilSBValue::ReadCStringFromHostMemory2
   (it's extended version of CMICmnLLDBUtilSBValue::ReadCStringFromHostMemory)
# Improve error checking in CMICmnLLDBUtilSBValue::GetSimpleValueChar (MI)
# Refactor CMICmnLLDBUtilSBValue (MI)
## Remove CMICmnLLDBUtilSBValue::ReadCStringFromHostMemory
   (use CMICmnLLDBUtilSBValue::ReadCStringFromHostMemory2 instead)
## Rename CMICmnLLDBUtilSBValue::ReadCStringFromHostMemory2 to
   CMICmnLLDBUtilSBValue::ReadCStringFromHostMemory
## Move CMICmnLLDBUtilSBValue::GetValueCString to private methods
## Rename CMICmnLLDBUtilSBValue::GetValueCString to
   CMICmnLLDBUtilSBValue::GetSimpleValueCStringArray
## Remove CMICmnLLDBUtilSBValue::GetChildValueCString
# Improve MiGdbSetShowTestCase.test_lldbmi_gdb_set_show_print_char_array_as_string test to check char16_t/char32_t (MI)
# Fix CMICmnLLDBUtilSBValue::GetSimpleValueCStringArray for Unicode (MI)
## Fix handling of char16_t and char32_t
## Improve CMICmnLLDBUtilSBValue::ReadCStringFromHostMemory to read
   variables of type char[]: add vnMaxLen argument
## Turn on few cases to check char16_t[] and char32_t[] output in
   MiGdbSetShowTestCase.test_lldbmi_gdb_set_show_print_char_array_as_string
# Remove unnecessary checks in CMICmnLLDBUtilSBValue (MI)

llvm-svn: 236827
This commit is contained in:
Ilia K 2015-05-08 11:21:13 +00:00
parent 84dc009bef
commit b9bfd969e3
6 changed files with 281 additions and 147 deletions

View File

@ -36,12 +36,28 @@ class MiGdbSetShowTestCase(lldbmi_testcase.MiTestCaseBase):
self.expect("\^done,value=\"off\"")
# Test that an char* is expanded to string when print char-array-as-string is "off"
self.runCmd("-var-create var1 * string_ptr")
self.expect("\^done,name=\"var1\",numchild=\"1\",value=\"0x[0-9a-f]+ \\\\\\\"string - const char \*\\\\\\\"\",type=\"const char \*\",thread-id=\"1\",has_more=\"0\"")
self.runCmd("-var-create - * cp")
self.expect("\^done,name=\"var\d+\",numchild=\"1\",value=\"0x[0-9a-f]+ \\\\\\\"hello\\\\\\\"\",type=\"const char \*\",thread-id=\"1\",has_more=\"0\"")
# Test that an char[] isn't expanded to string when print char-array-as-string is "off"
self.runCmd("-var-create var2 * string_arr")
self.expect("\^done,name=\"var2\",numchild=\"17\",value=\"\[17\]\",type=\"const char \[17\]\",thread-id=\"1\",has_more=\"0\"")
self.runCmd("-var-create - * ca")
self.expect("\^done,name=\"var\d+\",numchild=\"6\",value=\"\[6\]\",type=\"const char \[6\]\",thread-id=\"1\",has_more=\"0\"")
# Test that an char16_t* is expanded to string when print char-array-as-string is "off"
self.runCmd("-var-create - * u16p")
self.expect("\^done,name=\"var\d+\",numchild=\"1\",value=\"0x[0-9a-f]+ u\\\\\\\"hello\\\\\\\"\",type=\"const char16_t \*\",thread-id=\"1\",has_more=\"0\"")
# Test that an char16_t[] isn't expanded to string when print char-array-as-string is "off"
self.runCmd("-var-create - * u16a")
self.expect("\^done,name=\"var\d+\",numchild=\"6\",value=\"\[6\]\",type=\"const char16_t \[6\]\",thread-id=\"1\",has_more=\"0\"")
# Test that an char32_t* is expanded to string when print char-array-as-string is "off"
self.runCmd("-var-create - * u32p")
self.expect("\^done,name=\"var\d+\",numchild=\"1\",value=\"0x[0-9a-f]+ U\\\\\\\"hello\\\\\\\"\",type=\"const char32_t \*\",thread-id=\"1\",has_more=\"0\"")
# Test that an char32_t[] isn't expanded to string when print char-array-as-string is "off"
self.runCmd("-var-create - * u32a")
self.expect("\^done,name=\"var\d+\",numchild=\"6\",value=\"\[6\]\",type=\"const char32_t \[6\]\",thread-id=\"1\",has_more=\"0\"")
# Test that -gdb-set can set print char-array-as-string flag
self.runCmd("-gdb-set print char-array-as-string on")
@ -52,12 +68,28 @@ class MiGdbSetShowTestCase(lldbmi_testcase.MiTestCaseBase):
self.expect("\^done,value=\"on\"")
# Test that an char* is expanded to string when print char-array-as-string is "on"
self.runCmd("-var-create var1 * string_ptr")
self.expect("\^done,name=\"var1\",numchild=\"1\",value=\"0x[0-9a-f]+ \\\\\\\"string - const char \*\\\\\\\"\",type=\"const char \*\",thread-id=\"1\",has_more=\"0\"")
self.runCmd("-var-create - * cp")
self.expect("\^done,name=\"var\d+\",numchild=\"1\",value=\"0x[0-9a-f]+ \\\\\\\"hello\\\\\\\"\",type=\"const char \*\",thread-id=\"1\",has_more=\"0\"")
# Test that an char[] isn't expanded to string when print char-array-as-string is "on"
self.runCmd("-var-create var2 * string_arr")
self.expect("\^done,name=\"var2\",numchild=\"17\",value=\"\\\\\\\"string - char \[\]\\\\\\\"\",type=\"const char \[17\]\",thread-id=\"1\",has_more=\"0\"")
self.runCmd("-var-create - * ca")
self.expect("\^done,name=\"var\d+\",numchild=\"6\",value=\"\\\\\\\"hello\\\\\\\"\",type=\"const char \[6\]\",thread-id=\"1\",has_more=\"0\"")
# Test that an char16_t* is expanded to string when print char-array-as-string is "on"
self.runCmd("-var-create - * u16p")
self.expect("\^done,name=\"var\d+\",numchild=\"1\",value=\"0x[0-9a-f]+ u\\\\\\\"hello\\\\\\\"\",type=\"const char16_t \*\",thread-id=\"1\",has_more=\"0\"")
# Test that an char16_t[] isn't expanded to string when print char-array-as-string is "on"
self.runCmd("-var-create - * u16a")
self.expect("\^done,name=\"var\d+\",numchild=\"6\",value=\"u\\\\\\\"hello\\\\\\\"\",type=\"const char16_t \[6\]\",thread-id=\"1\",has_more=\"0\"")
# Test that an char32_t* is expanded to string when print char-array-as-string is "on"
self.runCmd("-var-create - * u32p")
self.expect("\^done,name=\"var\d+\",numchild=\"1\",value=\"0x[0-9a-f]+ U\\\\\\\"hello\\\\\\\"\",type=\"const char32_t \*\",thread-id=\"1\",has_more=\"0\"")
# Test that an char32_t[] isn't expanded to string when print char-array-as-string is "on"
self.runCmd("-var-create - * u32a")
self.expect("\^done,name=\"var\d+\",numchild=\"6\",value=\"U\\\\\\\"hello\\\\\\\"\",type=\"const char32_t \[6\]\",thread-id=\"1\",has_more=\"0\"")
# Test that -gdb-set print char-array-as-string fails if "on"/"off" isn't specified
self.runCmd("-gdb-set print char-array-as-string")

View File

@ -47,8 +47,12 @@ var_list_children(void)
void
gdb_set_show_print_char_array_as_string_test(void)
{
const char *string_ptr = "string - const char *";
const char string_arr[] = "string - char []";
const char *cp = "hello";
const char ca[] = "hello";
const char16_t *u16p = u"hello";
const char16_t u16a[] = u"hello";
const char32_t *u32p = U"hello";
const char32_t u32a[] = U"hello";
// BP_gdb_set_show_print_char_array_as_string_test
}

View File

@ -7,6 +7,9 @@
//
//===----------------------------------------------------------------------===//
// Third party headers:
#include <cinttypes>
// In-house headers:
#include "MICmnLLDBUtilSBValue.h"
#include "MICmnLLDBDebugSessionInfo.h"
@ -121,14 +124,12 @@ CMICmnLLDBUtilSBValue::GetSimpleValue(const bool vbHandleArrayType, CMIUtilStrin
{
if (m_bHandleCharType && IsCharType())
{
const uint8_t value = m_rValue.GetValueAsUnsigned();
const CMIUtilString prefix(CMIUtilString::Format("%c", value).Escape().AddSlashes());
vwrValue = CMIUtilString::Format("%hhu '%s'", value, prefix.c_str());
vwrValue = GetSimpleValueChar();
return MIstatus::success;
}
else
{
const MIchar *pValue = m_bValidSBValue ? m_rValue.GetValue() : nullptr;
const MIchar *pValue = m_rValue.GetValue();
vwrValue = pValue != nullptr ? pValue : m_pUnkwn;
return MIstatus::success;
}
@ -137,18 +138,12 @@ CMICmnLLDBUtilSBValue::GetSimpleValue(const bool vbHandleArrayType, CMIUtilStrin
{
if (m_bHandleCharType && IsFirstChildCharType())
{
const MIchar *pValue = m_bValidSBValue ? m_rValue.GetValue() : nullptr;
const CMIUtilString value = pValue != nullptr ? pValue : m_pUnkwn;
const CMIUtilString prefix(GetChildValueCString().Escape().AddSlashes());
// Note code that has const in will not show the text suffix to the string pointer
// i.e. const char * pMyStr = "blah"; ==> "0x00007000"" <-- Eclipse shows this
// but char * pMyStr = "blah"; ==> "0x00007000" "blah"" <-- Eclipse shows this
vwrValue = CMIUtilString::Format("%s \"%s\"", value.c_str(), prefix.c_str());
vwrValue = GetSimpleValueCStringPointer();
return MIstatus::success;
}
else
{
const MIchar *pValue = m_bValidSBValue ? m_rValue.GetValue() : nullptr;
const MIchar *pValue = m_rValue.GetValue();
vwrValue = pValue != nullptr ? pValue : m_pUnkwn;
return MIstatus::success;
}
@ -161,10 +156,7 @@ CMICmnLLDBUtilSBValue::GetSimpleValue(const bool vbHandleArrayType, CMIUtilStrin
bPrintCharArrayAsString) && bPrintCharArrayAsString;
if (bPrintCharArrayAsString && m_bHandleCharType && IsFirstChildCharType())
{
// TODO: to match char* it should be the following
// vwrValue = CMIUtilString::Format("[%u] \"%s\"", nChildren, prefix.c_str());
const CMIUtilString prefix(GetValueCString().Escape().AddSlashes());
vwrValue = CMIUtilString::Format("\"%s\"", prefix.c_str());
vwrValue = GetSimpleValueCStringArray();
return MIstatus::success;
}
else if (vbHandleArrayType)
@ -178,6 +170,137 @@ CMICmnLLDBUtilSBValue::GetSimpleValue(const bool vbHandleArrayType, CMIUtilStrin
return MIstatus::failure;
}
//++ ------------------------------------------------------------------------------------
// Details: Retrieve from the LLDB SB Value object the char value of the variable.
// Type: Method.
// Args: None.
// Return: CMIUtilString - The char value of the variable.
// Throws: None.
//--
CMIUtilString
CMICmnLLDBUtilSBValue::GetSimpleValueChar(void) const
{
const uint64_t value = m_rValue.GetValueAsUnsigned();
if (value == 0)
{
const uint64_t nFailValue = 1;
if (nFailValue == m_rValue.GetValueAsUnsigned(nFailValue))
return m_pUnkwn;
}
const lldb::BasicType eType = m_rValue.GetType().GetBasicType();
switch (eType)
{
default:
assert(0 && "value must be a char type");
case lldb::eBasicTypeChar:
case lldb::eBasicTypeSignedChar:
case lldb::eBasicTypeUnsignedChar:
{
const CMIUtilString prefix(CMIUtilString::ConvertToPrintableASCII((char)value));
return CMIUtilString::Format("%" PRIu8 " '%s'", (uint8_t)value, prefix.c_str());
}
case lldb::eBasicTypeChar16:
{
const CMIUtilString prefix(CMIUtilString::ConvertToPrintableASCII((char16_t)value));
return CMIUtilString::Format("U+%04" PRIx16 " u'%s'", (uint16_t)value, prefix.c_str());
}
case lldb::eBasicTypeChar32:
{
const CMIUtilString prefix(CMIUtilString::ConvertToPrintableASCII((char32_t)value));
return CMIUtilString::Format("U+%08" PRIx32 " U'%s'", (uint32_t)value, prefix.c_str());
}
}
}
//++ ------------------------------------------------------------------------------------
// Details: Retrieve from the LLDB SB Value object of type char* the c-string value.
// Type: Method.
// Args: None.
// Return: CMIUtilString - The c-string value of the variable.
// Throws: None.
//--
CMIUtilString
CMICmnLLDBUtilSBValue::GetSimpleValueCStringPointer(void) const
{
const MIchar *value = m_rValue.GetValue();
if (value == nullptr)
return m_pUnkwn;
lldb::SBValue child = m_rValue.GetChildAtIndex(0);
const lldb::BasicType eType = child.GetType().GetBasicType();
switch (eType)
{
default:
assert(0 && "child must be a char type");
case lldb::eBasicTypeChar:
case lldb::eBasicTypeSignedChar:
case lldb::eBasicTypeUnsignedChar:
{
// FIXME Add slashes before double quotes
const CMIUtilString prefix(ReadCStringFromHostMemory<char>(child).AddSlashes());
// Note code that has const in will not show the text suffix to the string pointer
// i.e. const char * pMyStr = "blah"; ==> "0x00007000"" <-- Eclipse shows this
// but char * pMyStr = "blah"; ==> "0x00007000" "blah"" <-- Eclipse shows this
return CMIUtilString::Format("%s \"%s\"", value, prefix.c_str());
}
case lldb::eBasicTypeChar16:
{
// FIXME Add slashes before double quotes
const CMIUtilString prefix(ReadCStringFromHostMemory<char16_t>(child).AddSlashes());
return CMIUtilString::Format("%s u\"%s\"", value, prefix.c_str());
}
case lldb::eBasicTypeChar32:
{
// FIXME Add slashes before double quotes
const CMIUtilString prefix(ReadCStringFromHostMemory<char32_t>(child).AddSlashes());
return CMIUtilString::Format("%s U\"%s\"", value, prefix.c_str());
}
}
}
//++ ------------------------------------------------------------------------------------
// Details: Retrieve from the LLDB SB Value object of type char[] the c-string value.
// Type: Method.
// Args: None.
// Return: CMIUtilString - The c-string value of the variable.
// Throws: None.
//--
CMIUtilString
CMICmnLLDBUtilSBValue::GetSimpleValueCStringArray(void) const
{
const MIuint nChildren = m_rValue.GetNumChildren();
lldb::SBValue child = m_rValue.GetChildAtIndex(0);
const lldb::BasicType eType = child.GetType().GetBasicType();
switch (eType)
{
default:
assert(0 && "value must be a char[] type");
case lldb::eBasicTypeChar:
case lldb::eBasicTypeSignedChar:
case lldb::eBasicTypeUnsignedChar:
{
// FIXME Add slashes before double quotes
const CMIUtilString prefix(ReadCStringFromHostMemory<char>(m_rValue, nChildren).AddSlashes());
// TODO: to match char* it should be the following
// return CMIUtilString::Format("[%u] \"%s\"", nChildren, prefix.c_str());
return CMIUtilString::Format("\"%s\"", prefix.c_str());
}
case lldb::eBasicTypeChar16:
{
// FIXME Add slashes before double quotes
const CMIUtilString prefix(ReadCStringFromHostMemory<char16_t>(m_rValue, nChildren).AddSlashes());
return CMIUtilString::Format("u\"%s\"", prefix.c_str());
}
case lldb::eBasicTypeChar32:
{
// FIXME Add slashes before double quotes
const CMIUtilString prefix(ReadCStringFromHostMemory<char32_t>(m_rValue, nChildren).AddSlashes());
return CMIUtilString::Format("U\"%s\"", prefix.c_str());
}
}
}
bool
CMICmnLLDBUtilSBValue::GetCompositeValue(const bool vbPrintFieldNames, CMICmnMIValueTuple &vwrMiValueTuple,
const MIuint vnDepth /* = 1 */) const
@ -234,28 +357,6 @@ CMICmnLLDBUtilSBValue::GetCompositeValue(const bool vbPrintFieldNames, CMICmnMIV
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: If the LLDB SB Value object is a char or char[] type then form the text data
// string otherwise return nothing. m_bHandleCharType must be true to return
// text data if any.
// Type: Method.
// Args: None.
// Return: CMIUtilString - Text description of the variable's value.
// Throws: None.
//--
CMIUtilString
CMICmnLLDBUtilSBValue::GetValueCString(void) const
{
CMIUtilString text;
if (m_bHandleCharType && (IsCharType() || (IsArrayType() && IsFirstChildCharType())))
{
text = ReadCStringFromHostMemory(m_rValue);
}
return text;
}
//++ ------------------------------------------------------------------------------------
// Details: Retrieve the flag stating whether this value object is a char type or some
// other type. Char type can be signed or unsigned.
@ -268,7 +369,17 @@ bool
CMICmnLLDBUtilSBValue::IsCharType(void) const
{
const lldb::BasicType eType = m_rValue.GetType().GetBasicType();
return ((eType == lldb::eBasicTypeChar) || (eType == lldb::eBasicTypeSignedChar) || (eType == lldb::eBasicTypeUnsignedChar));
switch (eType)
{
case lldb::eBasicTypeChar:
case lldb::eBasicTypeSignedChar:
case lldb::eBasicTypeUnsignedChar:
case lldb::eBasicTypeChar16:
case lldb::eBasicTypeChar32:
return true;
default:
return false;
}
}
//++ ------------------------------------------------------------------------------------
@ -341,62 +452,35 @@ CMICmnLLDBUtilSBValue::IsArrayType(void) const
return m_rValue.GetType().IsArrayType();
}
//++ ------------------------------------------------------------------------------------
// Details: Retrieve the C string data for a child of char type (one and only child) for
// the parent value object. If the child is not a char type or the parent has
// more than one child then an empty string is returned. Char type can be
// signed or unsigned.
// Type: Method.
// Args: None.
// Return: CMIUtilString - Text description of the variable's value.
// Throws: None.
//--
CMIUtilString
CMICmnLLDBUtilSBValue::GetChildValueCString(void) const
{
CMIUtilString text;
const MIuint nChildren = m_rValue.GetNumChildren();
// Is it a basic type
if (nChildren == 0)
return text;
// Is it a composite type
if (nChildren > 1)
return text;
lldb::SBValue member = m_rValue.GetChildAtIndex(0);
const CMICmnLLDBUtilSBValue utilValue(member);
if (m_bHandleCharType && utilValue.IsCharType())
{
text = ReadCStringFromHostMemory(member);
}
return text;
}
//++ ------------------------------------------------------------------------------------
// Details: Retrieve the C string data of value object by read the memory where the
// variable is held.
// Type: Method.
// Args: vrValueObj - (R) LLDB SBValue variable object.
// Args: vrValue - (R) LLDB SBValue variable object.
// Return: CMIUtilString - Text description of the variable's value.
// Throws: None.
//--
template <typename charT>
CMIUtilString
CMICmnLLDBUtilSBValue::ReadCStringFromHostMemory(const lldb::SBValue &vrValueObj) const
CMICmnLLDBUtilSBValue::ReadCStringFromHostMemory(lldb::SBValue &vrValue, const MIuint vnMaxLen) const
{
CMIUtilString text;
lldb::SBValue &rValue = const_cast<lldb::SBValue &>(vrValueObj);
const lldb::addr_t addr = rValue.GetLoadAddress();
CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
const MIuint nBytes(128);
std::unique_ptr<char[]> apBufferMemory(new char[nBytes]);
std::string result;
lldb::addr_t addr = vrValue.GetLoadAddress(), end_addr = addr + vnMaxLen * sizeof(charT);
lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetProcess();
lldb::SBError error;
const MIuint64 nReadBytes = rSessionInfo.GetProcess().ReadMemory(addr, apBufferMemory.get(), nBytes, error);
MIunused(nReadBytes);
return CMIUtilString(apBufferMemory.get());
while (addr < end_addr)
{
charT ch;
const MIuint64 nReadBytes = process.ReadMemory(addr, &ch, sizeof(ch), error);
if (error.Fail() || nReadBytes != sizeof(ch))
return m_pUnkwn;
else if (ch == 0)
break;
result.append(CMIUtilString::ConvertToPrintableASCII(ch));
addr += sizeof(ch);
}
return result.c_str();
}
//++ ------------------------------------------------------------------------------------

View File

@ -36,8 +36,6 @@ class CMICmnLLDBUtilSBValue
//
CMIUtilString GetName(void) const;
CMIUtilString GetValue(const bool vbExpandAggregates = false) const;
CMIUtilString GetValueCString(void) const;
CMIUtilString GetChildValueCString(void) const;
CMIUtilString GetTypeName(void) const;
CMIUtilString GetTypeNameDisplay(void) const;
bool IsCharType(void) const;
@ -53,8 +51,11 @@ class CMICmnLLDBUtilSBValue
// Methods:
private:
CMIUtilString ReadCStringFromHostMemory(const lldb::SBValue &vrValueObj) const;
template <typename charT> CMIUtilString ReadCStringFromHostMemory(lldb::SBValue &vrValue, const MIuint vnMaxLen = UINT32_MAX) const;
bool GetSimpleValue(const bool vbHandleArrayType, CMIUtilString &vrValue) const;
CMIUtilString GetSimpleValueChar(void) const;
CMIUtilString GetSimpleValueCStringPointer(void) const;
CMIUtilString GetSimpleValueCStringArray(void) const;
bool GetCompositeValue(const bool vbPrintFieldNames, CMICmnMIValueTuple &vwrMiValueTuple, const MIuint vnDepth = 1) const;
// Attributes:

View File

@ -17,7 +17,6 @@
// In-house headers:
#include "MIUtilString.h"
#include "Platform.h"
//++ ------------------------------------------------------------------------------------
// Details: CMIUtilString constructor.
@ -804,54 +803,10 @@ CMIUtilString::Escape(const bool vbEscapeQuotes /* = false */) const
for (MIuint nIndex(0); nIndex < nLen; ++nIndex)
{
const MIchar cUnescapedChar((*this)[nIndex]);
switch (cUnescapedChar)
{
case '\a':
strNew.append("\\a");
break;
case '\b':
strNew.append("\\b");
break;
case '\t':
strNew.append("\\t");
break;
case '\n':
strNew.append("\\n");
break;
case '\v':
strNew.append("\\v");
break;
case '\f':
strNew.append("\\f");
break;
case '\r':
strNew.append("\\r");
break;
case '\033':
strNew.append("\\e");
break;
case '\\':
strNew.append("\\\\");
break;
case '\"':
if (vbEscapeQuotes)
{
strNew.append("\\\"");
break;
}
// FALLTHROUGH
default:
if (::isprint(cUnescapedChar))
strNew.push_back(cUnescapedChar);
else
{
const size_t size = sizeof("\\xXX");
char strEscapedChar[size];
::snprintf(strEscapedChar, size, "\\x%02" PRIx8, cUnescapedChar);
strNew.append(strEscapedChar);
}
break;
}
if (cUnescapedChar == '"' && vbEscapeQuotes)
strNew.append("\\\"");
else
strNew.append(ConvertToPrintableASCII((char)cUnescapedChar));
}
return strNew;
}
@ -939,3 +894,57 @@ CMIUtilString::StripSlashes(void) const
return strNew;
}
CMIUtilString
CMIUtilString::ConvertToPrintableASCII(const char vChar)
{
switch (vChar)
{
case '\a':
return "\\a";
case '\b':
return "\\b";
case '\t':
return "\\t";
case '\n':
return "\\n";
case '\v':
return "\\v";
case '\f':
return "\\f";
case '\r':
return "\\r";
case '\033':
return "\\e";
case '\\':
return "\\\\";
default:
if (::isprint(vChar))
return Format("%c", vChar);
else
return Format("\\x%02" PRIx8, vChar);
}
}
CMIUtilString
CMIUtilString::ConvertToPrintableASCII(const char16_t vChar16)
{
if (vChar16 == (char16_t)(char)vChar16 && ::isprint(vChar16))
// Convert char16_t to char (if possible)
return Format("%c", vChar16);
else
return Format("\\u%02" PRIx8 "%02" PRIx8,
(vChar16 >> 8) & 0xff, vChar16 & 0xff);
}
CMIUtilString
CMIUtilString::ConvertToPrintableASCII(const char32_t vChar32)
{
if (vChar32 == (char32_t)(char)vChar32 && ::isprint(vChar32))
// Convert char32_t to char (if possible)
return Format("%c", vChar32);
else
return Format("\\U%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8,
(vChar32 >> 24) & 0xff, (vChar32 >> 16) & 0xff,
(vChar32 >> 8) & 0xff, vChar32 & 0xff);
}

View File

@ -12,6 +12,7 @@
// Third party headers:
#include <string>
#include <vector>
#include <cinttypes>
// In-house headers:
#include "MIDataTypes.h"
@ -36,6 +37,9 @@ class CMIUtilString : public std::string
static CMIUtilString FormatValist(const CMIUtilString &vrFormating, va_list vArgs);
static bool IsAllValidAlphaAndNumeric(const MIchar &vrText);
static bool Compare(const CMIUtilString &vrLhs, const CMIUtilString &vrRhs);
static CMIUtilString ConvertToPrintableASCII(const char vChar);
static CMIUtilString ConvertToPrintableASCII(const char16_t vChar16);
static CMIUtilString ConvertToPrintableASCII(const char32_t vChar32);
// Methods:
public: