ReaderMgr.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:33k
- /*
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 1999-2000 The Apache Software Foundation. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Xerces" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation, and was
- * originally based on software copyright (c) 1999, International
- * Business Machines, Inc., http://www.ibm.com . For more information
- * on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- */
- /*
- * $Id: ReaderMgr.cpp,v 1.15 2003/05/18 14:02:04 knoaman Exp $
- */
- // ---------------------------------------------------------------------------
- // Includes
- // ---------------------------------------------------------------------------
- #include <xercesc/util/BinMemInputStream.hpp>
- #include <xercesc/util/Janitor.hpp>
- #include <xercesc/util/PlatformUtils.hpp>
- #include <xercesc/util/RuntimeException.hpp>
- #include <xercesc/util/UnexpectedEOFException.hpp>
- #include <xercesc/util/XMLURL.hpp>
- #include <xercesc/util/XMLUniDefs.hpp>
- #include <xercesc/util/XMLUni.hpp>
- #include <xercesc/sax/InputSource.hpp>
- #include <xercesc/framework/LocalFileInputSource.hpp>
- #include <xercesc/framework/URLInputSource.hpp>
- #include <xercesc/framework/XMLBuffer.hpp>
- #include <xercesc/framework/XMLDocumentHandler.hpp>
- #include <xercesc/framework/XMLEntityDecl.hpp>
- #include <xercesc/framework/XMLEntityHandler.hpp>
- #include <xercesc/internal/EndOfEntityException.hpp>
- #include <xercesc/internal/ReaderMgr.hpp>
- XERCES_CPP_NAMESPACE_BEGIN
- // ---------------------------------------------------------------------------
- // ReaderMgr: Constructors and Destructor
- // ---------------------------------------------------------------------------
- ReaderMgr::ReaderMgr(MemoryManager* const manager) :
- fCurEntity(0)
- , fCurReader(0)
- , fEntityHandler(0)
- , fEntityStack(0)
- , fNextReaderNum(1)
- , fReaderStack(0)
- , fThrowEOE(false)
- , fXMLVersion(XMLReader::XMLV1_0)
- , fStandardUriConformant(false)
- , fMemoryManager(manager)
- {
- }
- ReaderMgr::~ReaderMgr()
- {
- //
- // Clean up the reader and entity stacks. Note that we don't own the
- // entities, so we don't delete the current entity (and the entity stack
- // does not own its elements either, so deleting it will not delete the
- // entities it still references!)
- //
- delete fCurReader;
- delete fReaderStack;
- delete fEntityStack;
- }
- // ---------------------------------------------------------------------------
- // ReaderMgr: Getter methods
- // ---------------------------------------------------------------------------
- bool ReaderMgr::isEmpty() const
- {
- return fReaderStack->empty();
- }
- // ---------------------------------------------------------------------------
- // ReaderMgr: Scanning APIs
- // ---------------------------------------------------------------------------
- XMLCh ReaderMgr::getNextChar()
- {
- XMLCh chRet;
- if (fCurReader->getNextChar(chRet))
- return chRet;
- //
- // Didn't get anything back so this reader is hosed. So lets move to
- // the next reader on the stack. If this fails, it will be because
- // its the end of the original file, and we just return zero.
- //
- // If its the end of an entity and fThrowEOE is set, it will throw out
- // of here. Otherwise, it will take us down to the next reader and
- // we'll have more chars.
- //
- if (!popReader())
- return XMLCh(0);
- // Else try again and return the new character
- fCurReader->getNextChar(chRet);
- return chRet;
- }
- void ReaderMgr::getSpaces(XMLBuffer& toFill)
- {
- // Reset the buffer before we start
- toFill.reset();
- while (true)
- {
- //
- // Get all the spaces from the current reader. If it returns true,
- // it hit a non-space and we are done. Else we have to pop a reader
- // and keep going.
- //
- if (fCurReader->getSpaces(toFill))
- break;
- // We wore that one out, so lets pop a reader and try again
- if (!popReader())
- break;
- }
- }
- void ReaderMgr::getUpToCharOrWS(XMLBuffer& toFill, const XMLCh toCheck)
- {
- // Reset the target buffer before we start
- toFill.reset();
- //
- // Ok, enter a loop where we ask the current reader to get chars until
- // it meets the criteria. It returns false if it came back due to eating
- // up all of its data. Else it returned because something matched, and
- // we are done.
- //
- while (true)
- {
- if (fCurReader->getUpToCharOrWS(toFill, toCheck))
- break;
- // We ate that one up, lets try to pop another. If not, break out
- if (!popReader())
- break;
- }
- }
- XMLCh ReaderMgr::peekNextChar()
- {
- XMLCh chRet;
- if (fCurReader->peekNextChar(chRet))
- return chRet;
- //
- // Didn't get anything back so this reader is hosed. So lets move to
- // the next reader on the stack. If this fails, it will be because
- // its the end of the original file, and we just return zero.
- //
- if (!popReader())
- return XMLCh(0);
- // Else peek again and return the character
- fCurReader->peekNextChar(chRet);
- return chRet;
- }
- bool ReaderMgr::skippedChar(const XMLCh toCheck)
- {
- while (true)
- {
- // If we get it, then just return true now
- if (fCurReader->skippedChar(toCheck))
- return true;
- //
- // Check to see if we hit end of input on this reader. If so, then
- // lets pop and try again. Else, we failed. If we cannot pop another
- // then we failed.
- //
- if (!fCurReader->getNoMoreFlag())
- break;
- if (!popReader())
- break;
- }
- return false;
- }
- bool ReaderMgr::skippedSpace()
- {
- while (true)
- {
- // If we get it, then just return true now
- if (fCurReader->skippedSpace())
- return true;
- //
- // Check to see if we hit end of input on this reader. If so, then
- // lets pop and try again. Else, we failed. If we cannot pop another
- // then we failed.
- //
- if (!fCurReader->getNoMoreFlag())
- break;
- if (!popReader())
- break;
- }
- return false;
- }
- bool ReaderMgr::skipIfQuote(XMLCh& chGotten)
- {
- while (true)
- {
- // If we get it, then just return true now
- if (fCurReader->skipIfQuote(chGotten))
- return true;
- //
- // Check to see if we hit end of input on this reader. If so, then
- // lets pop and try again. Else, we failed. If we cannot pop another
- // then we failed.
- //
- if (!fCurReader->getNoMoreFlag())
- break;
- if (!popReader())
- break;
- }
- return false;
- }
- bool ReaderMgr::skipPastSpaces()
- {
- bool skippedSomething = false;
- bool tmpFlag;
- while (true)
- {
- //
- // Skip all the spaces in the current reader. If it returned because
- // it hit a non-space, break out. Else we have to pop another entity
- // and keep going.
- //
- if (fCurReader->skipSpaces(tmpFlag))
- break;
- if (tmpFlag)
- skippedSomething = true;
- // Try to pop another enitity. If we can't then we are done
- if (!popReader())
- break;
- }
- return (tmpFlag || skippedSomething);
- }
- void ReaderMgr::skipQuotedString(const XMLCh quoteCh)
- {
- XMLCh nextCh;
- while (true)
- {
- nextCh = getNextChar();
- // If we get an end of file char, then return
- if (!nextCh)
- break;
- // If we get the quote char, then break out
- if (nextCh == quoteCh)
- break;
- }
- }
- XMLCh ReaderMgr::skipUntilIn(const XMLCh* const listToSkip)
- {
- XMLCh nextCh;
- while (true)
- {
- nextCh = peekNextChar();
- if (!nextCh)
- break;
- if (XMLString::indexOf(listToSkip, nextCh) != -1)
- break;
- // Its one of ours so eat it
- getNextChar();
- }
- return nextCh;
- }
- XMLCh ReaderMgr::skipUntilInOrWS(const XMLCh* const listToSkip)
- {
- XMLCh nextCh;
- while (true)
- {
- nextCh = peekNextChar();
- if (!nextCh)
- break;
- if (fCurReader->isWhitespace(nextCh))
- break;
- if (XMLString::indexOf(listToSkip, nextCh) != -1)
- break;
- // Its one of ours, so eat it
- getNextChar();
- }
- return nextCh;
- }
- // ---------------------------------------------------------------------------
- // ReaderMgr: Control methods
- // ---------------------------------------------------------------------------
- //
- // If the reader stack is empty, then there is only the original main XML
- // entity left. If its empty, then we have no more input.
- //
- bool ReaderMgr::atEOF() const
- {
- return fReaderStack->empty() && fCurReader->getNoMoreFlag();
- }
- //
- // This method is called in the case of errors to clean up the stack when
- // entities have been incorrectly left on the stack due to syntax errors.
- // It just cleans back the stack, and sends no entity events.
- //
- void ReaderMgr::cleanStackBackTo(const unsigned int readerNum)
- {
- //
- // Just start popping readers until we find the one with the indicated
- // reader number.
- //
- while (true)
- {
- if (fCurReader->getReaderNum() == readerNum)
- break;
- if (fReaderStack->empty())
- ThrowXML(RuntimeException, XMLExcepts::RdrMgr_ReaderIdNotFound);
- delete fCurReader;
- fCurReader = fReaderStack->pop();
- fCurEntity = fEntityStack->pop();
- }
- }
- XMLReader* ReaderMgr::createReader( const InputSource& src
- , const bool xmlDecl
- , const XMLReader::RefFrom refFrom
- , const XMLReader::Types type
- , const XMLReader::Sources source
- , const bool calcSrcOfs)
- {
- //
- // Ask the input source to create us an input stream. The particular
- // type of input source will know what kind to create.
- //
- BinInputStream* newStream = src.makeStream();
- if (!newStream)
- return 0;
- //
- // Create a new reader and return it. If the source has an encoding that
- // it wants to force, then we call the constructor that does that.
- // Otherwise, we just call the one that provides the provisional encoding
- // to be possibly updated later by the encoding="" setting.
- //
- XMLReader* retVal = 0;
- // XMLReader ctor invokes refreshRawBuffer() which calls
- // newStream->readBytes().
- // This readBytes() may throw exception, which neither
- // refresRawBuffer(), nor XMLReader ctor catches.
- // We need to handle this exception to avoid leak on newStream.
- try {
- if (src.getEncoding())
- {
- retVal = new (fMemoryManager) XMLReader
- (
- src.getPublicId()
- , src.getSystemId()
- , newStream
- , src.getEncoding()
- , refFrom
- , type
- , source
- , false
- , calcSrcOfs
- , fXMLVersion
- , fMemoryManager
- );
- }
- else
- {
- retVal = new (fMemoryManager) XMLReader
- (
- src.getPublicId()
- , src.getSystemId()
- , newStream
- , refFrom
- , type
- , source
- , false
- , calcSrcOfs
- , fXMLVersion
- , fMemoryManager
- );
- }
- }
- catch (...) //NetAccessorException&
- {
- delete newStream;
- throw;
- }
- // If it failed for any reason, then return zero.
- if (!retVal) {
- delete newStream;
- return 0;
- }
- // Set the next available reader number on this reader
- retVal->setReaderNum(fNextReaderNum++);
- return retVal;
- }
- XMLReader* ReaderMgr::createReader( const XMLCh* const sysId
- , const XMLCh* const pubId
- , const bool xmlDecl
- , const XMLReader::RefFrom refFrom
- , const XMLReader::Types type
- , const XMLReader::Sources source
- , InputSource*& srcToFill
- , const bool calcSrcOfs)
- {
- // Create a buffer for expanding the system id
- XMLBuffer expSysId(1023, fMemoryManager);
- //
- // Allow the entity handler to expand the system id if they choose
- // to do so.
- //
- if (fEntityHandler)
- {
- if (!fEntityHandler->expandSystemId(sysId, expSysId))
- expSysId.set(sysId);
- }
- else
- {
- expSysId.set(sysId);
- }
- // Call the entity resolver interface to get an input source
- srcToFill = 0;
- if (fEntityHandler)
- {
- srcToFill = fEntityHandler->resolveEntity
- (
- pubId
- , expSysId.getRawBuffer()
- );
- }
- //
- // If they didn't create a source via the entity resolver, then we
- // have to create one on our own.
- //
- if (!srcToFill)
- {
- LastExtEntityInfo lastInfo;
- getLastExtEntityInfo(lastInfo);
- try
- {
- XMLURL urlTmp(lastInfo.systemId, expSysId.getRawBuffer());
- if (urlTmp.isRelative())
- {
- ThrowXML
- (
- MalformedURLException
- , XMLExcepts::URL_NoProtocolPresent
- );
- }
- else {
- if (fStandardUriConformant && urlTmp.hasInvalidChar())
- ThrowXML(MalformedURLException, XMLExcepts::URL_MalformedURL);
- srcToFill = new (fMemoryManager) URLInputSource(urlTmp, fMemoryManager);
- }
- }
- catch(const MalformedURLException& e)
- {
- // Its not a URL, so lets assume its a local file name if non-standard uri is allowed
- if (!fStandardUriConformant)
- srcToFill = new (fMemoryManager) LocalFileInputSource
- (
- lastInfo.systemId
- , expSysId.getRawBuffer()
- , fMemoryManager
- );
- else
- throw e;
- }
- }
- // Put a janitor on the input source
- Janitor<InputSource> janSrc(srcToFill);
- //
- // Now call the other version with the input source that we have, and
- // return the resulting reader.
- //
- XMLReader* retVal = createReader
- (
- *srcToFill
- , xmlDecl
- , refFrom
- , type
- , source
- , calcSrcOfs
- );
- // Either way, we can release the input source now
- janSrc.orphan();
- // If it failed for any reason, then return zero.
- if (!retVal)
- return 0;
- // Give this reader the next available reader number and return it
- retVal->setReaderNum(fNextReaderNum++);
- return retVal;
- }
- XMLReader* ReaderMgr::createReader( const XMLCh* const baseURI
- , const XMLCh* const sysId
- , const XMLCh* const pubId
- , const bool xmlDecl
- , const XMLReader::RefFrom refFrom
- , const XMLReader::Types type
- , const XMLReader::Sources source
- , InputSource*& srcToFill
- , const bool calcSrcOfs)
- {
- // Create a buffer for expanding the system id
- XMLBuffer expSysId(1023, fMemoryManager);
- //
- // Allow the entity handler to expand the system id if they choose
- // to do so.
- //
- if (fEntityHandler)
- {
- if (!fEntityHandler->expandSystemId(sysId, expSysId))
- expSysId.set(sysId);
- }
- else
- {
- expSysId.set(sysId);
- }
- // Call the entity resolver interface to get an input source
- srcToFill = 0;
- if (fEntityHandler)
- {
- srcToFill = fEntityHandler->resolveEntity
- (
- pubId
- , expSysId.getRawBuffer()
- );
- }
- //
- // If they didn't create a source via the entity resolver, then we
- // have to create one on our own.
- //
- if (!srcToFill)
- {
- LastExtEntityInfo lastInfo;
- getLastExtEntityInfo(lastInfo);
- try
- {
- XMLURL urlTmp((!baseURI || !*baseURI) ? lastInfo.systemId : baseURI, expSysId.getRawBuffer());
- if (urlTmp.isRelative())
- {
- ThrowXML
- (
- MalformedURLException
- , XMLExcepts::URL_NoProtocolPresent
- );
- }
- else {
- if (fStandardUriConformant && urlTmp.hasInvalidChar())
- ThrowXML(MalformedURLException, XMLExcepts::URL_MalformedURL);
- srcToFill = new (fMemoryManager) URLInputSource(urlTmp, fMemoryManager);
- }
- }
- catch(const MalformedURLException& e)
- {
- // Its not a URL, so lets assume its a local file name if non-standard uri is allowed
- if (!fStandardUriConformant)
- srcToFill = new (fMemoryManager) LocalFileInputSource
- (
- lastInfo.systemId
- , expSysId.getRawBuffer()
- , fMemoryManager
- );
- else
- throw e;
- }
- }
- // Put a janitor on the input source
- Janitor<InputSource> janSrc(srcToFill);
- //
- // Now call the other version with the input source that we have, and
- // return the resulting reader.
- //
- XMLReader* retVal = createReader
- (
- *srcToFill
- , xmlDecl
- , refFrom
- , type
- , source
- , calcSrcOfs
- );
- // Either way, we can release the input source now
- janSrc.orphan();
- // If it failed for any reason, then return zero.
- if (!retVal)
- return 0;
- // Give this reader the next available reader number and return it
- retVal->setReaderNum(fNextReaderNum++);
- return retVal;
- }
- XMLReader*
- ReaderMgr::createIntEntReader( const XMLCh* const sysId
- , const XMLReader::RefFrom refFrom
- , const XMLReader::Types type
- , const XMLCh* const dataBuf
- , const unsigned int dataLen
- , const bool copyBuf
- , const bool calcSrcOfs)
- {
- //
- // This one is easy, we just create an input stream for the data and
- // provide a few extra goodies.
- //
- // NOTE: We use a special encoding string that will be recognized
- // as a 'do nothing' transcoder for the already internalized XMLCh
- // data that makes up an internal entity.
- //
- BinMemInputStream* newStream = new (fMemoryManager) BinMemInputStream
- (
- (const XMLByte*)dataBuf
- , dataLen * sizeof(XMLCh)
- , copyBuf ? BinMemInputStream::BufOpt_Copy
- : BinMemInputStream::BufOpt_Reference
- , fMemoryManager
- );
- if (!newStream)
- return 0;
- XMLReader* retVal = new (fMemoryManager) XMLReader
- (
- sysId
- , 0
- , newStream
- , XMLRecognizer::XERCES_XMLCH
- , refFrom
- , type
- , XMLReader::Source_Internal
- , false
- , calcSrcOfs
- , fXMLVersion
- , fMemoryManager
- );
- // If it failed for any reason, then return zero.
- if (!retVal) {
- delete newStream;
- return 0;
- }
- // Set the reader number to the next available number
- retVal->setReaderNum(fNextReaderNum++);
- return retVal;
- }
- const XMLCh* ReaderMgr::getCurrentEncodingStr() const
- {
- const XMLEntityDecl* theEntity;
- const XMLReader* theReader = getLastExtEntity(theEntity);
- return theReader->getEncodingStr();
- }
- const XMLEntityDecl* ReaderMgr::getCurrentEntity() const
- {
- return fCurEntity;
- }
- XMLEntityDecl* ReaderMgr::getCurrentEntity()
- {
- return fCurEntity;
- }
- const XMLReader* ReaderMgr::getCurrentReader() const
- {
- return fCurReader;
- }
- XMLReader* ReaderMgr::getCurrentReader()
- {
- return fCurReader;
- }
- unsigned int ReaderMgr::getReaderDepth() const
- {
- // If the stack doesn't exist, its obviously zero
- if (!fEntityStack)
- return 0;
- //
- // The return is the stack size, plus one if there is a current
- // reader. So if there is no current reader and none on the stack,
- // its zero, else its some non-zero value.
- //
- unsigned int retVal = fEntityStack->size();
- if (fCurReader)
- retVal++;
- return retVal;
- }
- void ReaderMgr::getLastExtEntityInfo(LastExtEntityInfo& lastInfo) const
- {
- //
- // If the reader stack never got created or we've not managed to open any
- // main entity yet, then we can't give this information.
- //
- if (!fReaderStack || !fCurReader)
- {
- lastInfo.systemId = XMLUni::fgZeroLenString;
- lastInfo.publicId = XMLUni::fgZeroLenString;
- lastInfo.lineNumber = 0;
- lastInfo.colNumber = 0;
- return;
- }
- // We have at least one entity so get the data
- const XMLEntityDecl* theEntity;
- const XMLReader* theReader = getLastExtEntity(theEntity);
- // Fill in the info structure with the reader we found
- lastInfo.systemId = theReader->getSystemId();
- lastInfo.publicId = theReader->getPublicId();
- lastInfo.lineNumber = theReader->getLineNumber();
- lastInfo.colNumber = theReader->getColumnNumber();
- }
- bool ReaderMgr::isScanningPERefOutOfLiteral() const
- {
- // If the current reader is not for an entity, then definitely not
- if (!fCurEntity)
- return false;
- //
- // If this is a PE entity, and its not being expanded in a literal
- // then its true.
- //
- if ((fCurReader->getType() == XMLReader::Type_PE)
- && (fCurReader->getRefFrom() == XMLReader::RefFrom_NonLiteral))
- {
- return true;
- }
- return false;
- }
- bool ReaderMgr::pushReader( XMLReader* const reader
- , XMLEntityDecl* const entity)
- {
- //
- // First, if an entity was passed, we have to confirm that this entity
- // is not already on the entity stack. If so, then this is a recursive
- // entity expansion, so we issue an error and refuse to put the reader
- // on the stack.
- //
- // If there is no entity passed, then its not an entity being pushed, so
- // nothing to do. If there is no entity stack yet, then of coures it
- // cannot already be there.
- //
- if (entity && fEntityStack)
- {
- const unsigned int count = fEntityStack->size();
- const XMLCh* const theName = entity->getName();
- for (unsigned int index = 0; index < count; index++)
- {
- const XMLEntityDecl* curDecl = fEntityStack->elementAt(index);
- if (curDecl)
- {
- if (XMLString::equals(theName, curDecl->getName()))
- {
- // Oops, already there so delete reader and return
- delete reader;
- return false;
- }
- }
- }
- }
- //
- // Fault in the reader stack. Give it an initial capacity of 16, and
- // tell it it does own its elements.
- //
- if (!fReaderStack)
- fReaderStack = new (fMemoryManager) RefStackOf<XMLReader>(16, true, fMemoryManager);
- // And the entity stack, which does not own its elements
- if (!fEntityStack)
- fEntityStack = new (fMemoryManager) RefStackOf<XMLEntityDecl>(16, false, fMemoryManager);
- //
- // Push the current reader and entity onto their respective stacks.
- // Note that the the current entity can be null if the current reader
- // is not for an entity.
- //
- if (fCurReader)
- {
- fReaderStack->push(fCurReader);
- fEntityStack->push(fCurEntity);
- }
- //
- // Make the passed reader and entity the current top of stack. The
- // passed entity can (and often is) null.
- //
- fCurReader = reader;
- fCurEntity = entity;
- return true;
- }
- void ReaderMgr::reset()
- {
- // Reset all of the flags
- fThrowEOE = false;
- // Delete the current reader and flush the reader stack
- delete fCurReader;
- fCurReader = 0;
- if (fReaderStack)
- fReaderStack->removeAllElements();
- //
- // And do the same for the entity stack, but don't delete the current
- // entity (if any) since we don't own them.
- //
- fCurEntity = 0;
- if (fEntityStack)
- fEntityStack->removeAllElements();
- }
- // ---------------------------------------------------------------------------
- // ReaderMgr: Implement the SAX Locator interface
- // ---------------------------------------------------------------------------
- const XMLCh* ReaderMgr::getPublicId() const
- {
- if (!fReaderStack && !fCurReader)
- return XMLUni::fgZeroLenString;
- const XMLEntityDecl* theEntity;
- return getLastExtEntity(theEntity)->getPublicId();
- }
- const XMLCh* ReaderMgr::getSystemId() const
- {
- if (!fReaderStack && !fCurReader)
- return XMLUni::fgZeroLenString;
- const XMLEntityDecl* theEntity;
- return getLastExtEntity(theEntity)->getSystemId();
- }
- XMLSSize_t ReaderMgr::getColumnNumber() const
- {
- if (!fReaderStack && !fCurReader)
- return 0;
- const XMLEntityDecl* theEntity;
- return getLastExtEntity(theEntity)->getColumnNumber();
- }
- XMLSSize_t ReaderMgr::getLineNumber() const
- {
- if (!fReaderStack && !fCurReader)
- return 0;
- const XMLEntityDecl* theEntity;
- return getLastExtEntity(theEntity)->getLineNumber();
- }
- // ---------------------------------------------------------------------------
- // ReaderMgr: Private helper methods
- // ---------------------------------------------------------------------------
- const XMLReader*
- ReaderMgr::getLastExtEntity(const XMLEntityDecl*& itsEntity) const
- {
- //
- // Scan down the reader stack until we find a reader for an entity that
- // is external. First check that there is anything in the stack at all,
- // in which case the current reader is the main file and that's the one
- // that we want.
- //
- const XMLReader* theReader = fCurReader;
- //
- // If there is a current entity and it is not an external entity, then
- // search the stack; else, keep the reader that we've got since its
- // either an external entity reader or the main file reader.
- //
- const XMLEntityDecl* curEntity = fCurEntity;
- if (curEntity && !curEntity->isExternal())
- {
- unsigned int index = fReaderStack->size();
- if (index)
- {
- while (true)
- {
- // Move down to the previous element and get a pointer to it
- index--;
- curEntity = fEntityStack->elementAt(index);
- //
- // If its null or its an external entity, then this reader
- // is what we want, so break out with that one.
- //
- if (!curEntity)
- {
- theReader = fReaderStack->elementAt(index);
- break;
- }
- else if (curEntity->isExternal())
- {
- theReader = fReaderStack->elementAt(index);
- break;
- }
- // We hit the end, so leave the main file reader as the one
- if (!index)
- break;
- }
- }
- }
- itsEntity = curEntity;
- return theReader;
- }
- bool ReaderMgr::popReader()
- {
- //
- // We didn't get any more, so try to pop off a reader. If the reader
- // stack is empty, then we are at the end, so return false.
- //
- if (fReaderStack->empty())
- return false;
- //
- // Remember the current entity, before we pop off a new one. We might
- // need this to throw the end of entity exception at the end.
- //
- XMLEntityDecl* prevEntity = fCurEntity;
- const bool prevReaderThrowAtEnd = fCurReader->getThrowAtEnd();
- const unsigned int readerNum = fCurReader->getReaderNum();
- //
- // Delete the current reader and pop a new reader and entity off
- // the stacks.
- //
- delete fCurReader;
- fCurReader = fReaderStack->pop();
- fCurEntity = fEntityStack->pop();
- //
- // If there was a previous entity, and either the fThrowEOE flag is set
- // or reader was marked as such, then throw an end of entity.
- //
- if (prevEntity && fThrowEOE || prevReaderThrowAtEnd)
- throw EndOfEntityException(prevEntity, readerNum);
- while (true)
- {
- //
- // They don't want us to throw, so lets just return with a new
- // reader. Here we have to do a loop because we might have multiple
- // readers on these stack that are empty (i.e. the last char in them
- // was the ';' at the end of the entity ref that caused the next
- // entity to be pushed.
- //
- // So we loop until we find a non-empty reader, or hit the main
- // file entity. If we find one with some chars available, then break
- // out and take that one.
- //
- if (fCurReader->charsLeftInBuffer())
- break;
- fCurReader->refreshCharBuffer();
- if (fCurReader->charsLeftInBuffer())
- break;
- //
- // The current one is hosed. So, if the reader stack is empty we
- // are dead meat and can give up now.
- //
- if (fReaderStack->empty())
- return false;
- // Else pop again and try it one more time
- delete fCurReader;
- fCurReader = fReaderStack->pop();
- fCurEntity = fEntityStack->pop();
- }
- return true;
- }
- XERCES_CPP_NAMESPACE_END