#include "wx/zstream.h"
#include "wx/strconv.h"
#include "wx/scopedptr.h"
+#include "wx/versioninfo.h"
#include "expat.h" // from Expat
: m_type(type), m_name(name), m_content(content),
m_attrs(attrs), m_parent(parent),
m_children(NULL), m_next(next),
- m_lineNo(lineNo)
+ m_lineNo(lineNo),
+ m_noConversion(false)
{
if (m_parent)
{
: m_type(type), m_name(name), m_content(content),
m_attrs(NULL), m_parent(NULL),
m_children(NULL), m_next(NULL),
- m_lineNo(lineNo)
+ m_lineNo(lineNo), m_noConversion(false)
{}
wxXmlNode::wxXmlNode(const wxXmlNode& node)
m_name = node.m_name;
m_content = node.m_content;
m_lineNo = node.m_lineNo;
+ m_noConversion = node.m_noConversion;
m_children = NULL;
wxXmlNode *n = node.m_children;
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;
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);
*wxConvCurrent);
wxLogError(_("XML parsing error: '%s' at line %d"),
error.c_str(),
- XML_GetCurrentLineNumber(parser));
+ (int)XML_GetCurrentLineNumber(parser));
ok = false;
break;
}
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.substr(i+1, 4) != wxS("amp;")) ||
- ((flags & XML_ESCAPE_QUOTES) && c == wxS('"')))
- {
- if ( !OutputString(stream, str.substr(last, i - last),
- 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 - last), convMem, convFile);
+ return OutputString(stream, escaped, convMem, convFile);
}
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);
}
break;
case wxXML_TEXT_NODE:
- rc = OutputStringEnt(stream, node->GetContent(), convMem, convFile);
+ if (node->GetNoConversion())
+ {
+ stream.Write(node->GetContent().c_str(), node->GetContent().Length());
+ rc = true;
+ }
+ else
+ rc = OutputEscapedString(stream, node->GetContent(),
+ convMem, convFile,
+ Escape_Text);
break;
case wxXML_ELEMENT_NODE:
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);
}
}
OutputString(stream, wxS("\n"), convMem.get(), convFile.get());
}
+/*static*/ wxVersionInfo wxXmlDocument::GetLibraryVersionInfo()
+{
+ return wxVersionInfo("expat",
+ XML_MAJOR_VERSION,
+ XML_MINOR_VERSION,
+ XML_MICRO_VERSION);
+}
+
#endif // wxUSE_XML