X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/cc24bf919256e8e1d317dbb8e67df6d007d641ea..ad66316ffbcfd10a4fb448116371d27db3613d17:/src/xml/xml.cpp diff --git a/src/xml/xml.cpp b/src/xml/xml.cpp index 1f1539556d..278adff98f 100644 --- a/src/xml/xml.cpp +++ b/src/xml/xml.cpp @@ -49,10 +49,11 @@ static bool wxIsWhiteOnly(const wxString& buf); wxXmlNode::wxXmlNode(wxXmlNode *parent,wxXmlNodeType type, const wxString& name, const wxString& content, - wxXmlAttribute *attrs, wxXmlNode *next) + wxXmlAttribute *attrs, wxXmlNode *next, int lineNo) : m_type(type), m_name(name), m_content(content), m_attrs(attrs), m_parent(parent), - m_children(NULL), m_next(next) + m_children(NULL), m_next(next), + m_lineNo(lineNo) { if (m_parent) { @@ -67,10 +68,12 @@ wxXmlNode::wxXmlNode(wxXmlNode *parent,wxXmlNodeType type, } wxXmlNode::wxXmlNode(wxXmlNodeType type, const wxString& name, - const wxString& content) + const wxString& content, + int lineNo) : m_type(type), m_name(name), m_content(content), m_attrs(NULL), m_parent(NULL), - m_children(NULL), m_next(NULL) + m_children(NULL), m_next(NULL), + m_lineNo(lineNo) {} wxXmlNode::wxXmlNode(const wxXmlNode& node) @@ -110,6 +113,7 @@ void wxXmlNode::DoCopy(const wxXmlNode& node) m_type = node.m_type; m_name = node.m_name; m_content = node.m_content; + m_lineNo = node.m_lineNo; m_children = NULL; wxXmlNode *n = node.m_children; @@ -183,39 +187,69 @@ void wxXmlNode::AddChild(wxXmlNode *child) child->m_parent = this; } -bool wxXmlNode::InsertChild(wxXmlNode *child, wxXmlNode *before_node) +// inserts a new node in front of 'followingNode' +bool wxXmlNode::InsertChild(wxXmlNode *child, wxXmlNode *followingNode) { - wxCHECK_MSG(before_node == NULL || before_node->GetParent() == this, false, - wxT("wxXmlNode::InsertChild - the node has incorrect parent")); - wxCHECK_MSG(child, false, wxT("Cannot insert a NULL pointer!")); + wxCHECK_MSG( child, false, "cannot insert a NULL node!" ); + wxCHECK_MSG( child->m_parent == NULL, false, "node already has a parent" ); + wxCHECK_MSG( child->m_next == NULL, false, "node already has m_next" ); + wxCHECK_MSG( followingNode == NULL || followingNode->GetParent() == this, + false, + "wxXmlNode::InsertChild - followingNode has incorrect parent" ); - if (m_children == before_node) - m_children = child; - else if (m_children == NULL) - { - if (before_node != NULL) - return false; // we have no children so we don't need to search - m_children = child; - } - else if (before_node == NULL) + // this is for backward compatibility, NULL was allowed here thanks to + // the confusion about followingNode's meaning + if ( followingNode == NULL ) + followingNode = m_children; + + if ( m_children == followingNode ) { - // prepend child - child->m_parent = this; child->m_next = m_children; m_children = child; - return true; } else { wxXmlNode *ch = m_children; - while (ch && ch->m_next != before_node) ch = ch->m_next; - if (!ch) - return false; // before_node not found + while ( ch && ch->m_next != followingNode ) + ch = ch->m_next; + if ( !ch ) + { + wxFAIL_MSG( "followingNode has this node as parent, but couldn't be found among children" ); + return false; + } + + child->m_next = followingNode; ch->m_next = child; } child->m_parent = this; - child->m_next = before_node; + return true; +} + +// inserts a new node right after 'precedingNode' +bool wxXmlNode::InsertChildAfter(wxXmlNode *child, wxXmlNode *precedingNode) +{ + wxCHECK_MSG( child, false, "cannot insert a NULL node!" ); + wxCHECK_MSG( child->m_parent == NULL, false, "node already has a parent" ); + wxCHECK_MSG( child->m_next == NULL, false, "node already has m_next" ); + wxCHECK_MSG( precedingNode == NULL || precedingNode->m_parent == this, false, + "precedingNode has wrong parent" ); + + if ( precedingNode ) + { + child->m_next = precedingNode->m_next; + precedingNode->m_next = child; + } + else // precedingNode == NULL + { + wxCHECK_MSG( m_children == NULL, false, + "NULL precedingNode only makes sense when there are no children" ); + + child->m_next = m_children; + m_children = child; + } + + child->m_parent = this; return true; } @@ -248,6 +282,21 @@ bool wxXmlNode::RemoveChild(wxXmlNode *child) } } +void wxXmlNode::AddAttribute(const wxString& name, const wxString& value) +{ + AddProperty(name, value); +} + +void wxXmlNode::AddAttribute(wxXmlAttribute *attr) +{ + AddProperty(attr); +} + +bool wxXmlNode::DeleteAttribute(const wxString& name) +{ + return DeleteProperty(name); +} + void wxXmlNode::AddProperty(const wxString& name, const wxString& value) { AddProperty(new wxXmlAttribute(name, value, NULL)); @@ -436,7 +485,7 @@ static wxString CharToString(wxMBConv *conv, #endif // !wxUSE_UNICODE wxUnusedVar(conv); - return wxString::FromUTF8(s, len); + return wxString::FromUTF8Unchecked(s, len); } // returns true if the given string contains only whitespaces @@ -454,38 +503,75 @@ bool wxIsWhiteOnly(const wxString& buf) struct wxXmlParsingContext { + wxXmlParsingContext() + : conv(NULL), + root(NULL), + node(NULL), + lastChild(NULL), + lastAsText(NULL), + removeWhiteOnlyNodes(false) + {} + + XML_Parser parser; wxMBConv *conv; wxXmlNode *root; - wxXmlNode *node; - wxXmlNode *lastAsText; + wxXmlNode *node; // the node being parsed + wxXmlNode *lastChild; // the last child of "node" + wxXmlNode *lastAsText; // the last _text_ child of "node" wxString encoding; wxString version; bool removeWhiteOnlyNodes; }; +// checks that ctx->lastChild is in consistent state +#define ASSERT_LAST_CHILD_OK(ctx) \ + wxASSERT( ctx->lastChild == NULL || \ + ctx->lastChild->GetNext() == NULL ); \ + wxASSERT( ctx->lastChild == NULL || \ + ctx->lastChild->GetParent() == ctx->node ) + extern "C" { static void StartElementHnd(void *userData, const char *name, const char **atts) { wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData; - wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, CharToString(ctx->conv, name)); + wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, + CharToString(ctx->conv, name), + wxEmptyString, + XML_GetCurrentLineNumber(ctx->parser)); const char **a = atts; + + // add node attributes while (*a) { node->AddAttribute(CharToString(ctx->conv, a[0]), CharToString(ctx->conv, a[1])); a += 2; } + if (ctx->root == NULL) + { ctx->root = node; + } else - ctx->node->AddChild(node); - ctx->node = node; + { + ASSERT_LAST_CHILD_OK(ctx); + ctx->node->InsertChildAfter(node, ctx->lastChild); + } + ctx->lastAsText = NULL; + ctx->lastChild = NULL; // our new node "node" has no children yet + + ctx->node = node; } static void EndElementHnd(void *userData, const char* WXUNUSED(name)) { wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData; + // we're exiting the last children of ctx->node->GetParent() and going + // back one level up, so current value of ctx->node points to the last + // child of ctx->node->GetParent() + ctx->lastChild = ctx->node; + ctx->node = ctx->node->GetParent(); ctx->lastAsText = NULL; } @@ -507,8 +593,13 @@ static void TextHnd(void *userData, const char *s, int len) if (!whiteOnly) { - ctx->lastAsText = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"), str); - ctx->node->AddChild(ctx->lastAsText); + wxXmlNode *textnode = + new wxXmlNode(wxXML_TEXT_NODE, wxT("text"), str, + XML_GetCurrentLineNumber(ctx->parser)); + + ASSERT_LAST_CHILD_OK(ctx); + ctx->node->InsertChildAfter(textnode, ctx->lastChild); + ctx->lastChild= ctx->lastAsText = textnode; } } } @@ -517,8 +608,13 @@ static void StartCdataHnd(void *userData) { wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData; - ctx->lastAsText = new wxXmlNode(wxXML_CDATA_SECTION_NODE, wxT("cdata"),wxT("")); - ctx->node->AddChild(ctx->lastAsText); + wxXmlNode *textnode = + new wxXmlNode(wxXML_CDATA_SECTION_NODE, wxT("cdata"), wxT(""), + XML_GetCurrentLineNumber(ctx->parser)); + + ASSERT_LAST_CHILD_OK(ctx); + ctx->node->InsertChildAfter(textnode, ctx->lastChild); + ctx->lastChild= ctx->lastAsText = textnode; } static void CommentHnd(void *userData, const char *data) @@ -527,12 +623,19 @@ static void CommentHnd(void *userData, const char *data) if (ctx->node) { - // VS: ctx->node == NULL happens if there is a comment before - // the root element (e.g. wxDesigner's output). We ignore such - // comments, no big deal... - ctx->node->AddChild(new wxXmlNode(wxXML_COMMENT_NODE, - wxT("comment"), CharToString(ctx->conv, data))); + wxXmlNode *commentnode = + new wxXmlNode(wxXML_COMMENT_NODE, + wxT("comment"), CharToString(ctx->conv, data), + XML_GetCurrentLineNumber(ctx->parser)); + + ASSERT_LAST_CHILD_OK(ctx); + ctx->node->InsertChildAfter(commentnode, ctx->lastChild); + ctx->lastChild = commentnode; } + //else: ctx->node == NULL happens if there is a comment before + // the root element. We current don't have a way to represent + // these in wxXmlDocument (FIXME). + ctx->lastAsText = NULL; } @@ -601,7 +704,6 @@ bool wxXmlDocument::Load(wxInputStream& stream, const wxString& encoding, int fl bool done; XML_Parser parser = XML_ParserCreate(NULL); - ctx.root = ctx.node = NULL; ctx.encoding = wxT("UTF-8"); // default in absence of encoding="" ctx.conv = NULL; #if !wxUSE_UNICODE @@ -609,6 +711,7 @@ bool wxXmlDocument::Load(wxInputStream& stream, const wxString& encoding, int fl ctx.conv = new wxCSConv(encoding); #endif ctx.removeWhiteOnlyNodes = (flags & wxXMLDOC_KEEP_WHITESPACE_NODES) == 0; + ctx.parser = parser; XML_SetUserData(parser, (void*)&ctx); XML_SetElementHandler(parser, StartElementHnd, EndElementHnd);