/* Copyright (C) 2000-2004 Code contributed by Greg Collecutt, Joseph Hope and Paul Cochrane This file is part of xmds. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* $Id: xmlparser.cc,v 1.11 2004/07/27 07:33:54 paultcochrane Exp $ */ /*! @file xmlparser.cc @brief XML parser classes and methods More detailed explanation... */ #include #include #include #include #define DEBUGXMLPARSER 0 //!< Whether or not to debug the XML parser #define DEBUGXMLENTITYSTREAMS 0 //!< Whether or not to debug the entity streams // ****************************************************************************** // ****************************************************************************** // XMLParserException // ****************************************************************************** // ****************************************************************************** long nXMLParserExceptions=0; //!< The number of XML parser exceptions // ****************************************************************************** XMLParserException::XMLParserException() : theError(UNKNOWN_ERR), theXMLEntityStreamStack(0), theErrorMessage("") { if(DEBUGXMLPARSER) { nXMLParserExceptions++; printf("XMLParserException::XMLParserException\n"); printf("nXMLParserExceptions=%li\n",nXMLParserExceptions); } }; // ****************************************************************************** XMLParserException::XMLParserException( const list *const yourXMLEntityStreamStack, const char *const yourErrorMessage, const unsigned short& yourError) : theError(yourError), theXMLEntityStreamStack(yourXMLEntityStreamStack), theErrorMessage(yourErrorMessage) { if(DEBUGXMLPARSER) { nXMLParserExceptions++; printf("XMLParserException::XMLParserException\n"); printf("nXMLParserExceptions=%li\n",nXMLParserExceptions); } }; // ****************************************************************************** XMLParserException::~XMLParserException() { if(DEBUGXMLPARSER) { nXMLParserExceptions--; printf("XMLParserException::~XMLParserException\n"); printf("nXMLParserExceptions=%li\n",nXMLParserExceptions); } }; // ****************************************************************************** const char* XMLParserException::getError() { const char* errorName; switch(theError) { case BAD_XML_ERR: errorName="XMLParserException::BAD_XML_ERR\n"; break; case ENCODING_NOT_SUPPORTED_ERR: errorName="XMLParserException::ENCODING_NOT_SUPPORTED_ERR\n"; break; case INVALID_FILE_ERR : errorName="XMLParserException::INVALID_FILE_ERR\n"; break; case INTERNAL_ERR: errorName="XMLParserException::INTERNAL_ERR\n"; break; default : errorName="XMLParserException::UNKNOWN_ERR\n"; } if(theXMLEntityStreamStack != 0) { s[0]=0; if(theXMLEntityStreamStack->size()==0) { return errorName; } char s2[256]; list::const_iterator ppXMLEntityStream = theXMLEntityStreamStack->begin(); sprintf(s2,"%sIn stream '%s', line %li, column %li,",errorName, (*ppXMLEntityStream)->name()->c_str(), (*ppXMLEntityStream)->streamPos.lineNumber, (*ppXMLEntityStream)->streamPos.columnNumber); strcat(s,s2); ppXMLEntityStream++; while(ppXMLEntityStream!=theXMLEntityStreamStack->end()) { sprintf(s2,"\n which was referenced from stream '%s', line %li, column %li,", (*ppXMLEntityStream)->name()->c_str(), (*ppXMLEntityStream)->streamPos.lineNumber, (*ppXMLEntityStream)->streamPos.columnNumber); strcat(s,s2); ppXMLEntityStream++; } sprintf(s2,"\nthe following error occurred:\n %s\n",theErrorMessage); strcat(s,s2); return s; } else return errorName; }; // ****************************************************************************** // ****************************************************************************** // XMLEntityStream // ****************************************************************************** // ****************************************************************************** long nXMLEntityStreams=0; //!< The number of XML entity streams // ****************************************************************************** XMLEntityStream::XMLEntityStream( XMLParser *const yourXMLParser, XMLEntityStream *const yourParentXMLEntityStream, const XMLString& yourName, const XMLString& yourSystemID): myXMLParser(yourXMLParser), myName(yourName), myParentXMLEntityStream(yourParentXMLEntityStream), mySystemID(yourSystemID) { if(DEBUGXMLENTITYSTREAMS) { nXMLEntityStreams++; printf("%s,XMLEntityStream::XMLEntityStream\n",myName.c_str()); printf(" nXMLEntityStreams=%li\n",nXMLEntityStreams); } streamPos.count=0; streamPos.lineNumber=1; streamPos.columnNumber=1; errormessage[0]=0; myTextStringValid=0; }; // ****************************************************************************** XMLEntityStream::~XMLEntityStream() { if(DEBUGXMLENTITYSTREAMS) { nXMLEntityStreams--; printf("%s,XMLEntityStream::~XMLEntityStream\n",myName.c_str()); printf(" nXMLEntityStreams=%li\n",nXMLEntityStreams); } list::iterator ppXMLEntityStream = myXMLEntityStreamList.begin(); while(ppXMLEntityStream != myXMLEntityStreamList.end()) { delete *ppXMLEntityStream; ppXMLEntityStream++; } }; // ****************************************************************************** const XMLString* XMLEntityStream::name() const { if(DEBUGXMLENTITYSTREAMS) { printf("%s,XMLEntityStream::name\n",myName.c_str()); } return &myName; }; // ****************************************************************************** XMLEntityStream* XMLEntityStream::parentXMLEntityStream() { if(DEBUGXMLENTITYSTREAMS) { printf("%s,XMLEntityStream::parentXMLEntityStream\n",myName.c_str()); } return myParentXMLEntityStream; }; // ****************************************************************************** bool XMLEntityStream::atEnd() const { if(DEBUGXMLENTITYSTREAMS) { printf("%s,XMLEntityStream::atEnd\n",myName.c_str()); } return streamPos.count >= myTextString.length(); }; // ****************************************************************************** //char XMLEntityStream::nextChar() { signed char XMLEntityStream::nextChar() { if(!myTextStringValid) { makeTextString(); } if(streamPos.count>=myTextString.length()) { return EOF; } else { char c=myTextString.data(streamPos.count); streamPos.columnNumber++; if(c==0x0A) { streamPos.lineNumber++; streamPos.columnNumber=1; } streamPos.count++; if(DEBUGXMLENTITYSTREAMS) { printf("%s:%li,%c\n",myName.c_str(),streamPos.count,c); } return c; } }; // ****************************************************************************** XMLEntityStream* XMLEntityStream::addParameterXMLEntityStream( const XMLString& name, const XMLString& PublicID, const XMLString& SystemID) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,XMLEntityStream::addParameterXMLEntityStream\n",myName.c_str()); } XMLEntityStream* newXMLEntityStream = new ParameterXMLEntityStream(myXMLParser,this,name,PublicID,SystemID); myXMLEntityStreamList.push_front(newXMLEntityStream); return newXMLEntityStream; }; // ****************************************************************************** XMLEntityStream* XMLEntityStream::addParameterXMLEntityStream( const XMLString& name, const XMLString& EntityLiteral) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,XMLEntityStream::addParameterXMLEntityStream\n",myName.c_str()); } XMLEntityStream* newXMLEntityStream = new ParameterXMLEntityStream(myXMLParser,this,name,EntityLiteral); myXMLEntityStreamList.push_front(newXMLEntityStream); return newXMLEntityStream; }; // ****************************************************************************** XMLEntityStream* XMLEntityStream::addGeneralXMLEntityStream( const XMLString& name, const XMLString& PublicID, const XMLString& SystemID) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,XMLEntityStream::addGeneralXMLEntityStream\n",myName.c_str()); } XMLEntityStream* newXMLEntityStream = new GeneralXMLEntityStream(myXMLParser,this,name,PublicID,SystemID); myXMLEntityStreamList.push_front(newXMLEntityStream); return newXMLEntityStream; }; // ****************************************************************************** XMLEntityStream* XMLEntityStream::addGeneralXMLEntityStream( const XMLString& name, const XMLString& EntityLieteral) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,XMLEntityStrea m::addGeneralXMLEntityStream\n",myName.c_str()); } XMLEntityStream* newXMLEntityStream = new GeneralXMLEntityStream(myXMLParser,this,name,EntityLieteral); myXMLEntityStreamList.push_front(newXMLEntityStream); return newXMLEntityStream; }; // ****************************************************************************** XMLEntityStream* XMLEntityStream::addUnparsedXMLEntityStream( const XMLString& name, const XMLString& PublicID, const XMLString& SystemID, const XMLString& NotationName) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,XMLEntityStream::addUnparsedXMLEntityStream\n",myName.c_str()); } XMLEntityStream* newXMLEntityStream = new UnparsedXMLEntityStream(myXMLParser,this,name,PublicID,SystemID,NotationName); myXMLEntityStreamList.push_front(newXMLEntityStream); return newXMLEntityStream; }; // ****************************************************************************** XMLEntityStream* XMLEntityStream::getXMLEntityStream( const XMLString& getName, const XMLEntityStreamType& ofEntityType) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,XMLEntityStream::getXMLEntityStream\n",myName.c_str()); } XMLEntityStream* testXMLEntityStream; XMLEntityStream* nextXMLEntityStream; list::const_iterator ppXMLEntityStream; // first try locally testXMLEntityStream=0; ppXMLEntityStream = myXMLEntityStreamList.begin(); while((testXMLEntityStream==0)&(ppXMLEntityStream != myXMLEntityStreamList.end())) { if ((*(*ppXMLEntityStream)->name()==getName)&( (*ppXMLEntityStream)->entityType()==ofEntityType)) { testXMLEntityStream = *ppXMLEntityStream; } ppXMLEntityStream++; } if(testXMLEntityStream==0) { // now try the more general search tree downwards routine starting with // the immediate parent and working our way up the ancestral line each time // it fails, until it gets to Adam. if(myParentXMLEntityStream==0) { // I am the root element. Go straight to getXMLEntityStreamTreeWalkDown testXMLEntityStream = getXMLEntityStreamTreeWalkDown(getName,ofEntityType); } else { nextXMLEntityStream=myParentXMLEntityStream; while((testXMLEntityStream==0)&(nextXMLEntityStream!=0)) { testXMLEntityStream = nextXMLEntityStream->getXMLEntityStreamTreeWalkDown(getName,ofEntityType); nextXMLEntityStream = nextXMLEntityStream->parentXMLEntityStream(); } } } if(testXMLEntityStream!=0) { for(list::const_iterator ppXMLEntityStream = myXMLParser->XMLEntityStreamStack.begin() ; ppXMLEntityStream != myXMLParser->XMLEntityStreamStack.end(); ppXMLEntityStream++) { if(testXMLEntityStream==*ppXMLEntityStream) { sprintf(errormessage,"Circular reference to parameter entity '%s'",getName.c_str()); throw XMLParserException(&myXMLParser->XMLEntityStreamStack,errormessage, XMLParserException::BAD_XML_ERR); } } testXMLEntityStream->streamPos.count=0; testXMLEntityStream->streamPos.columnNumber=1; testXMLEntityStream->streamPos.lineNumber=1; } return testXMLEntityStream; }; // ****************************************************************************** void XMLEntityStream::printStreamTree( unsigned long level) const { for(unsigned long i=0;i::const_iterator ppXMLEntityStream = myXMLEntityStreamList.begin(); while(ppXMLEntityStream != myXMLEntityStreamList.end()) { (*ppXMLEntityStream)->printStreamTree(level+1); ppXMLEntityStream++; } }; // ****************************************************************************** XMLEntityStream* XMLEntityStream::getXMLEntityStreamTreeWalkDown( const XMLString& name, const XMLEntityStreamType& ofEntityType) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,XMLEntityStream::getXMLEntityStreamTreeWalkDown\n",myName.c_str()); } if((myName==name)&(entityType()==ofEntityType)) { return this; } XMLEntityStream* testXMLEntityStream=0; list::const_iterator ppXMLEntityStream = myXMLEntityStreamList.begin(); while((testXMLEntityStream==0)&(ppXMLEntityStream != myXMLEntityStreamList.end())) { testXMLEntityStream = (*ppXMLEntityStream)->getXMLEntityStreamTreeWalkDown(name,ofEntityType); ppXMLEntityStream++; } return testXMLEntityStream; }; // ****************************************************************************** void XMLEntityStream::loadExternalTextString() { if(DEBUGXMLENTITYSTREAMS) { printf("%s,XMLEntityStream::loadExternalTextString\n",myName.c_str()); } // check that file exists FILE *infile = fopen(mySystemID.c_str(),"r"); if(infile==0) { sprintf(errormessage,"Cannot open '%s' for reading",mySystemID.c_str()); throw XMLParserException(&myXMLParser->XMLEntityStreamStack, errormessage,XMLParserException::INVALID_FILE_ERR); } // load file into myTextString; myTextString.loadFromFile(infile); fclose(infile); }; // ****************************************************************************** // ****************************************************************************** // RootXMLEntityStream // ****************************************************************************** // ****************************************************************************** // ****************************************************************************** RootXMLEntityStream::RootXMLEntityStream( XMLParser *const yourXMLParser, const XMLString& yourSystemID): XMLEntityStream(yourXMLParser,0,"document_entity",yourSystemID) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,RootXMLEntityStream::RootXMLEntityStream\n",myName.c_str()); } }; // ****************************************************************************** XMLEntityStream::XMLEntityStreamType RootXMLEntityStream::entityType() const { if(DEBUGXMLENTITYSTREAMS) { printf("%s,RootXMLEntityStream::entityType\n",myName.c_str()); } return ROOT_ENTITY; }; // ****************************************************************************** XMLEntityStream::XMLEntityLocationType RootXMLEntityStream::entityLocation() const { if(DEBUGXMLENTITYSTREAMS) { printf("%s,RootXMLEntityStream::entityLocation\n",myName.c_str()); } return INTERNAL_ENTITY; }; // ****************************************************************************** const XMLString* RootXMLEntityStream::replacementText() { throw XMLParserException(&myXMLParser->XMLEntityStreamStack, "RootXMLEntityStream::replacementText() called!", XMLParserException::INTERNAL_ERR); }; // ****************************************************************************** void RootXMLEntityStream::makeTextString() { if(DEBUGXMLENTITYSTREAMS) { printf("%s,RootXMLEntityStream::makeTextString\n",myName.c_str()); } loadExternalTextString(); myTextStringValid=1; }; // ****************************************************************************** // ****************************************************************************** // GPXMLEntityStream // ****************************************************************************** // ****************************************************************************** // ****************************************************************************** // constructor for an internal entity GPXMLEntityStream::GPXMLEntityStream( XMLParser *const yourXMLParser, XMLEntityStream *const yourParentXMLEntityStream, const XMLString& yourName, const XMLString& yourEntityLiteral): XMLEntityStream(yourXMLParser,yourParentXMLEntityStream,yourName,""), myPublicID(""), myEntityLiteral(yourEntityLiteral), myEntityLocation(INTERNAL_ENTITY) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,GPXMLEntityStream::GPXMLEntityStream - internal\n",myName.c_str()); } }; // ****************************************************************************** // constructor for an external entity GPXMLEntityStream::GPXMLEntityStream( XMLParser *const yourXMLParser, XMLEntityStream *const yourParentXMLEntityStream, const XMLString& yourName, const XMLString& yourPublicID, const XMLString& yourSystemID): XMLEntityStream(yourXMLParser,yourParentXMLEntityStream,yourName,yourSystemID), myPublicID(yourPublicID), myEntityLiteral(""), myEntityLocation(EXTERNAL_ENTITY) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,GPXMLEntityStream::GPXMLEntityStream - external\n",myName.c_str()); } }; // ****************************************************************************** XMLEntityStream::XMLEntityLocationType GPXMLEntityStream::entityLocation() const { if(DEBUGXMLENTITYSTREAMS) { printf("%s,GPXMLEntityStream::entityLocation\n",myName.c_str()); } return myEntityLocation; }; // ****************************************************************************** const XMLString* GPXMLEntityStream::replacementText() { if(DEBUGXMLENTITYSTREAMS) { printf("%s,GPXMLEntityStream::replacementText\n",myName.c_str()); } if(!myTextStringValid) { makeTextString(); } return &myTextString; }; // ****************************************************************************** void GPXMLEntityStream::makeTextString() { if(DEBUGXMLENTITYSTREAMS) { printf("%s,GPXMLEntityStream::makeTextString\n",myName.c_str()); } myTextStringValid=1; if(myEntityLocation==EXTERNAL_ENTITY) { loadExternalTextString(); // parse for TextDecl XMLString VersionNum; XMLString EncName; myXMLParser->matchProduction77TextDecl(this,VersionNum,EncName); // now remove TextDecl from myTextString myTextString.replaceData(0,streamPos.count,""); streamPos.count=0; return; } // if here, we must be an internal entity, in which case we ought to // be preparsed for character and parameter entity refs myTextString=myEntityLiteral; //char c; signed char c; unsigned long refLength; XMLString refName; XMLEntityStream* refXMLEntityStream; StreamPositionStruct lastPos; lastPos=streamPos; c=nextChar(); while(c!=EOF) { if(c=='&') { streamPos=lastPos; refLength=myXMLParser->matchProduction66CharRef(this,c); streamPos=lastPos; if(refLength>0) { const char s[2]={c,0}; myTextString.replaceData(streamPos.count,refLength,s); streamPos.columnNumber += refLength; streamPos.count++; } lastPos=streamPos; c=nextChar(); } if(c=='%') { // might be the % in an declaration // therefore check next character, and proceed only if not a WhiteSpace c=nextChar(); if(!XMLChar::isWhiteSpace(c)) { streamPos=lastPos; refLength=myXMLParser->matchProduction69PEReference(this,refName); streamPos=lastPos; refXMLEntityStream = getXMLEntityStream(refName,XMLEntityStream::PARAMETER_ENTITY); if(refXMLEntityStream==0) { sprintf(errormessage,"Parameter entity '%s' unknown",refName.c_str()); throw XMLParserException(&myXMLParser->XMLEntityStreamStack,errormessage,XMLParserException::BAD_XML_ERR); } myXMLParser->XMLEntityStreamStack.push_front(refXMLEntityStream); myTextString.replaceData(streamPos.count,refLength, *refXMLEntityStream->replacementText()); myXMLParser->XMLEntityStreamStack.pop_front(); } } lastPos=streamPos; c=nextChar(); } streamPos.count=0; streamPos.lineNumber=1; streamPos.columnNumber=1; if(DEBUGXMLENTITYSTREAMS) { printf("myTextString=%s\n",myTextString.c_str()); } }; // ****************************************************************************** // ****************************************************************************** // ParameterXMLEntityStream // ****************************************************************************** // ****************************************************************************** // ****************************************************************************** // constructor for an internal entity ParameterXMLEntityStream::ParameterXMLEntityStream( XMLParser *const yourXMLParser, XMLEntityStream *const yourParentXMLEntityStream, const XMLString& yourName, const XMLString& yourEntityLiteral): GPXMLEntityStream(yourXMLParser,yourParentXMLEntityStream,yourName,yourEntityLiteral) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,ParameterXMLEntityStream::ParameterXMLEntityStream - internal\n",myName.c_str()); } }; // ****************************************************************************** // constructor for an external entity ParameterXMLEntityStream::ParameterXMLEntityStream( XMLParser *const yourXMLParser, XMLEntityStream *const yourParentXMLEntityStream, const XMLString& yourName, const XMLString& yourPublicID, const XMLString& yourSystemID): GPXMLEntityStream(yourXMLParser,yourParentXMLEntityStream,yourName,yourPublicID,yourSystemID) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,ParameterXMLEntityStream::ParameterXMLEntityStream - external\n",myName.c_str()); } }; // ****************************************************************************** XMLEntityStream::XMLEntityStreamType ParameterXMLEntityStream::entityType() const { if(DEBUGXMLENTITYSTREAMS) { printf("%s,ParameterXMLEntityStream::entityType\n",myName.c_str()); } return PARAMETER_ENTITY; }; // ****************************************************************************** // ****************************************************************************** // GeneralXMLEntityStream // ****************************************************************************** // ****************************************************************************** // ****************************************************************************** // constructor for an internal entity GeneralXMLEntityStream::GeneralXMLEntityStream( XMLParser *const yourXMLParser, XMLEntityStream *const yourParentXMLEntityStream, const XMLString& yourName, const XMLString& yourEntityLiteral): GPXMLEntityStream(yourXMLParser,yourParentXMLEntityStream,yourName,yourEntityLiteral) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,GeneralXMLEntityStream::GeneralXMLEntityStream - internal\n",myName.c_str()); } }; // ****************************************************************************** // constructor for an external entity GeneralXMLEntityStream::GeneralXMLEntityStream( XMLParser *const yourXMLParser, XMLEntityStream *const yourParentXMLEntityStream, const XMLString& yourName, const XMLString& yourPublicID, const XMLString& yourSystemID): GPXMLEntityStream(yourXMLParser,yourParentXMLEntityStream,yourName,yourPublicID,yourSystemID) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,GeneralXMLEntityStream::GeneralXMLEntityStream - external\n",myName.c_str()); } }; // ****************************************************************************** XMLEntityStream::XMLEntityStreamType GeneralXMLEntityStream::entityType() const { if(DEBUGXMLENTITYSTREAMS) { printf("%s,GeneralXMLEntityStream::entityType\n",myName.c_str()); } return GENERAL_ENTITY; }; // ****************************************************************************** // ****************************************************************************** // UnparsedXMLEntityStream // ****************************************************************************** // ****************************************************************************** // ****************************************************************************** UnparsedXMLEntityStream::UnparsedXMLEntityStream( XMLParser *const yourXMLParser, XMLEntityStream *const yourParentXMLEntityStream, const XMLString& yourName, const XMLString& yourPublicID, const XMLString& yourSystemID, const XMLString& yourNotationName): XMLEntityStream(yourXMLParser,yourParentXMLEntityStream,yourName,yourSystemID), myPublicID(yourPublicID), myNotationName(yourNotationName) { if(DEBUGXMLENTITYSTREAMS) { printf("%s,UnparsedXMLEntityStream::UnparsedXMLEntityStream\n",myName.c_str()); } }; // ****************************************************************************** XMLEntityStream::XMLEntityStreamType UnparsedXMLEntityStream::entityType() const { if(DEBUGXMLENTITYSTREAMS) { printf("%s,UnparsedXMLEntityStream::entityType\n",myName.c_str()); } return UNPARSED_ENTITY; }; // ****************************************************************************** XMLEntityStream::XMLEntityLocationType UnparsedXMLEntityStream::entityLocation() const { if(DEBUGXMLENTITYSTREAMS) { printf("%s,UnparsedXMLEntityStream::entityLocation\n",myName.c_str()); } return EXTERNAL_ENTITY; }; // ****************************************************************************** const XMLString* UnparsedXMLEntityStream::replacementText() { throw XMLParserException(&myXMLParser->XMLEntityStreamStack,"UnparsedXMLEntityStream::replacementText() called!", XMLParserException::INTERNAL_ERR); }; // ****************************************************************************** bool UnparsedXMLEntityStream::atEnd() const { return 1; }; // ****************************************************************************** XMLEntityStream* UnparsedXMLEntityStream::addParameterXMLEntityStream( const XMLString& name, const XMLString& PublicID, const XMLString& SystemID) { throw XMLParserException(&myXMLParser->XMLEntityStreamStack,"UnparsedXMLEntityStream::addParameterXMLEntityStream() called!", XMLParserException::INTERNAL_ERR); }; // ****************************************************************************** XMLEntityStream* UnparsedXMLEntityStream::addParameterXMLEntityStream( const XMLString& name, const XMLString& EntityLiteral) { throw XMLParserException(&myXMLParser->XMLEntityStreamStack,"UnparsedXMLEntityStream::addParameterXMLEntityStream() called!", XMLParserException::INTERNAL_ERR); }; // ****************************************************************************** XMLEntityStream* UnparsedXMLEntityStream::addGeneralXMLEntityStream( const XMLString& name, const XMLString& EntityLiteral) { throw XMLParserException(&myXMLParser->XMLEntityStreamStack,"UnparsedXMLEntityStream::addGeneralXMLEntityStream() called!", XMLParserException::INTERNAL_ERR); }; // ****************************************************************************** XMLEntityStream* UnparsedXMLEntityStream::addGeneralXMLEntityStream( const XMLString& name, const XMLString& PublicID, const XMLString& SystemID, const XMLString& NotationName) { throw XMLParserException(&myXMLParser->XMLEntityStreamStack,"UnparsedXMLEntityStream::addGeneralXMLEntityStream() called!", XMLParserException::INTERNAL_ERR); }; // ****************************************************************************** XMLEntityStream* UnparsedXMLEntityStream::addUnparsedXMLEntityStream( const XMLString& name, const XMLString& PublicID, const XMLString& SystemID, const XMLString& NotationName) { throw XMLParserException(&myXMLParser->XMLEntityStreamStack,"UnparsedXMLEntityStream::addUnparsedXMLEntityStream() called!", XMLParserException::INTERNAL_ERR); }; // ****************************************************************************** XMLEntityStream* UnparsedXMLEntityStream::getXMLEntityStream( const XMLString& getName, const XMLEntityStreamType& ofEntityType) { throw XMLParserException(&myXMLParser->XMLEntityStreamStack,"UnparsedXMLEntityStream::getXMLEntityStream() called!", XMLParserException::INTERNAL_ERR); }; // ****************************************************************************** void UnparsedXMLEntityStream::makeTextString() { throw XMLParserException(&myXMLParser->XMLEntityStreamStack,"UnparsedXMLEntityStream::makeTextString() called!", XMLParserException::INTERNAL_ERR); }; // ****************************************************************************** // ****************************************************************************** // XMLParser // ****************************************************************************** // ****************************************************************************** // ****************************************************************************** XMLParser::XMLParser() { if(DEBUGXMLPARSER) { printf("XMLParser::XMLParser()\n"); } myxmdsBytePoint=0; }; // ****************************************************************************** XMLParser::~XMLParser() { if(DEBUGXMLPARSER) { printf("XMLParser::~XMLParser()\n"); } if(rootXMLEntityStream != 0) { delete rootXMLEntityStream; } if(DEBUGXMLPARSER) { printf(" ...XMLParser deleted\n"); } }; // ****************************************************************************** Document* XMLParser::parseFromFile( const char* fileName) { if(DEBUGXMLPARSER) { printf("XMLParser::parseFromFile\n"); } XMLEntityStreamStack.clear(); rootXMLEntityStream = new RootXMLEntityStream(this,fileName); XMLEntityStreamStack.push_front(rootXMLEntityStream); // add default expansions for the general entities // < > & ' and " rootXMLEntityStream->addGeneralXMLEntityStream("lt","&#60;"); rootXMLEntityStream->addGeneralXMLEntityStream("gt","&#62;"); rootXMLEntityStream->addGeneralXMLEntityStream("amp","&#38;"); rootXMLEntityStream->addGeneralXMLEntityStream("apos","&#39;"); rootXMLEntityStream->addGeneralXMLEntityStream("quot","&#34;"); (*XMLEntityStreamStack.begin())=rootXMLEntityStream; theDocumentType=0; theDocument=0; rootVersionNum="1.0"; rootEncName=""; StandAlone=0; try { matchProduction01Document(); } catch (XMLException XMLErr) { printf("Could not load Document\n"); printf("due to the following XMLException:\n"); printf("%s",XMLErr.getError()); } catch (DOMException DOMErr) { printf("Could not load Document\n"); printf("due to the following DOMException:\n"); printf("%s",DOMErr.getError()); } if(DEBUGXMLPARSER) { myDOMImplementation.printAll(); } return(theDocument); }; // ****************************************************************************** unsigned long XMLParser::xmdsBytePoint() const { if(DEBUGXMLPARSER) { printf("XMLParser::xmdsBytePoint\n"); } return myxmdsBytePoint; } /* The folowwing routines are designed to parse the productions laid out in XML 1.0 (second edition). These productions fall into three categories: 1. Required. An error at any stage of parsing a required production will generate the XMLParserException BAD_XML_ERR. These routines are declared with the return type void. 2. Optional. An error at the early stages of parsing will not be reported and the routine will back out and return 0. If the parsing passes a 'critical point' (the point at which the intended production is uniquely specified) the routine will generate the XMLParserException BAD_XML_ERR so that the user may know where they are going wrong. These routines are declared as type bool so that the calling routine knows whether or not the attempted parse was successful. 3. Either of the above, in which case the routine is passed a bool parameter 'required' so that it knows which behaviour is expected. The definition of where the 'critical point' should go is not easy, as many productons are comprised of ORed subproductions, and yet it would be nice to be able to feed reasonable error messages to the user if they have made a reconisable attempt at a particular production. Therefore many productions test for their subproductions in a particular order, with the last one to be tested having a very early critical point, and yeilding error messages that encompass all the other subproductions. */ // ****************************************************************************** void XMLParser::matchProduction01Document() { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction01Document\n"); } matchProduction22Prolog(); if(!matchProduction39Element(0)) { // no root element throw XMLParserException(&XMLEntityStreamStack, "Root element expected.",XMLParserException::BAD_XML_ERR); } while(matchProduction27Misc(0)); // what is this supposed to do?? PTC //char c = (*XMLEntityStreamStack.begin())->nextChar(); signed char c = (*XMLEntityStreamStack.begin())->nextChar(); if(c!=EOF) { // what is this extra stuff? throw XMLParserException(&XMLEntityStreamStack, "End of file expected.",XMLParserException::BAD_XML_ERR); } }; // ****************************************************************************** long XMLParser::matchProduction03S( XMLEntityStream *const thisStream, const bool required) const { // this production is sometimes required and sometimes optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction03S\n"); } StreamPositionStruct lastStreamPos = thisStream->streamPos; long length=0; //char c=thisStream->nextChar(); signed char c=thisStream->nextChar(); while(XMLChar::isWhiteSpace(c)&(c!=EOF)) { lastStreamPos = thisStream->streamPos; length++; c=thisStream->nextChar(); } if(!XMLChar::isWhiteSpace(c)) { thisStream->streamPos = lastStreamPos; } if((length==0)&required) { throw XMLParserException(&XMLEntityStreamStack, "White space expected.",XMLParserException::BAD_XML_ERR); } return length; }; // ****************************************************************************** long XMLParser::matchProduction03SDeep( const bool required) { // this production is like the normal whitespace production, // except that it also descends and climbs PE streams, since // allowable white space forms logical boundaries between atoms of a DTD if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction03SDeep\n"); } if(XMLEntityStreamStack.size()==1) { return matchProduction03S((*XMLEntityStreamStack.begin()),required); } StreamPositionStruct lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; XMLEntityStream* nextXMLEntityStream; long length=0; //char c=(*XMLEntityStreamStack.begin())->nextChar(); signed char c=(*XMLEntityStreamStack.begin())->nextChar(); while(XMLChar::isWhiteSpace(c)|(c=='%')|(c==EOF)) { if(c==EOF) { if(XMLEntityStreamStack.size()==1) { throw XMLParserException(&XMLEntityStreamStack,"Unexpected end of file", XMLParserException::BAD_XML_ERR); } XMLEntityStreamStack.pop_front(); } else if(c=='%') { // might yet be the % in an declaration // therefore check next character, and proceed only if not a WhiteSpace c=(*XMLEntityStreamStack.begin())->nextChar(); if(!XMLChar::isWhiteSpace(c)) { (*XMLEntityStreamStack.begin())->streamPos.count -= 2; (*XMLEntityStreamStack.begin())->streamPos.columnNumber -= 2; XMLString refName; StreamPositionStruct lastStreamPos2 = (*XMLEntityStreamStack.begin())->streamPos; matchProduction69PEReference((*XMLEntityStreamStack.begin()),refName); nextXMLEntityStream = (*XMLEntityStreamStack.begin())->getXMLEntityStream(refName,XMLEntityStream::PARAMETER_ENTITY); if(nextXMLEntityStream==0) { (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos2; sprintf(errormessage,"Parameter entity '%s' unknown",refName.c_str()); throw XMLParserException(&XMLEntityStreamStack,errormessage,XMLParserException::BAD_XML_ERR); } XMLEntityStreamStack.push_front(nextXMLEntityStream); } else { (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; if((length==0)&required) { throw XMLParserException(&XMLEntityStreamStack,"White space expected",XMLParserException::BAD_XML_ERR); } return length; } } length++; lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; c=(*XMLEntityStreamStack.begin())->nextChar(); } (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; if((length==0)&required) { throw XMLParserException(&XMLEntityStreamStack,"White space expected",XMLParserException::BAD_XML_ERR); } return length; }; // ****************************************************************************** bool XMLParser::matchProduction05Name( XMLEntityStream *const thisStream, XMLString& Name) const { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction05Name\n"); } if(!matchProduction07Nmtoken(thisStream,Name)) { return 0; } // critical point // and check that it is a valid name if(!Name.isName()) { thisStream->streamPos.columnNumber -= Name.length(); throw XMLParserException(&XMLEntityStreamStack,"Not a valid Name",XMLParserException::BAD_XML_ERR); } if(DEBUGXMLPARSER) { printf("Name = '%s'\n",Name.c_str()); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction07Nmtoken( XMLEntityStream *const thisStream, XMLString& Nmtoken) const { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction07Nmtoken\n"); } StreamPositionStruct lastStreamPos = thisStream->streamPos; // first of all need to determine length of NMToken unsigned long length=0; //char c=thisStream->nextChar(); signed char c=thisStream->nextChar(); if(c==EOF) { return 0; } while(XMLChar::isNameChar(c)) { length++; c=thisStream->nextChar(); } thisStream->streamPos = lastStreamPos; if(length==0) { return 0; } char* s = new char[length+1]; for(unsigned long i=0; inextChar(); } s[length]=0; Nmtoken=s; delete s; if(DEBUGXMLPARSER) { printf("Nmtoken = '%s'\n",Nmtoken.c_str()); } return 1; }; // ****************************************************************************** void XMLParser::matchProduction09EntityLiteral( XMLString& EntityLiteral) { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction09EntityLiteral\n"); } matchProductionQuotedString((*XMLEntityStreamStack.begin()),EntityLiteral); }; // ****************************************************************************** void XMLParser::matchProduction10AttValue( XMLString& AttValue) { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction_AttVal\n"); } matchProductionQuotedString((*XMLEntityStreamStack.begin()),AttValue); // check it for "<" for(unsigned long i=0;istreamPos.columnNumber -= PubidLiteral.length() + 1; throw XMLParserException(&XMLEntityStreamStack,"not a valid PubidLiteral",XMLParserException::BAD_XML_ERR); } }; // ****************************************************************************** bool XMLParser::matchProduction14CharData( Element* containingElement) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction14CharData\n"); } list lastXMLEntityStreamStack; list lastStreamsPosition; // store last position in this and all parent streams storeStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); // need to get length and expand general entity // and character references as we go long length=sweepContent(0); // now restore last position for this and all parent streams restoreStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); if(length==0) { return 0; } char* s=new char[length+1]; sweepContent(s); XMLString CharData=s; delete s; Node* newTextNode = theDocument->createTextNode(CharData); containingElement->appendChild(newTextNode); if(DEBUGXMLPARSER) { printf("CharData = '%s'\n",CharData.c_str()); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction15Comment( Element* containingElement) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction15Comment\n"); } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"")) { // comment incorrectly terminated throw XMLParserException(&XMLEntityStreamStack,"'-->' expected",XMLParserException::BAD_XML_ERR); } if(!(containingElement==0)) { Node* newCommentNode = theDocument->createComment(Comment); containingElement->appendChild(newCommentNode); } if(DEBUGXMLPARSER) { printf("Comment = '%s'\n",Comment.c_str()); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction16PI( Element* containingElement) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction16PI\n"); } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"streamPos.columnNumber -= PITarget.length(); throw XMLParserException(&XMLEntityStreamStack, "illegal processing instruction target name", XMLParserException::BAD_XML_ERR); } StreamPositionStruct lastStreamPos1 = (*XMLEntityStreamStack.begin())->streamPos; long whiteSpace=matchProduction03S((*XMLEntityStreamStack.begin()),0); StreamPositionStruct lastStreamPos2 = (*XMLEntityStreamStack.begin())->streamPos; long length = howFarTo("?>"); if((length>0)&(whiteSpace==0)) { (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos1; throw XMLParserException(&XMLEntityStreamStack,"white space expected",XMLParserException::BAD_XML_ERR); } (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos2; loadNChar((*XMLEntityStreamStack.begin()),PIString,length); if(!(containingElement==0)) { Node* newProcessingInstructionNode = theDocument->createProcessingInstruction(PITarget,PIString); containingElement->appendChild(newProcessingInstructionNode); } if(DEBUGXMLPARSER) { printf("PITarget = '%s'\n",PITarget.c_str()); printf("PIString = '%s'\n",PIString.c_str()); } // skip the '?>' (*XMLEntityStreamStack.begin())->streamPos.count += 2; (*XMLEntityStreamStack.begin())->streamPos.columnNumber += 2; return 1; }; // ****************************************************************************** void XMLParser::matchProduction17PITarget( XMLString& PITarget) { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction17PITarget\n"); } matchProduction05Name((*XMLEntityStreamStack.begin()),PITarget); }; // ****************************************************************************** bool XMLParser::matchProduction18CDSect( Element* containingElement) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction18CDSect\n"); } if(!matchProduction19CDStart()) { return 0; } // critical point XMLString CData; matchProduction20CData(CData); matchProduction21CDEnd(); Node* newCDATASectionNode = theDocument->createCDATASection(CData); containingElement->appendChild(newCDATASectionNode); return 1; }; // ****************************************************************************** bool XMLParser::matchProduction19CDStart() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction19CDStart\n"); } return(matchProductionFixedString((*XMLEntityStreamStack.begin()),"streamPos; long length = howFarTo("]]>"); (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; loadNChar((*XMLEntityStreamStack.begin()),CData,length); if(DEBUGXMLPARSER) { printf("CData = '%s'\n",CData.c_str()); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction21CDEnd() { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction21CDEnd\n"); } return(matchProductionFixedString((*XMLEntityStreamStack.begin()),"]]>")); }; // ****************************************************************************** void XMLParser::matchProduction22Prolog() { // this production is required // note, however, that all of its sub-productions are optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction22Prolog\n"); } matchProduction23XMLDecl(); while(matchProduction27Misc(0)); // again, what is this doing?? PTC matchProduction28doctypedecl(); if(!(theDocumentType==0)) { while(matchProduction27Misc(0)); // and again... PTC } }; // ****************************************************************************** bool XMLParser::matchProduction23XMLDecl() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction23XMLDecl\n"); } StreamPositionStruct lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; if(!matchProductionFixedString((*XMLEntityStreamStack.begin())," not an XMLDecl => back out (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; return 0; } // critical point XMLString tempString; if(matchProduction24VersionInfo((*XMLEntityStreamStack.begin()),tempString)) { rootVersionNum=tempString; } { if(matchProduction80EncodingDecl((*XMLEntityStreamStack.begin()),tempString)) rootEncName=tempString; } matchProduction32SDDecl(); matchProduction03S((*XMLEntityStreamStack.begin()),0); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"?>")) { // XMLDecl incorrectly terminated throw XMLParserException(&XMLEntityStreamStack,"'?>' expected",XMLParserException::BAD_XML_ERR); } return 0; }; // ****************************************************************************** bool XMLParser::matchProduction24VersionInfo( XMLEntityStream *const thisStream, XMLString& VersionNum) { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction24VersionInfo\n"); } if(!matchProductionFixedString(thisStream,"version")) { throw XMLParserException(&XMLEntityStreamStack,"'version' expected",XMLParserException::BAD_XML_ERR); } matchProduction25Eq(thisStream); matchProductionQuotedString(thisStream,VersionNum); if(!VersionNum.isVersionNum()) { // isn't a VersionNum thisStream->streamPos.columnNumber -= VersionNum.length() + 1; throw XMLParserException(&XMLEntityStreamStack,"not a valid Version number",XMLParserException::BAD_XML_ERR); } if(DEBUGXMLPARSER) { printf("VersionNum = '%s'\n",VersionNum.c_str()); } return 1; }; // ****************************************************************************** void XMLParser::matchProduction25Eq( XMLEntityStream *const thisStream) { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction25Eq\n"); } matchProduction03S(thisStream,0); if(!matchProductionFixedString(thisStream,"=")) { throw XMLParserException(&XMLEntityStreamStack,"'=' expected",XMLParserException::BAD_XML_ERR); } matchProduction03S(thisStream,0); }; // ****************************************************************************** bool XMLParser::matchProduction27Misc( Element* containingElement) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction27Misc\n"); } if(matchProduction03SDeep(0)>0) { return 1; } if(matchProduction15Comment(containingElement)) { return 1; } if(matchProduction16PI(containingElement)) { return 1; } return 0; }; // ****************************************************************************** bool XMLParser::matchProduction28aDeclSep() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction28aDeclSep\n"); } if(matchProduction03SDeep(0)>0) { return 1; } XMLString refName; unsigned long refLength; XMLEntityStream* refStream; refLength=matchProduction69PEReference((*XMLEntityStreamStack.begin()),refName); if(refLength==0) { return 0; } // we have found a PEReference, now need to find its stream and descend // into it refStream = (*XMLEntityStreamStack.begin())->getXMLEntityStream(refName,XMLEntityStream::PARAMETER_ENTITY); if(refStream==0) { (*XMLEntityStreamStack.begin())->streamPos.count -= refLength; (*XMLEntityStreamStack.begin())->streamPos.columnNumber -= refLength; sprintf(errormessage,"Parameter Entity '%s' unknown",refName.c_str()); throw XMLParserException(&XMLEntityStreamStack,errormessage,XMLParserException::BAD_XML_ERR); } XMLEntityStreamStack.push_front(refStream); return 1; }; // ****************************************************************************** bool XMLParser::matchProduction28doctypedecl() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction28doctypedecl\n"); } StreamPositionStruct lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"streamPos = lastStreamPos; return 0; } // critical point XMLString doctypeName; XMLString SystemLiteral; XMLString PubidLiteral; if(!matchProduction05Name((*XMLEntityStreamStack.begin()),doctypeName)) { throw XMLParserException(&XMLEntityStreamStack,"Name (for DTD) expected.", XMLParserException::BAD_XML_ERR); } matchProduction03S((*XMLEntityStreamStack.begin()),0); matchProduction75ExternalID(PubidLiteral,SystemLiteral); matchProduction03S((*XMLEntityStreamStack.begin()),0); // OK, now we can create 'theDocumentType' theDocumentType = myDOMImplementation.createDocumentType(doctypeName,PubidLiteral,SystemLiteral); // now if we have a SystemLiteral we need to create an XMLEntityStream for it, and // descend into it in order to parse the external DTD before processing the // internal subset if(SystemLiteral.length()>0) { if(StandAlone) { throw XMLParserException(&XMLEntityStreamStack,"External DTD not allowed in standalone documents", XMLParserException::BAD_XML_ERR); } XMLEntityStream* newXMLEntityStream = (*XMLEntityStreamStack.begin())->addParameterXMLEntityStream( doctypeName,PubidLiteral,SystemLiteral); XMLEntityStreamStack.push_front(newXMLEntityStream); matchProduction31extSubsetDecl(); if(XMLEntityStreamStack.size()>1) { throw XMLParserException(&XMLEntityStreamStack, "markupdecl|conditionalSect|DeclSep expected", XMLParserException::BAD_XML_ERR); } } // now parse internal subset if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"[")) { bool more2go = 1; while(more2go) { more2go = matchProduction29markupdecl(); if((*XMLEntityStreamStack.begin())!=rootXMLEntityStream) { more2go = more2go|matchProduction61conditionalSect(); } more2go = more2go|matchProduction28aDeclSep(); if(!more2go) { if((*XMLEntityStreamStack.begin())!=rootXMLEntityStream) { if((*XMLEntityStreamStack.begin())->atEnd()) { (*XMLEntityStreamStack.begin()) = (*XMLEntityStreamStack.begin())->parentXMLEntityStream(); } else { throw XMLParserException(&XMLEntityStreamStack, "markupdecl|conditionalSect|DeclSep expected", XMLParserException::BAD_XML_ERR); } more2go=1; } } } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"]")) { // not correctly terminated throw XMLParserException(&XMLEntityStreamStack,"']' expected", XMLParserException::BAD_XML_ERR); } matchProduction03S((*XMLEntityStreamStack.begin()),0); } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),">")) { // not correctly terminated throw XMLParserException(&XMLEntityStreamStack,"'>'expected", XMLParserException::BAD_XML_ERR); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction29markupdecl() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction29markupdecl\n"); } if(matchProduction45elementdecl()) { return 1; } if(matchProduction52AttlistDecl()) { return 1; } if(matchProduction70EntityDecl()) { return 1; } if(matchProduction82NotationDecl()) { return 1; } if(matchProduction16PI(0)) { return 1; } if(matchProduction15Comment(0)) { return 1; } return 0; }; // ****************************************************************************** void XMLParser::matchProduction31extSubsetDecl() { if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction31extSubsetDecl\n"); } // this production is optional const unsigned long enteringlevel = XMLEntityStreamStack.size(); while(1) { if(matchProduction29markupdecl()) {} else if(matchProduction61conditionalSect()) {} else if(matchProduction28aDeclSep()) {} else if(XMLEntityStreamStack.size()<=enteringlevel) { return; } else { throw XMLParserException(&XMLEntityStreamStack,"markupdecl|conditionalSect|DeclSep expected", XMLParserException::BAD_XML_ERR); } } }; // ****************************************************************************** bool XMLParser::matchProduction32SDDecl() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction32SDDecl\n"); } StreamPositionStruct lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; if(matchProduction03S((*XMLEntityStreamStack.begin()),0)==0) { return 0; // there was no white space } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"standalone")) { // back out (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; return 0; } // critical point matchProduction25Eq((*XMLEntityStreamStack.begin())); XMLString SDDecl; lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; matchProductionQuotedString((*XMLEntityStreamStack.begin()),SDDecl); if(SDDecl=="yes") { StandAlone = 1; } else if(SDDecl=="no") { StandAlone = 0; } else { // isn't an SDDecl (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; (*XMLEntityStreamStack.begin())->streamPos.columnNumber++; throw XMLParserException(&XMLEntityStreamStack,"'yes' or 'no' expected for StandAlone declaration", XMLParserException::BAD_XML_ERR); } if(DEBUGXMLPARSER) { printf("SDDecl = '%s'\n",SDDecl.c_str()); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction39Element( Element* containingElement) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction39Element\n"); } const XMLEntityStream *const enteringXMLEntityStream = (*XMLEntityStreamStack.begin()); StreamPositionStruct lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; XMLString tagName; list myAttributeNamesList; list myAttributeValuesList; Element* newElement; bool isEmptyElement=0; if(matchProduction44EmptyElementTag(&tagName,&myAttributeNamesList,&myAttributeValuesList)) { isEmptyElement=1; } else if(!matchProduction40STag(&tagName,&myAttributeNamesList,&myAttributeValuesList)) { return 0; } if((theDocument==0)&(theDocumentType!=0)) { if(tagName != *theDocumentType->nodeName()) { (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; (*XMLEntityStreamStack.begin())->streamPos.columnNumber++; sprintf(errormessage, "Expecting root element to be '%s'\n",theDocumentType->nodeName()->c_str()); throw XMLParserException(&XMLEntityStreamStack,errormessage, XMLParserException::BAD_XML_ERR); } } // need to compile a list of local URI bindings list localPrefixes; list localURIs; XMLString defaultURI; list::const_iterator pAttName = myAttributeNamesList.begin(); list::const_iterator pAttValue = myAttributeValuesList.begin(); while(pAttName!=myAttributeNamesList.end()) { if(pAttName->eqxmlns()) { defaultURI = *pAttValue; } else { XMLString attPrefix; XMLString attLocalName; if(pAttName->splitNSName(attPrefix,attLocalName)) { if(attPrefix.eqxmlns()) { localPrefixes.push_back(attLocalName); localURIs.push_back(*pAttValue); } } } pAttName++; pAttValue++; } // now find URI binding for element tagName XMLString prefix; XMLString localName; XMLString namespaceURI; if(tagName.splitNSName(prefix,localName)) { // prefix exists, is it xml:? if(prefix.eqxml()) { if(DEBUGXMLPARSER) { printf("my prefix is xml, will use XML_NAMESPACEURI binding\n"); } namespaceURI = XML_NAMESPACEURI; } if(namespaceURI.length()==0) { // not xml: => look for xmlns:prefix="..." binding // firstly look for local binding if(DEBUGXMLPARSER) { printf("my prefix is not xml, looking for local binding\n"); } list::const_iterator pLocalPrefix=localPrefixes.begin(); list::const_iterator pLocalURIs=localURIs.begin(); while((namespaceURI.length()==0)&(pLocalPrefix!=localPrefixes.end())) { if(*pLocalPrefix==prefix) { namespaceURI=*pLocalURIs; } pLocalPrefix++; pLocalURIs++; } } if((namespaceURI.length()==0)&!(containingElement==0)) { // didn't find one in attributes, look in ancestor elements if(DEBUGXMLPARSER) { printf("my prefix is not xml, looking for binding in ancestor element\n"); } const XMLString* pNamespaceURI=containingElement->lookupNamespaceURI(prefix); if(!(pNamespaceURI==0)) { namespaceURI=*pNamespaceURI; } } if(namespaceURI.length()==0) { // cannot find a URI binding (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; (*XMLEntityStreamStack.begin())->streamPos.columnNumber++; throw XMLParserException(&XMLEntityStreamStack, "Cannot find internal URI binding for this prefix", XMLParserException::BAD_XML_ERR); } } else { // no prefix => look for default xmlns="..." binding if(!(defaultURI.length()==0)) { // a local default exists if(DEBUGXMLPARSER) { printf("there is a local default URI binding\n"); } namespaceURI=defaultURI; } else if(!(containingElement==0)) { // no local default, try in ancestor elements if(DEBUGXMLPARSER) { printf("looking for default binding in ancestor element\n"); } const XMLString* pNamespaceURI=containingElement->lookupNamespaceURI(""); if(!(pNamespaceURI==0)) { namespaceURI=*pNamespaceURI; } } } if(DEBUGXMLPARSER) { printf("my namespaceURI binding is'%s'\n",namespaceURI.c_str()); } if(theDocument==0) { theDocument = myDOMImplementation.createDocument(namespaceURI,tagName,theDocumentType); newElement = theDocument->documentElement(); } else { if (namespaceURI.length()==0) { newElement = theDocument->createElement(tagName); } else { newElement = theDocument->createElementNS(namespaceURI,tagName); } } if(!(containingElement==0)) { containingElement->appendChild(newElement); } // now add the attributes pAttName = myAttributeNamesList.begin(); pAttValue = myAttributeValuesList.begin(); while(pAttName!=myAttributeNamesList.end()) { if(DEBUGXMLPARSER) { printf("examining attribute %s='%s'\n",pAttName->c_str(),pAttValue->c_str()); } if(pAttName->splitNSName(prefix,localName)) { // attribute has a prefix if(DEBUGXMLPARSER) { printf(" attribute has a prefix\n"); } namespaceURI=""; if(prefix.eqxml()) { namespaceURI = XML_NAMESPACEURI; } else if(prefix.eqxmlns()) { namespaceURI = XMLNS_NAMESPACEURI; } else { // need to look for local binding if(DEBUGXMLPARSER) { printf(" prefix is not xml or xmlns, looking for local binding\n"); } list::const_iterator pLocalPrefix=localPrefixes.begin(); list::const_iterator pLocalURIs=localURIs.begin(); while((namespaceURI.length()==0)&(pLocalPrefix!=localPrefixes.end())) { if(*pLocalPrefix==prefix) { namespaceURI=*pLocalURIs; } pLocalPrefix++; pLocalURIs++; } } if((namespaceURI.length()==0)&!(containingElement==0)) { // look for default in ancestor elements if(DEBUGXMLPARSER) { printf("no local binding found, looking for ancestral binding\n"); } const XMLString* pNamespaceURI=containingElement->lookupNamespaceURI(""); if(!(pNamespaceURI==0)) { namespaceURI=*pNamespaceURI; } } if(namespaceURI.length()==0) { sprintf(errormessage,"Cannot find internal URI binding for prefix '%s'\n",prefix.c_str()); throw XMLParserException(&XMLEntityStreamStack,errormessage,XMLParserException::BAD_XML_ERR); } // all is ok, can add NSAttribute newElement->setAttributeNS(namespaceURI,*pAttName,*pAttValue); } else { // attribute has no prefix if(DEBUGXMLPARSER) { printf(" attribute has no prefix\n"); } if(pAttName->eqxmlns()) { namespaceURI = XMLNS_NAMESPACEURI; } else { namespaceURI = defaultURI; } if(namespaceURI.length()==0) { newElement->setAttribute(*pAttName,*pAttValue); } else { newElement->setAttributeNS(namespaceURI,*pAttName,*pAttValue); } } pAttName++; pAttValue++; } if(!isEmptyElement) { matchProduction43content(newElement); if((*XMLEntityStreamStack.begin()) != enteringXMLEntityStream) { throw XMLParserException(&XMLEntityStreamStack, "End tag without start tag in same entity", XMLParserException::BAD_XML_ERR); } myxmdsBytePoint = (*XMLEntityStreamStack.begin())->streamPos.count; matchProduction42ETag(tagName); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction40STag( XMLString* tagName, list* myAttributeNamesList, list* myAttributeValuesList) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction40STag\n"); } StreamPositionStruct lastStreamPos1 = (*XMLEntityStreamStack.begin())->streamPos; if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"<")) { return 0; } StreamPositionStruct lastStreamPos2 = (*XMLEntityStreamStack.begin())->streamPos; //char c=(*XMLEntityStreamStack.begin())->nextChar(); signed char c=(*XMLEntityStreamStack.begin())->nextChar(); if(c==EOF) { // back out (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos1; return 0; } if(!XMLChar::isLetter(c)) { // back out (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos1; return 0; } // critical point (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos2; matchProduction05Name((*XMLEntityStreamStack.begin()),*tagName); while(matchProduction03S((*XMLEntityStreamStack.begin()),0)) { XMLString nextAttributeName; XMLString nextAttributeValue; XMLString* newXMLString; if(matchProduction41Attribute(nextAttributeName,nextAttributeValue)) { newXMLString = new XMLString(nextAttributeName); myAttributeNamesList->push_back(*newXMLString); newXMLString = new XMLString(nextAttributeValue); myAttributeValuesList->push_back(*newXMLString); } } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),">")) { // not correctly terminated throw XMLParserException(&XMLEntityStreamStack,"'>' expected",XMLParserException::BAD_XML_ERR); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction41Attribute( XMLString& AttName, XMLString& AttValue) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction41Attribute\n"); } StreamPositionStruct lastStreamPos; lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; //char c=(*XMLEntityStreamStack.begin())->nextChar(); signed char c=(*XMLEntityStreamStack.begin())->nextChar(); if(c==EOF) { return 0; } if(!XMLChar::isLetter(c)) { // not an attribute (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; return 0; } (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; matchProduction05Name((*XMLEntityStreamStack.begin()),AttName); // check that AttName is NS well formed if(!AttName.isNSWellFormed()) { (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; throw XMLParserException(&XMLEntityStreamStack,"Attribute name not NameSpace well formed", XMLParserException::BAD_XML_ERR); } // check that prefix and localName are valid XMLString prefix; XMLString localName; if(AttName.splitNSName(prefix,localName)) { if(!(prefix.eqxmlns()|prefix.eqxml())&prefix.beginsWithxml()) { (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; throw XMLParserException(&XMLEntityStreamStack, "Prefix not allowed to begin with (X|x)(M|m)(L|l)", XMLParserException::BAD_XML_ERR); } if(localName.length()==0) { throw XMLParserException(&XMLEntityStreamStack,"Where is the local name?", XMLParserException::BAD_XML_ERR); } } else { if(!AttName.eqxmlns()&AttName.beginsWithxml()) { (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; throw XMLParserException(&XMLEntityStreamStack, "Atrribute name not allowed to begin with (X|x)(M|m)(L|l)", XMLParserException::BAD_XML_ERR); } } matchProduction25Eq((*XMLEntityStreamStack.begin())); lastStreamPos=(*XMLEntityStreamStack.begin())->streamPos; matchProduction10AttValue(AttValue); (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; // now parse the AttValue for character and general entity refs, // checking for circular references as we go. See 14CharData for prior example list lastXMLEntityStreamStack; list lastStreamsPosition; storeStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); long length=sweepAttValue(0); restoreStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); char* s=new char[length+1]; sweepAttValue(s); AttValue=s; delete s; return 1; }; // ****************************************************************************** void XMLParser::matchProduction42ETag( XMLString& RequiredName) { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction42ETag\n"); } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"streamPos.count -= ETagName.length(); (*XMLEntityStreamStack.begin())->streamPos.columnNumber -= ETagName.length(); sprintf(errormessage, "End tag for element '%s' expected",RequiredName.c_str()); throw XMLParserException(&XMLEntityStreamStack,errormessage, XMLParserException::BAD_XML_ERR); } matchProduction03S((*XMLEntityStreamStack.begin()),0); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),">")) { // not correctly terminated throw XMLParserException(&XMLEntityStreamStack,"'>' expected", XMLParserException::BAD_XML_ERR); } }; // ****************************************************************************** void XMLParser::matchProduction43content( Element* containingElement) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction43content\n"); } bool contentFound=1; while(contentFound) { if (contentFound=matchProduction14CharData(containingElement)) {} else if(contentFound=matchProduction39Element(containingElement)) {} // else if(contentFound=matchProduction67Reference(containingElement)) {} else if(contentFound=matchProduction18CDSect(containingElement)) {} else if(contentFound=matchProduction16PI(containingElement)) {} else { (contentFound=matchProduction15Comment(containingElement)); } } }; // ****************************************************************************** bool XMLParser::matchProduction44EmptyElementTag( XMLString* tagName, list* myAttributeNamesList, list* myAttributeValuesList) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction44EmptyElementTag\n"); } // this routine is a special case of the normal STag routine, in that // it will go the end and then back out if no / found StreamPositionStruct lastStreamPos1 = (*XMLEntityStreamStack.begin())->streamPos; if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"<")) { return 0; } StreamPositionStruct lastStreamPos2 = (*XMLEntityStreamStack.begin())->streamPos; //char c=(*XMLEntityStreamStack.begin())->nextChar(); signed char c=(*XMLEntityStreamStack.begin())->nextChar(); if(c==EOF) { // back out (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos1; return 0; } if(!XMLChar::isLetter(c)) { // back out (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos1; return 0; } // while this routine will go to the end and then back out if no /> found // it well test the tagName and the attribute list for errors anyway (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos2; matchProduction05Name((*XMLEntityStreamStack.begin()),*tagName); // check that tagName is NS well formed if(!tagName->isNSWellFormed()) { (*XMLEntityStreamStack.begin())->streamPos.columnNumber -= tagName->length(); throw XMLParserException(&XMLEntityStreamStack,"Element tagName not NameSpace well formed",XMLParserException::BAD_XML_ERR); } // check that prefix and localName are valid XMLString prefix; XMLString localName; if(tagName->splitNSName(prefix,localName)) { if((!prefix.eqxml())&prefix.beginsWithxml()) { (*XMLEntityStreamStack.begin())->streamPos.columnNumber -= tagName->length(); throw XMLParserException(&XMLEntityStreamStack, "Prefix not allowed to begin with (X|x)(M|m)(L|l)", XMLParserException::BAD_XML_ERR); } if(localName.length()==0) { throw XMLParserException(&XMLEntityStreamStack,"Where is the local name?", XMLParserException::BAD_XML_ERR); } } else { if(tagName->beginsWithxml()) { (*XMLEntityStreamStack.begin())->streamPos.columnNumber -= tagName->length(); throw XMLParserException(&XMLEntityStreamStack, "Element name not allowed to begin with (X|x)(M|m)(L|l)", XMLParserException::BAD_XML_ERR); } } while(matchProduction03S((*XMLEntityStreamStack.begin()),0)) { XMLString nextAttributeName; XMLString nextAttributeValue; XMLString* newXMLString; if(matchProduction41Attribute(nextAttributeName,nextAttributeValue)) { // test new attribute to see if its name is unique in this element tag for(list::const_iterator pXMLString = myAttributeNamesList->begin(); pXMLString != myAttributeNamesList->end();pXMLString++) { if(nextAttributeName==*pXMLString) { throw XMLParserException(&XMLEntityStreamStack,"Duplicated attribute!", XMLParserException::BAD_XML_ERR); } } // add new attribute to list newXMLString = new XMLString(nextAttributeName); myAttributeNamesList->push_back(*newXMLString); newXMLString = new XMLString(nextAttributeValue); myAttributeValuesList->push_back(*newXMLString); } } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"/>")) { // back out myAttributeNamesList->clear(); myAttributeValuesList->clear(); (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos1; return 0; } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction45elementdecl() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction45elementdecl\n"); } const XMLEntityStream *const enteringStream = (*XMLEntityStreamStack.begin()); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"")) { // not correctly terminated throw XMLParserException(&XMLEntityStreamStack,"'>'expected", XMLParserException::BAD_XML_ERR); } return 1; }; // ****************************************************************************** void XMLParser::matchProduction46contentspec() { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction46contentspec\n"); } if(matchProduction51Mixed()) { return; } if(matchProduction47children()) { // test for children after mixed return; } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"EMPTY")) { return; } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"ANY")) { return; } throw XMLParserException(&XMLEntityStreamStack, "'EMPTY' or 'ANY' or mixed or children productions expected", XMLParserException::BAD_XML_ERR); }; // ****************************************************************************** bool XMLParser::matchProduction47children() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction47children\n"); } StreamPositionStruct lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; if(!matchProduction49choice()) { if(!matchProduction50seq()) { // testing seq after choice is important! // back out (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; return 0; } } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"?")) { return 1; } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"*")) { return 1; } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"+")) { return 1; } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction48cp() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction48cp\n"); } XMLString Name; if(!matchProduction49choice()) { if(!matchProduction50seq()) { try { matchProduction05Name((*XMLEntityStreamStack.begin()),Name); } catch(XMLParserException XMLRoutinesErr) { return 0; } } } if(matchProduction03SDeep(0)>0) { return 1; } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"?")) { return 1; } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"*")) { return 1; } matchProductionFixedString((*XMLEntityStreamStack.begin()),"+"); return 1; }; // ****************************************************************************** bool XMLParser::matchProduction49choice() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction49choice\n"); } list lastXMLEntityStreamStack; list lastStreamsPosition; storeStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); bool foundOR=0; if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"(")) { return 0; } matchProduction03SDeep(0); if(!matchProduction48cp()) { // back out restoreStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); return 0; } matchProduction03SDeep(0); while(matchProductionFixedString((*XMLEntityStreamStack.begin()),"|")) { // critical point matchProduction03SDeep(0); if(!matchProduction48cp()) { throw XMLParserException(&XMLEntityStreamStack, "Name or (choice) or (seq) expected", XMLParserException::BAD_XML_ERR); } matchProduction03SDeep(0); foundOR=1; } if(!foundOR) { // back out restoreStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); return 0; } if((*XMLEntityStreamStack.begin()) != (*lastXMLEntityStreamStack.begin())) { // Bad nesting throw XMLParserException(&XMLEntityStreamStack, "Logical structures not properly nested.", XMLParserException::BAD_XML_ERR); } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),")")) { throw XMLParserException(&XMLEntityStreamStack,"'|' or ')' expected", XMLParserException::BAD_XML_ERR); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction50seq() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction50seq\n"); } const XMLEntityStream *const enteringStream = (*XMLEntityStreamStack.begin()); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"(")) { return 0; } // set critical point here, but test for seq after choice // and children after mixed, this way at least opening with a bracket // will generate informative error messages matchProduction03SDeep(0); if(!matchProduction48cp()) { throw XMLParserException(&XMLEntityStreamStack, "#PCDATA or Name or (choice) or (seq) expected", XMLParserException::BAD_XML_ERR); } matchProduction03SDeep(0); while(matchProductionFixedString((*XMLEntityStreamStack.begin()),",")) { matchProduction03SDeep(0); if(!matchProduction48cp()) { throw XMLParserException(&XMLEntityStreamStack, "Name or (choice) or (seq) expected", XMLParserException::BAD_XML_ERR); } matchProduction03SDeep(0); } if((*XMLEntityStreamStack.begin()) != enteringStream) { // Bad nesting throw XMLParserException(&XMLEntityStreamStack, "Logical structures not properly nested.", XMLParserException::BAD_XML_ERR); } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),")")) { throw XMLParserException(&XMLEntityStreamStack,"',' or '|' or ')' expected", XMLParserException::BAD_XML_ERR); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction51Mixed() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction51Mixed\n"); } list lastXMLEntityStreamStack; list lastStreamsPosition; storeStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"(")) { // back out restoreStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); return 0; } matchProduction03SDeep(0); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"#PCDATA")) { // back out restoreStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); return 0; } // critcal point matchProduction03SDeep(0); XMLString Name; bool hasNames=0; while(matchProductionFixedString((*XMLEntityStreamStack.begin()),"|")) { matchProduction03SDeep(0); matchProduction05Name((*XMLEntityStreamStack.begin()),Name); matchProduction03SDeep(0); hasNames=1; } if((*XMLEntityStreamStack.begin()) != (*lastXMLEntityStreamStack.begin())) { // Bad nesting throw XMLParserException(&XMLEntityStreamStack, "Logical structures not properly nested.", XMLParserException::BAD_XML_ERR); } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),")")) { throw XMLParserException(&XMLEntityStreamStack,"')' expected", XMLParserException::BAD_XML_ERR); } if(hasNames) { if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"*")) { throw XMLParserException(&XMLEntityStreamStack,"'*' expected", XMLParserException::BAD_XML_ERR); } } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction52AttlistDecl() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction52AttlistDecl\n"); } const XMLEntityStream *const enteringStream = (*XMLEntityStreamStack.begin()); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"")) { // not correctly terminated throw XMLParserException(&XMLEntityStreamStack,"'>' expected", XMLParserException::BAD_XML_ERR); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction53AttDef() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction53AttDef\n"); } if(matchProduction03SDeep(0)==0) { return 0; } char c=(*XMLEntityStreamStack.begin())->nextChar(); if(c=='>') { // back out, but it doesn't matter that we have covered the white space (*XMLEntityStreamStack.begin())->streamPos.count--; (*XMLEntityStreamStack.begin())->streamPos.columnNumber--; return 0; } // critical point XMLString attName; matchProduction05Name((*XMLEntityStreamStack.begin()),attName); matchProduction03SDeep(1); matchProduction54AttType(); matchProduction03SDeep(1); matchProduction60DefaultDecl(); return 1; }; // ****************************************************************************** void XMLParser::matchProduction54AttType() { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction54AttType\n"); } if(matchProduction55StringType()) { return; } if(matchProduction56TokenizedType()) { return; } if(matchProduction57EnumeratedType()) { return; } throw XMLParserException(&XMLEntityStreamStack,"AttType expected", XMLParserException::BAD_XML_ERR); }; // ****************************************************************************** bool XMLParser::matchProduction55StringType() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction55StringType\n"); } return matchProductionFixedString((*XMLEntityStreamStack.begin()),"CDATA"); }; // ****************************************************************************** bool XMLParser::matchProduction56TokenizedType() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction56TokenizedType\n"); } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"NMTOKENS")) { return 1; } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"NMTOKEN")) { return 1; } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"ENTITIES")) { return 1; } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"ENTITY")) { return 1; } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"IDREFS")) { return 1; } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"IDREF")) { return 1; } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"ID")) { return 1; } return 0; }; // ****************************************************************************** bool XMLParser::matchProduction57EnumeratedType() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction57EnumeratedType\n"); } if(matchProduction58NotationType()) { return 1; } if(matchProduction59Enumeration()) { return 1; } return 0; }; // ****************************************************************************** bool XMLParser::matchProduction58NotationType() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction58NotationType\n"); } XMLString Name; if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"NOTATION")) { return 0; } // critical point matchProduction03SDeep(1); const XMLEntityStream *const enteringStream = (*XMLEntityStreamStack.begin()); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"(")) { throw XMLParserException(&XMLEntityStreamStack,"'(' expected", XMLParserException::BAD_XML_ERR); } matchProduction03SDeep(0); matchProduction05Name((*XMLEntityStreamStack.begin()),Name); matchProduction03SDeep(0); while(matchProductionFixedString((*XMLEntityStreamStack.begin()),"|")) { matchProduction03SDeep(0); matchProduction05Name((*XMLEntityStreamStack.begin()),Name); matchProduction03SDeep(0); } if((*XMLEntityStreamStack.begin()) != enteringStream) { // Bad nesting throw XMLParserException(&XMLEntityStreamStack, "Logical structures not properly nested.", XMLParserException::BAD_XML_ERR); } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),")")) { throw XMLParserException(&XMLEntityStreamStack,"')' expected", XMLParserException::BAD_XML_ERR); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction59Enumeration() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction59Enumeration\n"); } XMLString Nmtoken; const XMLEntityStream *const enteringStream = (*XMLEntityStreamStack.begin()); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"(")) { return 0; } // critical point matchProduction03SDeep(0); matchProduction07Nmtoken((*XMLEntityStreamStack.begin()),Nmtoken); matchProduction03SDeep(0); while(matchProductionFixedString((*XMLEntityStreamStack.begin()),"|")) { matchProduction03SDeep(0); matchProduction07Nmtoken((*XMLEntityStreamStack.begin()),Nmtoken); matchProduction03SDeep(0); } if((*XMLEntityStreamStack.begin()) != enteringStream) { // Bad nesting throw XMLParserException(&XMLEntityStreamStack, "Logical structures not properly nested.", XMLParserException::BAD_XML_ERR); } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),")")) { throw XMLParserException(&XMLEntityStreamStack,"')' expected", XMLParserException::BAD_XML_ERR); } return 1; }; // ****************************************************************************** void XMLParser::matchProduction60DefaultDecl() { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction60DefaultDecl\n"); } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"#REQUIRED")) { return; } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"#IMPLIED")) { return; } matchProductionFixedString((*XMLEntityStreamStack.begin()),"#FIXED"); matchProduction03SDeep(0); XMLString AttValue; try { matchProduction10AttValue(AttValue); } catch(XMLParserException) { throw XMLParserException(&XMLEntityStreamStack, "'#REQUIRED' or '#IMPLIED' or '#FIXED AttValue' expected", XMLParserException::BAD_XML_ERR); } }; // ****************************************************************************** bool XMLParser::matchProduction61conditionalSect() { if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction61conditionalSect\n"); } // this production is optional if(matchProduction62includeSect()) { return 1; } if(matchProduction63ignoreSect()) { return 1; } return 0; }; // ****************************************************************************** bool XMLParser::matchProduction62includeSect() { if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction62includeSect\n"); } // this production is optional list lastXMLEntityStreamStack; list lastStreamsPosition; storeStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"")) { throw XMLParserException(&XMLEntityStreamStack,"']]>' expected", XMLParserException::BAD_XML_ERR); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction63ignoreSect() { if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction63ignoreSect\n"); } // this production is optional list lastXMLEntityStreamStack; list lastStreamsPosition; storeStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"")) { throw XMLParserException(&XMLEntityStreamStack,"']]>' expected", XMLParserException::BAD_XML_ERR); } return 1; }; // ****************************************************************************** void XMLParser::matchProduction64ignoreSectContents() { if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction64ignoreSectContents\n"); } // this production is optional matchProduction65ignore(); while(matchProductionFixedString((*XMLEntityStreamStack.begin()),"")) { throw XMLParserException(&XMLEntityStreamStack,"']]>' expected", XMLParserException::BAD_XML_ERR); } matchProduction65ignore(); } }; // ****************************************************************************** void XMLParser::matchProduction65ignore() { if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction65ignore\n"); } // this production is optional //char s[4]={0,0,0,0}; signed char s[4]={0,0,0,0}; StreamPositionStruct l[3]; l[0]=(*XMLEntityStreamStack.begin())->streamPos; s[0]=(*XMLEntityStreamStack.begin())->nextChar(); l[1]=(*XMLEntityStreamStack.begin())->streamPos; s[1]=(*XMLEntityStreamStack.begin())->nextChar(); if(s[0]==EOF) { (*XMLEntityStreamStack.begin())->streamPos=l[0]; return; } l[2]=(*XMLEntityStreamStack.begin())->streamPos; s[2]=(*XMLEntityStreamStack.begin())->nextChar(); while((s[2]!=EOF)&&strcmp((char *)s,"")) { s[0]=s[1];s[1]=s[2]; l[0]=l[1];l[1]=l[2]; l[2]=(*XMLEntityStreamStack.begin())->streamPos; s[2]=(*XMLEntityStreamStack.begin())->nextChar(); } (*XMLEntityStreamStack.begin())->streamPos=l[0]; }; // ****************************************************************************** unsigned long XMLParser::matchProduction66CharRef( XMLEntityStream *const thisStream, //char& cRef) const { signed char& cRef) const { if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction66CharRef\n"); } StreamPositionStruct lastStreamPos = thisStream->streamPos; //char c; signed char c; c=thisStream->nextChar(); if(c!='&') { thisStream->streamPos=lastStreamPos; return 0; }; c=thisStream->nextChar(); if(c!='#') { thisStream->streamPos=lastStreamPos; return 0; }; // critcal point bool hexNumber=0; c=thisStream->nextChar(); if(c=='x') { hexNumber=1; c=thisStream->nextChar(); } unsigned long length=0; if(hexNumber) { while(XMLChar::isLatinHexDigit(c)&(c!=EOF)) { length++; c=thisStream->nextChar(); } } else { while(XMLChar::isLatinDigit(c)&(c!=EOF)) { length++; c=thisStream->nextChar(); } } if(length==0) { if(hexNumber) { throw XMLParserException(&XMLEntityStreamStack, "hexadecimal reference expected", XMLParserException::BAD_XML_ERR); } else { throw XMLParserException(&XMLEntityStreamStack, "decimal reference expected", XMLParserException::BAD_XML_ERR); } } thisStream->streamPos.count -= length+1; thisStream->streamPos.columnNumber -= length+1; char* CharRefString; unsigned int CharRef; CharRefString = new char[length+1]; for(unsigned long i=0; inextChar(); } CharRefString[length]=0; if(hexNumber) { sscanf(CharRefString,"%x",&CharRef); } else { sscanf(CharRefString,"%u",&CharRef); } delete CharRefString; // finally check termination lastStreamPos = thisStream->streamPos; c=thisStream->nextChar(); if(c!=';') { // not correctly terminated thisStream->streamPos=lastStreamPos; throw XMLParserException(&XMLEntityStreamStack,"';' expected", XMLParserException::BAD_XML_ERR); }; if(CharRef&0xFF00) { // UTF16 and higher encodings not supported throw XMLParserException(&XMLEntityStreamStack, "Reference to Unicode XML character unable to be processed", XMLParserException::BAD_XML_ERR); } cRef = (char)CharRef; if(!XMLChar::isChar(cRef)) { // illegal character throw XMLParserException(&XMLEntityStreamStack, "Reference to Illegal XML character", XMLParserException::BAD_XML_ERR); } if(DEBUGXMLPARSER) { printf("CharRef = %c\n",CharRef); } if(hexNumber) { return length+4; } return length+3; }; // ****************************************************************************** unsigned long XMLParser::matchProduction68EntityRef( XMLEntityStream *const thisStream, XMLString& refName) const { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction68EntityRef\n"); } StreamPositionStruct lastStreamPos = thisStream->streamPos; char c; c=thisStream->nextChar(); if(c!='&') { thisStream->streamPos=lastStreamPos; return 0; }; //critical point if(!matchProduction05Name(thisStream,refName)) { throw XMLParserException(&XMLEntityStreamStack,"Name expected", XMLParserException::BAD_XML_ERR); } lastStreamPos = thisStream->streamPos; c=thisStream->nextChar(); if(c!=';') { thisStream->streamPos=lastStreamPos; throw XMLParserException(&XMLEntityStreamStack,"';' expected", XMLParserException::BAD_XML_ERR); } return refName.length()+2; }; // ****************************************************************************** unsigned long XMLParser::matchProduction69PEReference( XMLEntityStream *const thisStream, XMLString& PEName) const { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction69PEReference\n"); } StreamPositionStruct lastStreamPos = thisStream->streamPos; char c; c=thisStream->nextChar(); if(c!='%') { thisStream->streamPos=lastStreamPos; return 0; }; //critical point if(!matchProduction05Name(thisStream,PEName)) { throw XMLParserException(&XMLEntityStreamStack,"Name expected", XMLParserException::BAD_XML_ERR); } lastStreamPos = thisStream->streamPos; c=thisStream->nextChar(); if(c!=';') { thisStream->streamPos=lastStreamPos; throw XMLParserException(&XMLEntityStreamStack,"';' expected", XMLParserException::BAD_XML_ERR); } return PEName.length()+2; }; // ****************************************************************************** bool XMLParser::matchProduction70EntityDecl() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction70EntityDecl\n"); } if(matchProduction72PEDecl()) { return 1; } if(matchProduction71GEDecl()) { // do this one second for sake of error reporting return 1; } return 0; }; // ****************************************************************************** bool XMLParser::matchProduction71GEDecl() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction71GEDecl\n"); } const XMLEntityStream *const enteringStream = (*XMLEntityStreamStack.begin()); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"")) { // not correctly terminated throw XMLParserException(&XMLEntityStreamStack,"'>' expected", XMLParserException::BAD_XML_ERR); } // ok, now we have a new XMLEntityStream to load into storage: if(NotationName.length()>0) { (*XMLEntityStreamStack.begin())->addUnparsedXMLEntityStream( EntityDeclName,PubidLiteral,SystemLiteral,NotationName); } else if(SystemLiteral.length()>0) { (*XMLEntityStreamStack.begin())->addGeneralXMLEntityStream( EntityDeclName,PubidLiteral,SystemLiteral); } else { (*XMLEntityStreamStack.begin())->addGeneralXMLEntityStream(EntityDeclName,EntityLiteral); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction72PEDecl() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction72PEDecl\n"); } list lastXMLEntityStreamStack; list lastStreamsPosition; storeStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"")) { // not correctly terminated throw XMLParserException(&XMLEntityStreamStack,"'>' expected", XMLParserException::BAD_XML_ERR); } // ok, now we have a new XMLEntityStream to load into storage: if(SystemLiteral.length()>0) { (*XMLEntityStreamStack.begin())->addParameterXMLEntityStream( EntityDeclName,PubidLiteral,SystemLiteral); } else { (*XMLEntityStreamStack.begin())->addParameterXMLEntityStream(EntityDeclName,EntityLiteral); } return 1; }; // ****************************************************************************** void XMLParser::matchProduction73EntityDef( XMLString& PubidLiteral, XMLString& SystemLiteral, XMLString& NotationName, XMLString& EntityLiteral) { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction73EntityDef\n"); } if(matchProduction75ExternalID(PubidLiteral,SystemLiteral)) { matchProduction76NDataDecl(NotationName); } else { try { matchProduction09EntityLiteral(EntityLiteral); } catch(XMLParserException) { throw XMLParserException(&XMLEntityStreamStack, "EntityLiteral or ExternalID expected", XMLParserException::BAD_XML_ERR); } } }; // ****************************************************************************** void XMLParser::matchProduction74PEDef( XMLString& PubidLiteral, XMLString& SystemLiteral, XMLString& EntityLiteral) { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction74PEDef\n"); } if(!matchProduction75ExternalID(PubidLiteral,SystemLiteral)) { try { matchProduction09EntityLiteral(EntityLiteral); } catch(XMLParserException) { throw XMLParserException(&XMLEntityStreamStack, "EntityLiteral or ExternalID expected", XMLParserException::BAD_XML_ERR); } } }; // ****************************************************************************** bool XMLParser::matchProduction75ExternalID( XMLString& PubidLiteral, XMLString& SystemLiteral) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction75ExternalID\n"); } if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"SYSTEM")) { // it is a SYSTEM declaration matchProduction03SDeep(1); matchProduction11SystemLiteral(SystemLiteral); } else if(matchProductionFixedString((*XMLEntityStreamStack.begin()),"PUBLIC")) { // it is a PUBLIC declaration matchProduction03SDeep(1); matchProduction12PubidLiteral(PubidLiteral); matchProduction03SDeep(1); matchProduction11SystemLiteral(SystemLiteral); } else return 0; return 1; }; // ****************************************************************************** bool XMLParser::matchProduction76NDataDecl( XMLString& NotationName) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction76NDataDecl\n"); } list lastXMLEntityStreamStack; list lastStreamsPosition; storeStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); if(matchProduction03SDeep(0)==0) { return 0; } if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"NDATA")) { // no NDATA therefore not a NDataDecl restoreStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); return 0; } // critical point matchProduction03SDeep(1); matchProduction05Name((*XMLEntityStreamStack.begin()),NotationName); return 1; }; // ****************************************************************************** void XMLParser::matchProduction77TextDecl( XMLEntityStream *const thisStream, XMLString& VersionNum, XMLString& EncName) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction77TextDecl\n"); } StreamPositionStruct lastStreamPos = thisStream->streamPos; if(!matchProductionFixedString(thisStream," not a TextDecl => back out thisStream->streamPos = lastStreamPos; return; } // critical point matchProduction24VersionInfo(thisStream,VersionNum); matchProduction80EncodingDecl(thisStream,EncName); matchProduction03S(thisStream,0); if(!matchProductionFixedString(thisStream,"?>")) { // TextDecl incorrectly terminated throw XMLParserException(&XMLEntityStreamStack,"'?>' expected", XMLParserException::BAD_XML_ERR); } }; // ****************************************************************************** bool XMLParser::matchProduction80EncodingDecl( XMLEntityStream *const thisStream, XMLString& EncName) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction80EncodingDecl\n"); } StreamPositionStruct lastStreamPos = thisStream->streamPos; if(matchProduction03S(thisStream,0)==0) { return 0; // there was no white space } if(!matchProductionFixedString(thisStream,"encoding")) { // back out thisStream->streamPos = lastStreamPos; return 0; } // critical point matchProduction25Eq(thisStream); matchProduction81EncName(thisStream,EncName); return 1; }; // ****************************************************************************** void XMLParser::matchProduction81EncName( XMLEntityStream *const thisStream, XMLString& EncName) { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction81EncName\n"); } matchProductionQuotedString(thisStream,EncName); if(!EncName.isEncName()) { // isn't an EncName thisStream->streamPos.columnNumber -= EncName.length() + 1; throw XMLParserException(&XMLEntityStreamStack,"not a valid Encoding name", XMLParserException::BAD_XML_ERR); } if(DEBUGXMLPARSER) { printf("EncName = '%s'\n",EncName.c_str()); } }; // ****************************************************************************** bool XMLParser::matchProduction82NotationDecl() { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction82NotationDecl\n"); } const XMLEntityStream *const enteringStream = (*XMLEntityStreamStack.begin()); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"")) { // not correctly terminated throw XMLParserException(&XMLEntityStreamStack,"'>' expected", XMLParserException::BAD_XML_ERR); } return 1; }; // ****************************************************************************** bool XMLParser::matchProduction83PublicID( XMLString& PubidLiteral) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProduction83PublicID\n"); } // this production is a special case of the 75ExternalID production in which // the systemliteral is not required -- a bit tricky to pick this one up! list lastXMLEntityStreamStack; list lastStreamsPosition; storeStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); if(!matchProductionFixedString((*XMLEntityStreamStack.begin()),"PUBLIC")) { return 0; } matchProduction03SDeep(1); matchProduction12PubidLiteral(PubidLiteral); matchProduction03SDeep(0); char c=(*XMLEntityStreamStack.begin())->nextChar(); if(c!='>') { // back out restoreStreamPos(lastXMLEntityStreamStack,lastStreamsPosition); return 0; } (*XMLEntityStreamStack.begin())->streamPos.count--; (*XMLEntityStreamStack.begin())->streamPos.columnNumber--; return 1; }; // ****************************************************************************** long XMLParser::howFarTo( const char* pattern) { if(DEBUGXMLPARSER) { printf("XMLParser::howFarTo '%s'\n",pattern); } StreamPositionStruct lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; // return if pattern null pointer if(pattern==0) { return 0; } // get pattern length long patternLength=0; while(!(pattern[patternLength]==0)) { patternLength++; } // return if pattern empty string if(patternLength==0) { return 0; } // create test pattern and load from file long i; //char c; signed char c; char* testPattern = new char[patternLength+1]; for(i=0;inextChar())==EOF) { delete testPattern; throw XMLException(XMLException::UNEXPECTED_EOF_ERR); } testPattern[i]=c; } testPattern[patternLength]=0; // now step testpattern to the right until match is found long distance=0; while(strcmp(testPattern,pattern)) { if((c=(*XMLEntityStreamStack.begin())->nextChar())==EOF) { delete testPattern; throw XMLException(XMLException::UNEXPECTED_EOF_ERR); } for(i=0;istreamPos = lastStreamPos; return distance; }; // ****************************************************************************** bool XMLParser::matchProductionFixedString( XMLEntityStream *const thisStream, const char* pattern) { // this production is optional if(DEBUGXMLPARSER) { printf("XMLParser::matchProductionFixedString '%s'\n",pattern); } long length=0; while(!(pattern[length]==0)) { length++; } if(length==0) { return 1; } StreamPositionStruct lastStreamPos = thisStream->streamPos; XMLString testString; loadNChar(thisStream,testString,length); if(testString==pattern) { return 1; } thisStream->streamPos=lastStreamPos; return 0; }; // ****************************************************************************** void XMLParser::matchProductionQuotedString( XMLEntityStream *const thisStream, XMLString& quotedString) const { // this production is required if(DEBUGXMLPARSER) { printf("XMLParser::matchProductionQuotedString\n"); } StreamPositionStruct lastStreamPos1 = thisStream->streamPos; //char c=thisStream->nextChar(); signed char c=thisStream->nextChar(); if(!((c==0x22)|(c==0x27))) { thisStream->streamPos = lastStreamPos1; throw XMLParserException(&XMLEntityStreamStack,"Single or double quote expected", XMLParserException::BAD_XML_ERR); } //char quoteUsed = c; signed char quoteUsed = c; StreamPositionStruct lastStreamPos2 = thisStream->streamPos; long length=0; c=thisStream->nextChar(); while(!(c==quoteUsed)&(c!=EOF)) { length++; c=thisStream->nextChar(); } if(c!=quoteUsed) { throw XMLParserException(&XMLEntityStreamStack,"Unexpected end of stream", XMLParserException::BAD_XML_ERR); } thisStream->streamPos = lastStreamPos2; char* s = new char[length+1]; for(long i=0; inextChar(); } s[length]=0; quotedString=s; delete s; c=thisStream->nextChar(); }; // ****************************************************************************** unsigned long XMLParser::sweepContent( char* s) { if(DEBUGXMLPARSER) { printf("XMLParser::sweepContent\n"); } // this routine sweeps through element content and returns the length of the // content. It is then called a second time with the appropriate memory // allocated to s, and loads the data into s //char c; signed char c; XMLEntityStream* testNextXMLEntityStream; unsigned long refLength; XMLString refName; StreamPositionStruct lastStreamPos; unsigned long length = 0; bool cont = 1; while(cont) { lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; c=(*XMLEntityStreamStack.begin())->nextChar(); while(c==EOF) { if(XMLEntityStreamStack.size()==1) { throw XMLParserException(&XMLEntityStreamStack,"Unexpected end of file", XMLParserException::BAD_XML_ERR); } XMLEntityStreamStack.pop_front(); lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; c=(*XMLEntityStreamStack.begin())->nextChar(); } while(c=='&') { // need to expand character and general entity references (*XMLEntityStreamStack.begin())->streamPos.count--; (*XMLEntityStreamStack.begin())->streamPos.columnNumber--; refLength=matchProduction66CharRef((*XMLEntityStreamStack.begin()),c); if(refLength>0) { // it was a character reference if(s!=0) { s[length]=c; } length++; } else { // must be a general entity reference refLength=matchProduction68EntityRef((*XMLEntityStreamStack.begin()),refName); testNextXMLEntityStream = (*XMLEntityStreamStack.begin())->getXMLEntityStream(refName, XMLEntityStream::GENERAL_ENTITY); if(testNextXMLEntityStream==0) { (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; sprintf(errormessage,"General entity '%s' unknown",refName.c_str()); throw XMLParserException(&XMLEntityStreamStack,errormessage, XMLParserException::BAD_XML_ERR); } XMLEntityStreamStack.push_front(testNextXMLEntityStream); } lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; c=(*XMLEntityStreamStack.begin())->nextChar(); while(c==EOF) { if(XMLEntityStreamStack.size()==1) { throw XMLParserException(&XMLEntityStreamStack,"Unexpected end of file", XMLParserException::BAD_XML_ERR); } XMLEntityStreamStack.pop_front(); lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; c=(*XMLEntityStreamStack.begin())->nextChar(); } } cont = XMLChar::isCharData(c); if(cont) { if(s!=0) { s[length]=c; } length++; } } (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; if(s!=0) { s[length]=0; } return length; }; // ****************************************************************************** unsigned long XMLParser::sweepAttValue( char* s) { if(DEBUGXMLPARSER) { printf("XMLParser::sweepAttValue\n"); } // this routine sweeps through the AttValue content and returns the length of // the content. It is then called a second time with the appropriate memory // allocated to s, and loads the data into s // note it uses the current entity stream, assuming that it is already // positioned just before the opening quote. //char c; signed char c; XMLEntityStream* testNextXMLEntityStream; unsigned long refLength; XMLString refName; StreamPositionStruct lastStreamPos; unsigned long length = 0; //char quoteUsed = (*XMLEntityStreamStack.begin())->nextChar(); signed char quoteUsed = (*XMLEntityStreamStack.begin())->nextChar(); const XMLEntityStream *const enteringStream = (*XMLEntityStreamStack.begin()); bool cont = 1; while(cont) { lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; c=(*XMLEntityStreamStack.begin())->nextChar(); while(c==EOF) { if(XMLEntityStreamStack.size()==1) { throw XMLParserException(&XMLEntityStreamStack,"Unexpected end of file", XMLParserException::BAD_XML_ERR); } XMLEntityStreamStack.pop_front(); lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; c=(*XMLEntityStreamStack.begin())->nextChar(); } while(c=='&') { // need to expand character and general entity references (*XMLEntityStreamStack.begin())->streamPos.count--; (*XMLEntityStreamStack.begin())->streamPos.columnNumber--; refLength=matchProduction66CharRef((*XMLEntityStreamStack.begin()),c); if(refLength>0) { // it was a character reference if(s!=0) { s[length]=c; length++; } } else { // must be a general entity reference refLength=matchProduction68EntityRef((*XMLEntityStreamStack.begin()),refName); testNextXMLEntityStream = (*XMLEntityStreamStack.begin())->getXMLEntityStream(refName,XMLEntityStream::GENERAL_ENTITY); if(testNextXMLEntityStream==0) { (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; sprintf(errormessage,"General entity '%s' unknown",refName.c_str()); throw XMLParserException(&XMLEntityStreamStack,errormessage, XMLParserException::BAD_XML_ERR); } if(testNextXMLEntityStream->entityLocation()==XMLEntityStream::EXTERNAL_ENTITY) { (*XMLEntityStreamStack.begin())->streamPos = lastStreamPos; sprintf(errormessage, "Reference to external entity '%s' not allowed in AttValue", refName.c_str()); throw XMLParserException(&XMLEntityStreamStack,errormessage, XMLParserException::BAD_XML_ERR); } XMLEntityStreamStack.push_front(testNextXMLEntityStream); } lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; c=(*XMLEntityStreamStack.begin())->nextChar(); while(c==EOF) { if(XMLEntityStreamStack.size()==1) { throw XMLParserException(&XMLEntityStreamStack,"Unexpected end of file", XMLParserException::BAD_XML_ERR); } XMLEntityStreamStack.pop_front(); lastStreamPos = (*XMLEntityStreamStack.begin())->streamPos; c=(*XMLEntityStreamStack.begin())->nextChar(); } } cont = XMLChar::isCharData(c) &!((c==quoteUsed)&((*XMLEntityStreamStack.begin())==enteringStream)); if(cont) { if(s!=0) { s[length]=c; } length++; } } if(s!=0) { s[length]=0; } return length; }; // ****************************************************************************** void XMLParser::loadNChar( XMLEntityStream *const thisStream, XMLString& outString, const unsigned long& length) const { if(DEBUGXMLPARSER) { printf("XMLParser::loadNChar\n"); } char* s = new char[length+1]; for(unsigned long i=0;inextChar(); } s[length]=0; outString=s; delete s; }; // ****************************************************************************** void XMLParser::storeStreamPos( list& lastXMLEntityStreamStack, list& andTheirPositions) { if(DEBUGXMLPARSER) { printf("XMLParser::storeStreamPos\n"); } lastXMLEntityStreamStack.clear(); andTheirPositions.clear(); for(list::const_iterator ppXMLEntityStream = XMLEntityStreamStack.begin(); ppXMLEntityStream != XMLEntityStreamStack.end(); ppXMLEntityStream++) { lastXMLEntityStreamStack.push_back(*ppXMLEntityStream); andTheirPositions.push_back((*ppXMLEntityStream)->streamPos); } }; // ****************************************************************************** void XMLParser::restoreStreamPos( const list& lastXMLEntityStreamStack, const list& andTheirPositions) { if(DEBUGXMLPARSER) { printf("XMLParser::restoreStreamPos\n"); } XMLEntityStreamStack.clear(); list::const_iterator ppXMLEntityStream; ppXMLEntityStream = lastXMLEntityStreamStack.begin(); list::const_iterator pStreamPositionStruct; pStreamPositionStruct = andTheirPositions.begin(); while(ppXMLEntityStream != lastXMLEntityStreamStack.end()) { XMLEntityStreamStack.push_back(*ppXMLEntityStream); (*ppXMLEntityStream)->streamPos = *pStreamPositionStruct; ppXMLEntityStream++; pStreamPositionStruct++; } }; // ****************************************************************************** void XMLParser::printEntityStreamStack() const { if(DEBUGXMLPARSER) { printf("XMLParser::printEntityStreamStack\n"); } for(list::const_iterator ppXMLEntityStream = XMLEntityStreamStack.begin(); ppXMLEntityStream != XMLEntityStreamStack.end(); ppXMLEntityStream++) { printf(" %s,%li,%li\n",(*ppXMLEntityStream)->name()->c_str(),(*ppXMLEntityStream)->streamPos.lineNumber, (*ppXMLEntityStream)->streamPos.columnNumber); } };