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:
Václav Slavík
2010-08-04 14:57:30 +00:00
parent bbd55ff956
commit 926649a996
2 changed files with 83 additions and 49 deletions

View File

@@ -821,62 +821,69 @@ bool OutputString(wxOutputStream& stream,
return stream.IsOk(); return stream.IsOk();
} }
// flags for OutputStringEnt() enum EscapingMode
enum
{ {
XML_ESCAPE_QUOTES = 1 Escape_Text,
Escape_Attribute
}; };
// Same as above, but create entities first. // Same as above, but create entities first.
// Translates '<' to "&lt;", '>' to "&gt;" and '&' to "&amp;" // Translates '<' to "&lt;", '>' to "&gt;" and so on, according to the spec:
bool OutputStringEnt(wxOutputStream& stream, // http://www.w3.org/TR/2000/WD-xml-c14n-20000119.html#charescaping
const wxString& str, bool OutputEscapedString(wxOutputStream& stream,
wxMBConv *convMem, const wxString& str,
wxMBConv *convFile, wxMBConv *convMem,
int flags = 0) wxMBConv *convFile,
EscapingMode mode)
{ {
const size_t len = str.length(); wxString escaped;
size_t i, escaped.reserve(str.length());
last = 0;
for (i = 0; i < len; i++) for ( wxString::const_iterator i = str.begin(); i != str.end(); ++i )
{ {
wxChar c = str.GetChar(i); const wxChar c = *i;
if (c == wxS('<') || c == wxS('>') ||
(c == wxS('&') && str.substr(i+1, 4) != wxS("amp;")) || switch ( c )
((flags & XML_ESCAPE_QUOTES) && c == wxS('"')))
{ {
if ( !OutputString(stream, str.substr(last, i - last), case wxS('<'):
convMem, convFile) ) escaped.append(wxS("&lt;"));
return false; break;
case wxS('>'):
escaped.append(wxS("&gt;"));
break;
case wxS('&'):
escaped.append(wxS("&amp;"));
break;
case wxS('\r'):
escaped.append(wxS("&#xD;"));
break;
default:
if ( mode == Escape_Attribute )
{
switch ( c )
{
case wxS('"'):
escaped.append(wxS("&quot;"));
break;
case wxS('\t'):
escaped.append(wxS("&#x9;"));
break;
case wxS('\n'):
escaped.append(wxS("&#xA;"));
break;
default:
escaped.append(c);
}
const char *escaped; }
switch ( c ) else
{ {
case wxS('<'): escaped.append(c);
escaped = "&lt;"; }
break;
case wxS('>'):
escaped = "&gt;";
break;
case wxS('&'):
escaped = "&amp;";
break;
case wxS('"'):
escaped = "&quot;";
break;
default:
wxFAIL_MSG( "logic error in the code" );
return false;
}
if ( !OutputString(stream, escaped, convMem, convFile) )
return false;
last = i + 1;
} }
} }
return OutputString(stream, str.substr(last, i - last), convMem, convFile); return OutputString(stream, escaped, convMem, convFile);
} }
bool OutputIndentation(wxOutputStream& stream, bool OutputIndentation(wxOutputStream& stream,
@@ -906,7 +913,9 @@ bool OutputNode(wxOutputStream& stream,
break; break;
case wxXML_TEXT_NODE: case wxXML_TEXT_NODE:
rc = OutputStringEnt(stream, node->GetContent(), convMem, convFile); rc = OutputEscapedString(stream, node->GetContent(),
convMem, convFile,
Escape_Text);
break; break;
case wxXML_ELEMENT_NODE: case wxXML_ELEMENT_NODE:
@@ -922,9 +931,9 @@ bool OutputNode(wxOutputStream& stream,
rc = OutputString(stream, rc = OutputString(stream,
wxS(" ") + attr->GetName() + wxS("=\""), wxS(" ") + attr->GetName() + wxS("=\""),
convMem, convFile) && convMem, convFile) &&
OutputStringEnt(stream, attr->GetValue(), OutputEscapedString(stream, attr->GetValue(),
convMem, convFile, convMem, convFile,
XML_ESCAPE_QUOTES) && Escape_Attribute) &&
OutputString(stream, wxS("\""), convMem, convFile); OutputString(stream, wxS("\""), convMem, convFile);
} }
} }

View File

@@ -76,12 +76,14 @@ private:
CPPUNIT_TEST( InsertChildAfter ); CPPUNIT_TEST( InsertChildAfter );
CPPUNIT_TEST( LoadSave ); CPPUNIT_TEST( LoadSave );
CPPUNIT_TEST( CDATA ); CPPUNIT_TEST( CDATA );
CPPUNIT_TEST( Escaping );
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
void InsertChild(); void InsertChild();
void InsertChildAfter(); void InsertChildAfter();
void LoadSave(); void LoadSave();
void CDATA(); void CDATA();
void Escaping();
DECLARE_NO_COPY_CLASS(XmlTestCase) DECLARE_NO_COPY_CLASS(XmlTestCase)
}; };
@@ -215,3 +217,26 @@ void XmlTestCase::CDATA()
// is not // is not
CPPUNIT_ASSERT_EQUAL( "Giovanni Mittone", n->GetContent() ); 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&#xD;&#xA;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() );
}