X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e767076e80df6db956bb44482594fea014e685c1..673810eeb8e16599b599f3a851692c323bc20165:/src/xml/xml.cpp diff --git a/src/xml/xml.cpp b/src/xml/xml.cpp index 6872113502..5507a4fd77 100644 --- a/src/xml/xml.cpp +++ b/src/xml/xml.cpp @@ -29,7 +29,7 @@ #include "wx/datstrm.h" #include "wx/zstream.h" #include "wx/strconv.h" -#include "wx/ptr_scpd.h" +#include "wx/scopedptr.h" #include "expat.h" // from Expat @@ -618,6 +618,17 @@ static void StartCdataHnd(void *userData) ctx->lastChild= ctx->lastAsText = textnode; } +static void EndCdataHnd(void *userData) +{ + wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData; + + // we need to reset this pointer so that subsequent text nodes don't append + // their contents to this one but create new wxXML_TEXT_NODE objects (or + // not create anything at all if only white space follows the CDATA section + // and wxXMLDOC_KEEP_WHITESPACE_NODES is not used as is commonly the case) + ctx->lastAsText = NULL; +} + static void CommentHnd(void *userData, const char *data) { wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData; @@ -717,7 +728,7 @@ bool wxXmlDocument::Load(wxInputStream& stream, const wxString& encoding, int fl XML_SetUserData(parser, (void*)&ctx); XML_SetElementHandler(parser, StartElementHnd, EndElementHnd); XML_SetCharacterDataHandler(parser, TextHnd); - XML_SetStartCdataSectionHandler(parser, StartCdataHnd); + XML_SetCdataSectionHandler(parser, StartCdataHnd, EndCdataHnd);; XML_SetCommentHandler(parser, CommentHnd); XML_SetDefaultHandler(parser, DefaultHnd); XML_SetUnknownEncodingHandler(parser, UnknownEncodingHnd, NULL); @@ -733,7 +744,7 @@ bool wxXmlDocument::Load(wxInputStream& stream, const wxString& encoding, int fl *wxConvCurrent); wxLogError(_("XML parsing error: '%s' at line %d"), error.c_str(), - XML_GetCurrentLineNumber(parser)); + (int)XML_GetCurrentLineNumber(parser)); ok = false; break; } @@ -783,12 +794,18 @@ bool OutputString(wxOutputStream& stream, #if wxUSE_UNICODE wxUnusedVar(convMem); + if ( !convFile ) + convFile = &wxConvUTF8; - const wxWX2MBbuf buf(str.mb_str(convFile ? *convFile : wxConvUTF8)); - if ( !buf ) + const wxScopedCharBuffer buf(str.mb_str(*convFile)); + if ( !buf.length() ) + { + // conversion failed, can't write this string in an XML file in this + // (presumably non-UTF-8) encoding return false; + } - stream.Write(buf, strlen(buf)); + stream.Write(buf, buf.length()); #else // !wxUSE_UNICODE if ( convFile && convMem ) { @@ -804,61 +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) -{ - const size_t len = str.length(); - size_t i, - last = 0; - for (i = 0; i < len; i++) - { - wxChar c = str.GetChar(i); - if (c == wxS('<') || c == wxS('>') || - (c == wxS('&') && str.Mid(i+1, 4) != wxS("amp;")) || - ((flags & XML_ESCAPE_QUOTES) && c == wxS('"'))) - { - if ( !OutputString(stream, str.substr(last, i), convMem, convFile) ) - return false; +// 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) +{ + wxString escaped; + escaped.reserve(str.length()); - 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; - } + for ( wxString::const_iterator i = str.begin(); i != str.end(); ++i ) + { + const wxChar c = *i; - if ( !OutputString(stream, escaped, convMem, convFile) ) - return false; + switch ( c ) + { + 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); + } - last = i + 1; + } + else + { + escaped.append(c); + } } } - return OutputString(stream, str.substr(last, i), convMem, convFile); + return OutputString(stream, escaped, convMem, convFile); } bool OutputIndentation(wxOutputStream& stream, @@ -867,7 +892,7 @@ bool OutputIndentation(wxOutputStream& stream, wxMBConv *convFile) { wxString str(wxS("\n")); - str += wxString(2*indent, wxS(' ')); + str += wxString(indent, wxS(' ')); return OutputString(stream, str, convMem, convFile); } @@ -888,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: @@ -904,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); } }