const char* TTiXmlUnknown::Parse( const char* p, TTiXmlParsingData* data, TTiXmlEncoding encoding ) { TTiXmlDocument* document = GetDocument(); p = SkipWhiteSpace( p, encoding ); if ( data ) { data->Stamp( p, encoding ); location = data->Cursor(); } if ( !p || !*p || *p != '<' ) { if ( document ) document->SetError( TTiXml_ERROR_PARSING_UNKNOWN, p, data, encoding ); return 0; } ++p; value = ""; while ( p && *p && *p != '>' ) { value += *p; ++p; } if ( !p ) { if ( document ) document->SetError( TTiXml_ERROR_PARSING_UNKNOWN, 0, 0, encoding ); } if ( *p == '>' ) return p+1; return p; }
void TTiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) { while ( in->good() ) { int c = in->peek(); if ( !cdata && (c == '<' ) ) { return; } if ( c <= 0 ) { TTiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } (*tag) += (char) c; in->get(); // "commits" the peek made above if ( cdata && c == '>' && tag->size() >= 3 ) { size_t len = tag->size(); if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { // terminator of cdata. return; } } } }
const char* TTiXmlDeclaration::Parse( const char* p, TTiXmlParsingData* data, TTiXmlEncoding _encoding ) { p = SkipWhiteSpace( p, _encoding ); // Find the beginning, find the end, and look for // the stuff in-between. TTiXmlDocument* document = GetDocument(); if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) ) { if ( document ) document->SetError( TTiXml_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); return 0; } if ( data ) { data->Stamp( p, _encoding ); location = data->Cursor(); } p += 5; version = ""; encoding = ""; standalone = ""; while ( p && *p ) { if ( *p == '>' ) { ++p; return p; } p = SkipWhiteSpace( p, _encoding ); if ( StringEqual( p, "version", true, _encoding ) ) { TTiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); version = attrib.Value(); } else if ( StringEqual( p, "encoding", true, _encoding ) ) { TTiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); encoding = attrib.Value(); } else if ( StringEqual( p, "standalone", true, _encoding ) ) { TTiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); standalone = attrib.Value(); } else { // Read over whatever it is. while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) ++p; } } return 0; }
const char* TTiXmlComment::Parse( const char* p, TTiXmlParsingData* data, TTiXmlEncoding encoding ) { TTiXmlDocument* document = GetDocument(); value = ""; p = SkipWhiteSpace( p, encoding ); if ( data ) { data->Stamp( p, encoding ); location = data->Cursor(); } const char* startTag = "<!--"; const char* endTag = "-->"; if ( !StringEqual( p, startTag, false, encoding ) ) { document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); return 0; } p += strlen( startTag ); // [ 1475201 ] TinyXML parses entities in comments // Oops - ReadText doesn't work, because we don't want to parse the entities. // p = ReadText( p, &value, false, endTag, false, encoding ); // // from the XML spec: /* [Definition: Comments may appear anywhere in a document outside other markup; in addition, they may appear within the document type declaration at places allowed by the grammar. They are not part of the document's character data; an XML processor MAY, but need not, make it possible for an application to retrieve the text of comments. For compatibility, the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity references MUST NOT be recognized within comments. An example of a comment: <!-- declarations for <head> & <body> --> */ value = ""; // Keep all the white space. while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) { value.append( p, 1 ); ++p; } if ( p && *p ) p += strlen( endTag ); return p; }
const char* TTiXmlText::Parse( const char* p, TTiXmlParsingData* data, TTiXmlEncoding encoding ) { value = ""; TTiXmlDocument* document = GetDocument(); if ( data ) { data->Stamp( p, encoding ); location = data->Cursor(); } const char* const startTag = "<![CDATA["; const char* const endTag = "]]>"; if ( cdata || StringEqual( p, startTag, false, encoding ) ) { cdata = true; if ( !StringEqual( p, startTag, false, encoding ) ) { document->SetError( TTiXml_ERROR_PARSING_CDATA, p, data, encoding ); return 0; } p += strlen( startTag ); // Keep all the white space, ignore the encoding, etc. while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) { value += *p; ++p; } TTiXml_STRING dummy; p = ReadText( p, &dummy, false, endTag, false, encoding ); return p; } else { bool ignoreWhite = true; const char* end = "<"; p = ReadText( p, &value, ignoreWhite, end, false, encoding ); if ( p ) return p-1; // don't truncate the '<' return 0; } }
void TTiXmlText::StreamIn( TTiXml_ISTREAM * in, TTiXml_STRING * tag ) { if ( cdata ) { int c = in->get(); if ( c <= 0 ) { TTiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TTiXml_ERROR_EMBEDDED_NULL, 0, 0, TTiXml_ENCODING_UNKNOWN ); return; } (*tag) += (char) c; if ( c == '>' && tag->at( tag->length() - 2 ) == ']' && tag->at( tag->length() - 3 ) == ']' ) { // All is well. return; } } else { while ( in->good() ) { int c = in->peek(); if ( c == '<' ) return; if ( c <= 0 ) { TTiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TTiXml_ERROR_EMBEDDED_NULL, 0, 0, TTiXml_ENCODING_UNKNOWN ); return; } (*tag) += (char) c; in->get(); } } }
void TTiXmlElement::SetAttribute( const std::string& name, const std::string& _value ) { TTiXmlAttribute* node = attributeSet.Find( name ); if ( node ) { node->SetValue( _value ); return; } TTiXmlAttribute* attrib = new TTiXmlAttribute( name, _value ); if ( attrib ) { attributeSet.Add( attrib ); } else { TTiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TTiXml_ERROR_OUT_OF_MEMORY, 0, 0, TTiXml_ENCODING_UNKNOWN ); } }
void TTiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag ) { while ( in->good() ) { int c = in->get(); if ( c <= 0 ) { TTiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } (*tag) += (char) c; if ( c == '>' ) { // All is well. return; } } }
void TTiXmlDeclaration::StreamIn( TTiXml_ISTREAM * in, TTiXml_STRING * tag ) { while ( in->good() ) { int c = in->get(); if ( c <= 0 ) { TTiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TTiXml_ERROR_EMBEDDED_NULL, 0, 0, TTiXml_ENCODING_UNKNOWN ); return; } (*tag) += (char) c; if ( c == '>' ) { // All is well. return; } } }
TTiXmlNode* TTiXmlNode::ReplaceChild( TTiXmlNode* replaceThis, const TTiXmlNode& withThis ) { if ( !replaceThis ) return 0; if ( replaceThis->parent != this ) return 0; if ( withThis.ToDocument() ) { // A document can never be a child. Thanks to Noam. TTiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TTiXmlNode* node = withThis.Clone(); if ( !node ) return 0; node->next = replaceThis->next; node->prev = replaceThis->prev; if ( replaceThis->next ) replaceThis->next->prev = node; else lastChild = node; if ( replaceThis->prev ) replaceThis->prev->next = node; else firstChild = node; delete replaceThis; node->parent = this; return node; }
const char* TTiXmlComment::Parse( const char* p, TTiXmlParsingData* data, TTiXmlEncoding encoding ) { TTiXmlDocument* document = GetDocument(); value = ""; p = SkipWhiteSpace( p, encoding ); if ( data ) { data->Stamp( p, encoding ); location = data->Cursor(); } const char* startTag = "<!--"; const char* endTag = "-->"; if ( !StringEqual( p, startTag, false, encoding ) ) { document->SetError( TTiXml_ERROR_PARSING_COMMENT, p, data, encoding ); return 0; } p += strlen( startTag ); p = ReadText( p, &value, false, endTag, false, encoding ); return p; }
void TTiXmlDocument::operator=( const TTiXmlDocument& copy ) { Clear(); copy.CopyTo( this ); }
TTiXmlDocument::TTiXmlDocument( const TTiXmlDocument& copy ) : TTiXmlNode( TTiXmlNode::TINYXML_DOCUMENT ) { copy.CopyTo( this ); }
const char* TTiXmlElement::Parse( const char* p, TTiXmlParsingData* data, TTiXmlEncoding encoding ) { p = SkipWhiteSpace( p, encoding ); TTiXmlDocument* document = GetDocument(); if ( !p || !*p ) { if ( document ) document->SetError( TTiXml_ERROR_PARSING_ELEMENT, 0, 0, encoding ); return 0; } if ( data ) { data->Stamp( p, encoding ); location = data->Cursor(); } if ( *p != '<' ) { if ( document ) document->SetError( TTiXml_ERROR_PARSING_ELEMENT, p, data, encoding ); return 0; } p = SkipWhiteSpace( p+1, encoding ); // Read the name. const char* pErr = p; p = ReadName( p, &value, encoding ); if ( !p || !*p ) { if ( document ) document->SetError( TTiXml_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding ); return 0; } TTiXml_STRING endTag ("</"); endTag += value; endTag += ">"; // Check for and read attributes. Also look for an empty // tag or an end tag. while ( p && *p ) { pErr = p; p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) { if ( document ) document->SetError( TTiXml_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); return 0; } if ( *p == '/' ) { ++p; // Empty tag. if ( *p != '>' ) { if ( document ) document->SetError( TTiXml_ERROR_PARSING_EMPTY, p, data, encoding ); return 0; } return (p+1); } else if ( *p == '>' ) { // Done with attributes (if there were any.) // Read the value -- which can include other // elements -- read the end tag, and return. ++p; p = ReadValue( p, data, encoding ); // Note this is an Element method, and will set the error if one happens. if ( !p || !*p ) return 0; // We should find the end tag now if ( StringEqual( p, endTag.c_str(), false, encoding ) ) { p += endTag.length(); return p; } else { if ( document ) document->SetError( TTiXml_ERROR_READING_END_TAG, p, data, encoding ); return 0; } } else { // Try to read an attribute: TTiXmlAttribute* attrib = new TTiXmlAttribute(); if ( !attrib ) { if ( document ) document->SetError( TTiXml_ERROR_OUT_OF_MEMORY, pErr, data, encoding ); return 0; } attrib->SetDocument( document ); const char* pErr = p; p = attrib->Parse( p, data, encoding ); if ( !p || !*p ) { if ( document ) document->SetError( TTiXml_ERROR_PARSING_ELEMENT, pErr, data, encoding ); delete attrib; return 0; } // Handle the strange case of double attributes: TTiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() ); if ( node ) { node->SetValue( attrib->Value() ); delete attrib; return 0; } attributeSet.Add( attrib ); } } return p; }
void TTiXmlElement::StreamIn (TTiXml_ISTREAM * in, TTiXml_STRING * tag) { // We're called with some amount of pre-parsing. That is, some of "this" // element is in "tag". Go ahead and stream to the closing ">" while( in->good() ) { int c = in->get(); if ( c <= 0 ) { TTiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TTiXml_ERROR_EMBEDDED_NULL, 0, 0, TTiXml_ENCODING_UNKNOWN ); return; } (*tag) += (char) c ; if ( c == '>' ) break; } if ( tag->length() < 3 ) return; // Okay...if we are a "/>" tag, then we're done. We've read a complete tag. // If not, identify and stream. if ( tag->at( tag->length() - 1 ) == '>' && tag->at( tag->length() - 2 ) == '/' ) { // All good! return; } else if ( tag->at( tag->length() - 1 ) == '>' ) { // There is more. Could be: // text // closing tag // another node. for ( ;; ) { StreamWhiteSpace( in, tag ); // Do we have text? if ( in->good() && in->peek() != '<' ) { // Yep, text. TTiXmlText text( "" ); text.StreamIn( in, tag ); // What follows text is a closing tag or another node. // Go around again and figure it out. continue; } // We now have either a closing tag...or another node. // We should be at a "<", regardless. if ( !in->good() ) return; assert( in->peek() == '<' ); int tagIndex = (int) tag->length(); bool closingTag = false; bool firstCharFound = false; for( ;; ) { if ( !in->good() ) return; int c = in->peek(); if ( c <= 0 ) { TTiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TTiXml_ERROR_EMBEDDED_NULL, 0, 0, TTiXml_ENCODING_UNKNOWN ); return; } if ( c == '>' ) break; *tag += (char) c; in->get(); if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) ) { firstCharFound = true; if ( c == '/' ) closingTag = true; } } // If it was a closing tag, then read in the closing '>' to clean up the input stream. // If it was not, the streaming will be done by the tag. if ( closingTag ) { if ( !in->good() ) return; int c = in->get(); if ( c <= 0 ) { TTiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TTiXml_ERROR_EMBEDDED_NULL, 0, 0, TTiXml_ENCODING_UNKNOWN ); return; } assert( c == '>' ); *tag += (char) c; // We are done, once we've found our closing tag. return; } else { // If not a closing tag, id it, and stream. const char* tagloc = tag->c_str() + tagIndex; TTiXmlNode* node = Identify( tagloc, TTiXml_DEFAULT_ENCODING ); if ( !node ) return; node->StreamIn( in, tag ); delete node; node = 0; // No return: go around from the beginning: text, closing tag, or node. } } } }
TTiXmlNode* TTiXmlNode::Identify( const char* p, TTiXmlEncoding encoding ) { TTiXmlNode* returnNode = 0; p = SkipWhiteSpace( p, encoding ); if( !p || !*p || *p != '<' ) { return 0; } TTiXmlDocument* doc = GetDocument(); p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) { return 0; } // What is this thing? // - Elements start with a letter or underscore, but xml is reserved. // - Comments: <!-- // - Decleration: <?xml // - Everthing else is unknown to tinyxml. // const char* xmlHeader = { "<?xml" }; const char* commentHeader = { "<!--" }; const char* dtdHeader = { "<!" }; const char* cdataHeader = { "<![CDATA[" }; if ( StringEqual( p, xmlHeader, true, encoding ) ) { #ifdef DEBUG_PARSER TTiXml_LOG( "XML parsing Declaration\n" ); #endif returnNode = new TTiXmlDeclaration(); } else if ( StringEqual( p, commentHeader, false, encoding ) ) { #ifdef DEBUG_PARSER TTiXml_LOG( "XML parsing Comment\n" ); #endif returnNode = new TTiXmlComment(); } else if ( StringEqual( p, cdataHeader, false, encoding ) ) { #ifdef DEBUG_PARSER TTiXml_LOG( "XML parsing CDATA\n" ); #endif TTiXmlText* text = new TTiXmlText( "" ); text->SetCDATA( true ); returnNode = text; } else if ( StringEqual( p, dtdHeader, false, encoding ) ) { #ifdef DEBUG_PARSER TTiXml_LOG( "XML parsing Unknown(1)\n" ); #endif returnNode = new TTiXmlUnknown(); } else if ( IsAlpha( *(p+1), encoding ) || *(p+1) == '_' ) { #ifdef DEBUG_PARSER TTiXml_LOG( "XML parsing Element\n" ); #endif returnNode = new TTiXmlElement( "" ); } else { #ifdef DEBUG_PARSER TTiXml_LOG( "XML parsing Unknown(2)\n" ); #endif returnNode = new TTiXmlUnknown(); } if ( returnNode ) { // Set the parent, so it can report errors returnNode->parent = this; } else { if ( doc ) doc->SetError( TTiXml_ERROR_OUT_OF_MEMORY, 0, 0, TTiXml_ENCODING_UNKNOWN ); } return returnNode; }
const char* TTiXmlElement::ReadValue( const char* p, TTiXmlParsingData* data, TTiXmlEncoding encoding ) { TTiXmlDocument* document = GetDocument(); // Read in text and elements in any order. const char* pWithWhiteSpace = p; p = SkipWhiteSpace( p, encoding ); while ( p && *p ) { if ( *p != '<' ) { // Take what we have, make a text element. TTiXmlText* textNode = new TTiXmlText( "" ); if ( !textNode ) { if ( document ) document->SetError( TTiXml_ERROR_OUT_OF_MEMORY, 0, 0, encoding ); return 0; } if ( TTiXmlBase::IsWhiteSpaceCondensed() ) { p = textNode->Parse( p, data, encoding ); } else { // Special case: we want to keep the white space // so that leading spaces aren't removed. p = textNode->Parse( pWithWhiteSpace, data, encoding ); } if ( !textNode->Blank() ) LinkEndChild( textNode ); else delete textNode; } else { // We hit a '<' // Have we hit a new element or an end tag? This could also be // a TTiXmlText in the "CDATA" style. if ( StringEqual( p, "</", false, encoding ) ) { return p; } else { TTiXmlNode* node = Identify( p, encoding ); if ( node ) { p = node->Parse( p, data, encoding ); LinkEndChild( node ); } else { return 0; } } } pWithWhiteSpace = p; p = SkipWhiteSpace( p, encoding ); } if ( !p ) { if ( document ) document->SetError( TTiXml_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding ); } return p; }