text: /*
   * Copyright (C) 2007-2013 Xagasoft, All rights reserved.
   *
   * This file is part of the libbu++ library and is released under the
   * terms of the license contained in the file LICENSE.
   */
  
  #include "bu/xmlreader.h"
  #include "bu/stream.h"
  
  namespace Bu { subExceptionDef( XmlException ) }
  
  Bu::XmlReader::XmlReader( Stream &rInput ) :
      rInput( rInput ),
      iCurToken( 0 ),
      iNextToken( 0 ),
      bIgnoreWS( true )
  {
      nextToken();
      stDocument();
  }
  
  Bu::XmlReader::~XmlReader()
  {
  }
  
  void Bu::XmlReader::fillBuffer()
  {
      if( rInput.isEos() )
          return;
      char buf[1024];
      int iSize = rInput.read( buf, 1024 );
      sBuf.append( buf, iSize );
  }
  
  void Bu::XmlReader::cleanupBuffer( int iUsed )
  {
      for( int j = 0; j < iUsed; j++ )
      {
          if( sBuf[j] == '\n' )
          {
              spNextToken.iLine++;
              spNextToken.iChar = 1;
          }
          else
          {
              spNextToken.iChar++;
          }
      }
  
      printf("--Deleting %d bytes from front of buffer.\n", iUsed );
      sBuf.trimFront( iUsed );
  }
  
  int Bu::XmlReader::nextToken()
  {
      fillBuffer();
  
      int iUsed = 1;
  
      iCurToken = iNextToken;
      spCurToken = spNextToken;
  
      switch( sBuf[0] )
      {
          case '<':
              if( !strncmp( sBuf.getStr(), "<?xml", 5 ) )
              {
                  iNextToken = tokXmlDeclHead;
                  iUsed = 5;
              }
              else
              {
                  iNextToken = '<';
              }
              break;
  
          case '?':
              if( sBuf[1] == '>' )
              {
                  iNextToken = tokXmlDeclEnd;
                  iUsed = 2;
              }
              else
              {
                  iNextToken = '?';
              }
              break;
  
          case ' ':
          case '\t':
          case '\n':
          case '\r':
              for( int j = 1;; j++ )
              {
                  if( j == sBuf.getSize() )
                  {
                      if( rInput.isEos() )
                          error("Reached end of input while waiting for whitespace to end.");
  
                      fillBuffer();
                  }
                  if( sBuf[j] == ' ' || sBuf[j] == '\t' ||
                      sBuf[j] == '\n' || sBuf[j] == '\r' )
                      iUsed++;
                  else
                      break;
              }
              sStr.clear();
              sStr.append( sBuf, iUsed );
              iNextToken = tokWS;
              break;
  
          case '=':
              iNextToken = sBuf[0];
              break;
  
          default:
              if( (sBuf[0] >= 'a' && sBuf[0] <= 'z') ||
                  (sBuf[0] >= 'A' && sBuf[0] <= 'Z') )
              {
                  for( int j = 1;; j++ )
                  {
                      if( j == sBuf.getSize() )
                      {
                          if( rInput.isEos() )
                              error("Reached end of input while waiting for a string to end.");
  
                          fillBuffer();
                      }
                      if( (sBuf[j] >= 'a' && sBuf[j] <= 'z') ||
                          (sBuf[j] >= 'A' && sBuf[j] <= 'Z') )
                          iUsed++;
                      else
                          break;
                  }
                  sStr.clear();
                  sStr.append( sBuf, iUsed );
                  iNextToken = tokIdent;
              }
      }
  
      cleanupBuffer( iUsed );
  
      return iCurToken;
  }
  
  void Bu::XmlReader::error( const char *sMessage )
  {
      throw Bu::XmlException("%d:%d:  %s",
          spCurToken.iLine, spCurToken.iChar, sMessage );
  }
  
  void Bu::XmlReader::stDocument()
  {
      stProlog();
  }
  
  void Bu::XmlReader::stProlog()
  {
      stXmlDecl();
  }
  
  void Bu::XmlReader::stXmlDecl()
  {
      if( nextToken() != tokXmlDeclHead )
          error("You must begin your xml file with a declaration: <?xml ... ?>");
      if( nextToken() != tokIdent )
          error("A version comes first!");
      if( sStr != "version" )
          error("No, a version!");
  }
  
  