• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/xml/TinyXmlDocument.cpp

00001 /* Modified for the SPL project. */
00002 /*
00003 www.sourceforge.net/projects/tinyxml
00004 Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
00005 
00006 This software is provided 'as-is', without any express or implied 
00007 warranty. In no event will the authors be held liable for any 
00008 damages arising from the use of this software.
00009 
00010 Permission is granted to anyone to use this software for any 
00011 purpose, including commercial applications, and to alter it and 
00012 redistribute it freely, subject to the following restrictions:
00013 
00014 1. The origin of this software must not be misrepresented; you must 
00015 not claim that you wrote the original software. If you use this
00016 software in a product, an acknowledgment in the product documentation
00017 would be appreciated but is not required.
00018 
00019 2. Altered source versions must be plainly marked as such, and 
00020 must not be misrepresented as being the original software.
00021 
00022 3. This notice may not be removed or altered from any source 
00023 distribution.
00024 */
00025 #include <spl/text/StringBuffer.h>
00026 #include <spl/io/TextStream.h>
00027 #include <spl/xml/XmlDocument.h>
00028 #include <spl/xml/XmlElement.h>
00029 
00030 int XmlDocument::m_tabsize;
00031 bool XmlDocument::m_condenseWhiteSpace = true;
00032 
00033 XmlDocument::XmlDocument() 
00034 :       XmlNode( XmlNode::DOCUMENT ), 
00035         m_useMicrosoftBOM(false)
00036 {
00037         m_tabsize = 4;
00038         m_useMicrosoftBOM = false;
00039 }
00040 
00041 XmlDocument::XmlDocument( const XmlDocument& copy ) 
00042 :       XmlNode( XmlNode::DOCUMENT ),
00043         m_useMicrosoftBOM(false)
00044 {
00045         copy.CopyTo( *this );
00046 }
00047 
00048 XmlDocument::~XmlDocument() 
00049 {
00050 }
00051 
00052 void XmlDocument::operator=( const XmlDocument& copy )
00053 {
00054         Clear();
00055         copy.CopyTo( *this );
00056 }
00057 
00058 XmlElementPtr XmlDocument::RootElement()
00059 { 
00060         return FirstChildElement(); 
00061 }
00062 
00063 String XmlDocument::Name() const
00064 {
00065         return String("#document");
00066 }
00067 
00069 void XmlDocument::Write( TextWriter& xmlout ) const
00070 {
00071         if ( m_useMicrosoftBOM ) 
00072         {
00073                 const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
00074                 const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
00075                 const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
00076 
00077                 xmlout.Write( (byte)TIXML_UTF_LEAD_0 );
00078                 xmlout.Write( (byte)TIXML_UTF_LEAD_1 );
00079                 xmlout.Write( (byte)TIXML_UTF_LEAD_2 );
00080         }
00081         WriteTo( xmlout );
00082 }
00083 
00085 XmlDocumentPtr XmlDocument::Parse( TextReader& xmlin, XmlParsingData* args, XmlEncoding encoding )
00086 {
00087         if ( !xmlin.CanRead() ) 
00088         {
00089                 throw new XmlException("Stream is not readable", -1, -1);
00090         }
00091 
00092         // Get the file size, so we can pre-allocate the string. HUGE speed impact.
00093         long length = xmlin.Length();
00094 
00095         // Strange case, but good to handle up front.
00096         if ( length <= 0 )
00097         {
00098                 throw new XmlException( "Stream is empty", -1, -1 );
00099         }
00100 
00101         // If we have a file, assume it is all one big XML file, and read it in.
00102         // The document parser may decide the document ends sooner than the entire file, however.
00103         StringBuffer data( length+1 );
00104                 
00105         // Subtle bug here. TinyXml did use fgets. But from the XML spec:
00106         // 2.11 End-of-Line Handling
00107         // <snip>
00108         // <quote>
00109         // ...the XML processor MUST behave as if it normalized all line breaks in external 
00110         // parsed entities (including the document entity) on input, before parsing, by translating 
00111         // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to 
00112         // a single #xA character.
00113         // </quote>
00114         //
00115         // It is not clear fgets does that, and certainly isn't clear it works cross platform. 
00116         // Generally, you expect fgets to translate from the convention of the OS to the c/unix
00117         // convention, and not work generally.
00118 
00119         /*
00120         while( fgets( buf, sizeof(buf), file ) )
00121         {
00122                 data += buf;
00123         }
00124         */
00125 
00126         const int buflen = 256;
00127         Array<byte> buf(buflen);
00128         int readlen;
00129         
00130         while ( (readlen = xmlin.ReadBlock(buf, 0, buflen)) > 0 )
00131         {
00132                 int crpos = spl::IndexofchfromWithLen((const char *)buf.Data(), 0xD, 0, readlen);
00133                 if ( crpos < 0 )
00134                 {
00135                         data.Append(buf, readlen);
00136                         continue;
00137                 }
00138                 for ( int x = 0; x < readlen; x++ )
00139                 {
00140                         char ch = buf[x];
00141                         if ( ch != 0xD )
00142                         {
00143                                 data.Append(ch);
00144                         }
00145                         else if ( x < readlen )
00146                         {
00147                                 if ( x == readlen-1 || buf[x+1] != 0xA )
00148                                 {
00149                                         data.Append((char)0xA);
00150                                 }
00151                         }
00152                 }
00153         }
00154 
00155         XmlDocumentPtr doc(new XmlDocument());
00156         XmlNodePtr xdoc = (XmlNodePtr)doc;
00157         doc->m_self = xdoc;
00158 
00159         doc->_Parse( data.GetChars(), args, encoding );
00160         
00161         return doc;
00162 }
00163 
00164 void XmlDocument::CopyTo( XmlDocument& target ) const
00165 {
00166         XmlNode::CopyTo( target );
00167 
00168         target.m_tabsize = m_tabsize;
00169         target.m_useMicrosoftBOM = m_useMicrosoftBOM;
00170 
00171         if (m_firstChild.IsNotNull())
00172         {
00173                 XmlNodePtr node;
00174                 for ( node = m_firstChild; node.IsNotNull(); node = node->NextSibling() )
00175                 {
00176                         node.ValidateMem();
00177                         target.AppendChild( node->Clone() );
00178                 }
00179         }
00180 }
00181 
00182 XmlNodePtr XmlDocument::Clone() const
00183 {
00184         XmlDocumentPtr clone = XmlDocumentPtr(new XmlDocument());
00185         XmlNodePtr xclone = (XmlNodePtr)clone;
00186         clone->m_self = xclone;
00187         CopyTo( *clone );
00188         return clone;
00189 }
00190 
00191 void XmlDocument::WriteTo( TextWriter& writer ) const
00192 {
00193         for ( XmlNodePtr node = FirstChild(); node.IsNotNull(); node = node->NextSibling() )
00194         {
00195                 node->WriteTo( writer );
00196         }
00197 }
00198 
00199 StringPtr XmlDocument::InnerXml() const
00200 {
00201         return ToString();
00202 }
00203 
00204 StringPtr XmlDocument::ToString() const
00205 {
00206         MemoryStreamPtr ms(new MemoryStream());
00207         TextWriter writer(ms);
00208         WriteTo(writer);
00209         return ms->ToString();          
00210 }
00211 
00212 XmlDocumentPtr  XmlDocument::ToDocument()    const
00213 {
00214         return (XmlNodePtr)m_self;
00215 }
00216 
00217 #ifdef DEBUG
00218 void XmlDocument::ValidateMem() const
00219 {
00220         XmlNode::ValidateMem();
00221 }
00222 
00223 void XmlDocument::CheckMem() const
00224 {
00225         XmlNode::CheckMem();
00226 }
00227 #endif