/* * Copyright (C) 2007-2019 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(), "' ) { 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: "); if( nextToken() != tokIdent ) error("A version comes first!"); if( sStr != "version" ) error("No, a version!"); }