char* Engine::FileSystem::Config::CXMLNode::ParseDeep( char* p, CXMLStrPair* parentEnd ) { // This is a recursive method, but thinking about it "at the current level" // it is a pretty simple flat list: // <foo/> // <!-- comment --> // // With a special case: // <foo> // </foo> // <!-- comment --> // // Where the closing element (/foo) *must* be the next thing after the opening // element, and the names must match. BUT the tricky bit is that the closing // element will be read by the child. // // 'endTag' is the end tag for this node, it is returned by a call to a child. // 'parentEnd' is the end tag for the parent, which is filled in and returned. while( p && *p ) { CXMLNode* node = 0; p = document->Identify( p, &node ); if ( p == 0 || node == 0 ) { break; } CXMLStrPair endTag; p = node->ParseDeep( p, &endTag ); if ( !p ) { DELETE_NODE( node ); node = 0; if ( !document->Error() ) { document->SetError( XML_ERROR_PARSING, 0, 0 ); } break; } // We read the end tag. Return it to the parent. if ( node->ToElement() && node->ToElement()->ClosingType() == CXMLElement::CLOSING ) { if ( parentEnd ) { *parentEnd = ((CXMLElement*)node)->value; } DELETE_NODE( node ); return p; } // Handle an end tag returned to this level. // And handle a bunch of annoying errors. CXMLElement* ele = node->ToElement(); if ( ele ) { if ( endTag.Empty() && ele->ClosingType() == CXMLElement::OPEN ) { document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); p = 0; } else if ( !endTag.Empty() && ele->ClosingType() != CXMLElement::OPEN ) { document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); p = 0; } else if ( !endTag.Empty() ) { if ( !CXMLUtil::StringEqual( endTag.GetStr(), node->Value() )) { document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); p = 0; } } } if ( p == 0 ) { DELETE_NODE( node ); node = 0; } if ( node ) { this->InsertEndChild( node ); } } return 0; }