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();
|
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 "<", '>' to ">" and '&' to "&"
|
// Translates '<' to "<", '>' to ">" 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("<"));
|
||||||
return false;
|
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 )
|
else
|
||||||
{
|
{
|
||||||
case wxS('<'):
|
escaped.append(c);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
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