void TTiXmlElement::StreamOut( TTiXml_OSTREAM * stream ) const { (*stream) << "<" << value; const TTiXmlAttribute* attrib; for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) { (*stream) << " "; attrib->StreamOut( stream ); } // If this node has children, give it a closing tag. Else // make it an empty tag. TTiXmlNode* node; if ( firstChild ) { (*stream) << ">"; for ( node = firstChild; node; node=node->NextSibling() ) { node->StreamOut( stream ); } (*stream) << "</" << value << ">"; } else { (*stream) << " />"; } }
void TTiXmlDocument::StreamIn( TTiXml_ISTREAM * in, TTiXml_STRING * tag ) { // The basic issue with a document is that we don't know what we're // streaming. Read something presumed to be a tag (and hope), then // identify it, and call the appropriate stream method on the tag. // // This "pre-streaming" will never read the closing ">" so the // sub-tag can orient itself. if ( !StreamTo( in, '<', tag ) ) { SetError( TTiXml_ERROR_PARSING_EMPTY, 0, 0, TTiXml_ENCODING_UNKNOWN ); return; } while ( in->good() ) { int tagIndex = (int) tag->length(); while ( in->good() && in->peek() != '>' ) { int c = in->get(); if ( c <= 0 ) { SetError( TTiXml_ERROR_EMBEDDED_NULL, 0, 0, TTiXml_ENCODING_UNKNOWN ); break; } (*tag) += (char) c; } if ( in->good() ) { // We now have something we presume to be a node of // some sort. Identify it, and call the node to // continue streaming. TTiXmlNode* node = Identify( tag->c_str() + tagIndex, TTiXml_DEFAULT_ENCODING ); if ( node ) { node->StreamIn( in, tag ); bool isElement = node->ToElement() != 0; delete node; node = 0; // If this is the root element, we're done. Parsing will be // done by the >> operator. if ( isElement ) { return; } } else { SetError( TTiXml_ERROR, 0, 0, TTiXml_ENCODING_UNKNOWN ); return; } } } // We should have returned sooner. SetError( TTiXml_ERROR, 0, 0, TTiXml_ENCODING_UNKNOWN ); }
TTiXmlNode* TTiXmlNode::NextSibling( const char * _value ) { TTiXmlNode* node; for ( node = next; node; node = node->next ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; }
TTiXmlNode* TTiXmlNode::LastChild( const char * _value ) { TTiXmlNode* node; for ( node = lastChild; node; node = node->prev ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; }
TTiXmlNode* TTiXmlNode::FirstChild( const char * _value ) { TTiXmlNode* node; for ( node = firstChild; node; node = node->next ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; }
TTiXmlNode* TTiXmlNode::PreviousSibling( const char * _value ) { TTiXmlNode* node; for ( node = prev; node; node = node->prev ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; }
TTiXmlDocument* TTiXmlNode::GetDocument() { TTiXmlNode* node; for( node = this; node; node = node->parent ) { if ( node->ToDocument() ) return node->ToDocument(); } return 0; }
TTiXmlElement* TTiXmlNode::NextSiblingElement( const char * _value ) { TTiXmlNode* node; for ( node = NextSibling( _value ); node; node = node->NextSibling( _value ) ) { if ( node->ToElement() ) return node->ToElement(); } return 0; }
TTiXmlElement* TTiXmlNode::NextSiblingElement() { TTiXmlNode* node; for ( node = NextSibling(); node; node = node->NextSibling() ) { if ( node->ToElement() ) return node->ToElement(); } return 0; }
TTiXmlElement* TTiXmlNode::FirstChildElement() { TTiXmlNode* node; for ( node = FirstChild(); node; node = node->NextSibling() ) { if ( node->ToElement() ) return node->ToElement(); } return 0; }
void TTiXmlDocument::CopyTo( TTiXmlDocument* target ) const { TTiXmlNode::CopyTo( target ); target->error = error; target->errorDesc = errorDesc.c_str (); TTiXmlNode* node = 0; for ( node = firstChild; node; node = node->NextSibling() ) { target->LinkEndChild( node->Clone() ); } }
void TTiXmlElement::Print( FILE* cfile, int depth ) const { int i; assert( cfile ); for ( i=0; i<depth; i++ ) { fprintf( cfile, " " ); } fprintf( cfile, "<%s", value.c_str() ); const TTiXmlAttribute* attrib; for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) { fprintf( cfile, " " ); attrib->Print( cfile, depth ); } // There are 3 different formatting approaches: // 1) An element without children is printed as a <foo /> node // 2) An element with only a text child is printed as <foo> text </foo> // 3) An element with children is printed on multiple lines. TTiXmlNode* node; if ( !firstChild ) { fprintf( cfile, " />" ); } else if ( firstChild == lastChild && firstChild->ToText() ) { fprintf( cfile, ">" ); firstChild->Print( cfile, depth + 1 ); fprintf( cfile, "</%s>", value.c_str() ); } else { fprintf( cfile, ">" ); for ( node = firstChild; node; node=node->NextSibling() ) { if ( !node->ToText() ) { fprintf( cfile, "\n" ); } node->Print( cfile, depth+1 ); } fprintf( cfile, "\n" ); for( i=0; i<depth; ++i ) { fprintf( cfile, " " ); } fprintf( cfile, "</%s>", value.c_str() ); } }
void TTiXmlDocument::CopyTo( TTiXmlDocument* target ) const { TTiXmlNode::CopyTo( target ); target->error = error; target->errorId = errorId; target->errorDesc = errorDesc; target->tabsize = tabsize; target->errorLocation = errorLocation; target->useMicrosoftBOM = useMicrosoftBOM; TTiXmlNode* node = 0; for ( node = firstChild; node; node = node->NextSibling() ) { target->LinkEndChild( node->Clone() ); } }
void TTiXmlElement::CopyTo( TTiXmlElement* target ) const { // superclass: TTiXmlNode::CopyTo( target ); // Element class: // Clone the attributes, then clone the children. const TTiXmlAttribute* attribute = 0; for( attribute = attributeSet.First(); attribute; attribute = attribute->Next() ) { target->SetAttribute( attribute->Name(), attribute->Value() ); } TTiXmlNode* node = 0; for ( node = firstChild; node; node = node->NextSibling() ) { target->LinkEndChild( node->Clone() ); } }
const char* TTiXmlDocument::Parse( const char* p, TTiXmlParsingData* prevData, TTiXmlEncoding encoding ) { ClearError(); // Parse away, at the document level. Since a document // contains nothing but other tags, most of what happens // here is skipping white space. if ( !p || !*p ) { SetError( TTiXml_ERROR_DOCUMENT_EMPTY, 0, 0, TTiXml_ENCODING_UNKNOWN ); return 0; } // Note that, for a document, this needs to come // before the while space skip, so that parsing // starts from the pointer we are given. location.Clear(); if ( prevData ) { location.row = prevData->cursor.row; location.col = prevData->cursor.col; } else { location.row = 0; location.col = 0; } TTiXmlParsingData data( p, TabSize(), location.row, location.col ); location = data.Cursor(); if ( encoding == TTiXml_ENCODING_UNKNOWN ) { // Check for the Microsoft UTF-8 lead bytes. const unsigned char* pU = (const unsigned char*)p; if ( *(pU+0) && *(pU+0) == TTiXml_UTF_LEAD_0 && *(pU+1) && *(pU+1) == TTiXml_UTF_LEAD_1 && *(pU+2) && *(pU+2) == TTiXml_UTF_LEAD_2 ) { encoding = TTiXml_ENCODING_UTF8; useMicrosoftBOM = true; } } p = SkipWhiteSpace( p, encoding ); if ( !p ) { SetError( TTiXml_ERROR_DOCUMENT_EMPTY, 0, 0, TTiXml_ENCODING_UNKNOWN ); return 0; } while ( p && *p ) { TTiXmlNode* node = Identify( p, encoding ); if ( node ) { p = node->Parse( p, &data, encoding ); LinkEndChild( node ); } else { break; } // Did we get encoding info? if ( encoding == TTiXml_ENCODING_UNKNOWN && node->ToDeclaration() ) { TTiXmlDeclaration* dec = node->ToDeclaration(); const char* enc = dec->Encoding(); assert( enc ); if ( *enc == 0 ) encoding = TTiXml_ENCODING_UTF8; else if ( StringEqual( enc, "UTF-8", true, TTiXml_ENCODING_UNKNOWN ) ) encoding = TTiXml_ENCODING_UTF8; else if ( StringEqual( enc, "UTF8", true, TTiXml_ENCODING_UNKNOWN ) ) encoding = TTiXml_ENCODING_UTF8; // incorrect, but be nice else encoding = TTiXml_ENCODING_LEGACY; } p = SkipWhiteSpace( p, encoding ); } // Was this empty? if ( !firstChild ) { SetError( TTiXml_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); return 0; } // All is well. return p; }
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; }
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. } } } }