Fix attributes escaping when writing XML.
wxXmlDocument didn't correctly escape some characters that the spec says must be escaped. Behaves correctly now. Fixes #12275. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65192 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
107
src/xml/xml.cpp
107
src/xml/xml.cpp
@@ -821,62 +821,69 @@ bool OutputString(wxOutputStream& stream,
|
||||
return stream.IsOk();
|
||||
}
|
||||
|
||||
// flags for OutputStringEnt()
|
||||
enum
|
||||
enum EscapingMode
|
||||
{
|
||||
XML_ESCAPE_QUOTES = 1
|
||||
Escape_Text,
|
||||
Escape_Attribute
|
||||
};
|
||||
|
||||
// Same as above, but create entities first.
|
||||
// Translates '<' to "<", '>' to ">" and '&' to "&"
|
||||
bool OutputStringEnt(wxOutputStream& stream,
|
||||
const wxString& str,
|
||||
wxMBConv *convMem,
|
||||
wxMBConv *convFile,
|
||||
int flags = 0)
|
||||
// Translates '<' to "<", '>' to ">" and so on, according to the spec:
|
||||
// http://www.w3.org/TR/2000/WD-xml-c14n-20000119.html#charescaping
|
||||
bool OutputEscapedString(wxOutputStream& stream,
|
||||
const wxString& str,
|
||||
wxMBConv *convMem,
|
||||
wxMBConv *convFile,
|
||||
EscapingMode mode)
|
||||
{
|
||||
const size_t len = str.length();
|
||||
size_t i,
|
||||
last = 0;
|
||||
for (i = 0; i < len; i++)
|
||||
wxString escaped;
|
||||
escaped.reserve(str.length());
|
||||
|
||||
for ( wxString::const_iterator i = str.begin(); i != str.end(); ++i )
|
||||
{
|
||||
wxChar c = str.GetChar(i);
|
||||
if (c == wxS('<') || c == wxS('>') ||
|
||||
(c == wxS('&') && str.substr(i+1, 4) != wxS("amp;")) ||
|
||||
((flags & XML_ESCAPE_QUOTES) && c == wxS('"')))
|
||||
const wxChar c = *i;
|
||||
|
||||
switch ( c )
|
||||
{
|
||||
if ( !OutputString(stream, str.substr(last, i - last),
|
||||
convMem, convFile) )
|
||||
return false;
|
||||
case wxS('<'):
|
||||
escaped.append(wxS("<"));
|
||||
break;
|
||||
case wxS('>'):
|
||||
escaped.append(wxS(">"));
|
||||
break;
|
||||
case wxS('&'):
|
||||
escaped.append(wxS("&"));
|
||||
break;
|
||||
case wxS('\r'):
|
||||
escaped.append(wxS("
"));
|
||||
break;
|
||||
default:
|
||||
if ( mode == Escape_Attribute )
|
||||
{
|
||||
switch ( c )
|
||||
{
|
||||
case wxS('"'):
|
||||
escaped.append(wxS("""));
|
||||
break;
|
||||
case wxS('\t'):
|
||||
escaped.append(wxS("	"));
|
||||
break;
|
||||
case wxS('\n'):
|
||||
escaped.append(wxS("
"));
|
||||
break;
|
||||
default:
|
||||
escaped.append(c);
|
||||
}
|
||||
|
||||
const char *escaped;
|
||||
switch ( c )
|
||||
{
|
||||
case wxS('<'):
|
||||
escaped = "<";
|
||||
break;
|
||||
case wxS('>'):
|
||||
escaped = ">";
|
||||
break;
|
||||
case wxS('&'):
|
||||
escaped = "&";
|
||||
break;
|
||||
case wxS('"'):
|
||||
escaped = """;
|
||||
break;
|
||||
default:
|
||||
wxFAIL_MSG( "logic error in the code" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !OutputString(stream, escaped, convMem, convFile) )
|
||||
return false;
|
||||
|
||||
last = i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
escaped.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OutputString(stream, str.substr(last, i - last), convMem, convFile);
|
||||
return OutputString(stream, escaped, convMem, convFile);
|
||||
}
|
||||
|
||||
bool OutputIndentation(wxOutputStream& stream,
|
||||
@@ -906,7 +913,9 @@ bool OutputNode(wxOutputStream& stream,
|
||||
break;
|
||||
|
||||
case wxXML_TEXT_NODE:
|
||||
rc = OutputStringEnt(stream, node->GetContent(), convMem, convFile);
|
||||
rc = OutputEscapedString(stream, node->GetContent(),
|
||||
convMem, convFile,
|
||||
Escape_Text);
|
||||
break;
|
||||
|
||||
case wxXML_ELEMENT_NODE:
|
||||
@@ -922,9 +931,9 @@ bool OutputNode(wxOutputStream& stream,
|
||||
rc = OutputString(stream,
|
||||
wxS(" ") + attr->GetName() + wxS("=\""),
|
||||
convMem, convFile) &&
|
||||
OutputStringEnt(stream, attr->GetValue(),
|
||||
convMem, convFile,
|
||||
XML_ESCAPE_QUOTES) &&
|
||||
OutputEscapedString(stream, attr->GetValue(),
|
||||
convMem, convFile,
|
||||
Escape_Attribute) &&
|
||||
OutputString(stream, wxS("\""), convMem, convFile);
|
||||
}
|
||||
}
|
||||
|
@@ -76,12 +76,14 @@ private:
|
||||
CPPUNIT_TEST( InsertChildAfter );
|
||||
CPPUNIT_TEST( LoadSave );
|
||||
CPPUNIT_TEST( CDATA );
|
||||
CPPUNIT_TEST( Escaping );
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
void InsertChild();
|
||||
void InsertChildAfter();
|
||||
void LoadSave();
|
||||
void CDATA();
|
||||
void Escaping();
|
||||
|
||||
DECLARE_NO_COPY_CLASS(XmlTestCase)
|
||||
};
|
||||
@@ -215,3 +217,26 @@ void XmlTestCase::CDATA()
|
||||
// is not
|
||||
CPPUNIT_ASSERT_EQUAL( "Giovanni Mittone", n->GetContent() );
|
||||
}
|
||||
|
||||
void XmlTestCase::Escaping()
|
||||
{
|
||||
// Verify that attribute values are escaped correctly, see
|
||||
// http://trac.wxwidgets.org/ticket/12275
|
||||
|
||||
const char *xmlText =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<root text=\"hello
this is a new line\">\n"
|
||||
" <x/>\n"
|
||||
"</root>\n"
|
||||
;
|
||||
|
||||
wxStringInputStream sis(xmlText);
|
||||
|
||||
wxXmlDocument doc;
|
||||
CPPUNIT_ASSERT( doc.Load(sis) );
|
||||
|
||||
wxStringOutputStream sos;
|
||||
CPPUNIT_ASSERT( doc.Save(sos) );
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL( xmlText, sos.GetString() );
|
||||
}
|
||||
|
Reference in New Issue
Block a user