You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xerces.apache.org by kn...@apache.org on 2002/12/04 02:41:15 UTC
cvs commit: xml-xerces/c/src/xercesc/internal XMLScanner.hpp XMLScanner.cpp
knoaman 2002/12/03 17:41:15
Modified: c/src/xercesc/internal XMLScanner.hpp XMLScanner.cpp
Log:
Scanner re-organization.
Revision Changes Path
1.13 +116 -283 xml-xerces/c/src/xercesc/internal/XMLScanner.hpp
Index: XMLScanner.hpp
===================================================================
RCS file: /home/cvs/xml-xerces/c/src/xercesc/internal/XMLScanner.hpp,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- XMLScanner.hpp 4 Nov 2002 14:58:19 -0000 1.12
+++ XMLScanner.hpp 4 Dec 2002 01:41:14 -0000 1.13
@@ -1,7 +1,7 @@
/*
* The Apache Software License, Version 1.1
*
- * Copyright (c) 1999-2001 The Apache Software Foundation. All rights
+ * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -56,6 +56,9 @@
/*
* $Log$
+ * Revision 1.13 2002/12/04 01:41:14 knoaman
+ * Scanner re-organization.
+ *
* Revision 1.12 2002/11/04 14:58:19 tng
* C++ Namespace Support.
*
@@ -236,41 +239,33 @@
#if !defined(XMLSCANNER_HPP)
#define XMLSCANNER_HPP
-#include <xercesc/util/KVStringPair.hpp>
-#include <xercesc/util/RefVectorOf.hpp>
-#include <xercesc/util/XMLString.hpp>
-#include <xercesc/framework/XMLAttr.hpp>
#include <xercesc/framework/XMLBufferMgr.hpp>
#include <xercesc/framework/XMLErrorCodes.hpp>
#include <xercesc/framework/XMLRefInfo.hpp>
-#include <xercesc/framework/XMLPScanToken.hpp>
-#include <xercesc/internal/ElemStack.hpp>
+#include <xercesc/util/NameIdPool.hpp>
+#include <xercesc/util/RefHashTableOf.hpp>
#include <xercesc/internal/ReaderMgr.hpp>
#include <xercesc/validators/DTD/DTDEntityDecl.hpp>
-#include <xercesc/validators/DTD/DTDValidator.hpp>
-#include <xercesc/validators/schema/SchemaValidator.hpp>
+#include <xercesc/framework/XMLAttr.hpp>
+
XERCES_CPP_NAMESPACE_BEGIN
class InputSource;
class XMLDocumentHandler;
-class DocTypeHandler;
-class XMLElementDecl;
class XMLEntityHandler;
-class XMLErrorReporter;
class ErrorHandler;
-class XMLMsgLoader;
+class DocTypeHandler;
+class XMLPScanToken;
+class XMLStringPool;
+class Grammar;
+class GrammarResolver;
class XMLValidator;
-class ValueStoreCache;
-class XPathMatcherStack;
-class FieldActivator;
-class IdentityConstraint;
-//
+
// This is the mondo scanner class, which does the vast majority of the
// work of parsing. It handles reading in input and spitting out events
// to installed handlers.
-//
class XMLPARSER_EXPORT XMLScanner
{
public :
@@ -345,7 +340,7 @@
, XMLErrorReporter* const errReporter
, XMLValidator* const valToAdopt
);
- ~XMLScanner();
+ virtual ~XMLScanner();
// -----------------------------------------------------------------------
@@ -369,6 +364,31 @@
, const char* const text4 = 0
);
+ // -----------------------------------------------------------------------
+ // Public pure virtual methods
+ // -----------------------------------------------------------------------
+ virtual const XMLCh* getName() const = 0;
+ virtual NameIdPool<DTDEntityDecl>* getEntityDeclPool() = 0;
+ virtual const NameIdPool<DTDEntityDecl>* getEntityDeclPool() const = 0;
+ virtual unsigned int resolveQName
+ (
+ const XMLCh* const qName
+ , XMLBuffer& prefixBufToFill
+ , const short mode
+ , int& prefixColonPos
+ ) = 0;
+ virtual void scanDocument
+ (
+ const InputSource& src
+ ) = 0;
+ virtual bool scanNext(XMLPScanToken& toFill) = 0;
+ virtual Grammar* loadGrammar
+ (
+ const InputSource& src
+ , const short grammarType
+ , const bool toCache = false
+ ) = 0;
+
// -----------------------------------------------------------------------
// Getter methods
@@ -390,7 +410,7 @@
RefHashTableOf<XMLRefInfo>* getIDRefList();
const RefHashTableOf<XMLRefInfo>* getIDRefList() const;
bool getInException() const;
- bool getLastExtLocation
+ /*bool getLastExtLocation
(
XMLCh* const sysIdToFill
, const unsigned int maxSysIdChars
@@ -398,7 +418,7 @@
, const unsigned int maxPubIdChars
, XMLSSize_t& lineToFill
, XMLSSize_t& colToFill
- ) const;
+ ) const;*/
const Locator* getLocator() const;
const ReaderMgr* getReaderMgr() const;
unsigned int getSrcOffset() const;
@@ -406,8 +426,6 @@
const XMLValidator* getValidator() const;
XMLValidator* getValidator();
int getErrorCount();
- NameIdPool<DTDEntityDecl>* getEntityDeclPool();
- const NameIdPool<DTDEntityDecl>* getEntityDeclPool() const;
const XMLStringPool* getURIStringPool() const;
XMLStringPool* getURIStringPool();
bool getHasNoDTD() const;
@@ -417,12 +435,12 @@
bool getNormalizeData() const;
bool isCachingGrammarFromParse() const;
bool isUsingCachedGrammarInParse() const;
+ bool getCalculateSrcOfs() const;
Grammar* getRootGrammar() const;
// -----------------------------------------------------------------------
// Getter methods
// -----------------------------------------------------------------------
-
/**
* When an attribute name has no prefix, unlike elements, it is not mapped
* to the global namespace. So, in order to have something to map it to
@@ -474,23 +492,6 @@
const XMLCh* getURIText(const unsigned int uriId) const;
- /**
- * This method separate the passed QName into prefix
- * and local part, and then return the URI id by resolving
- * the prefix.
- *
- * mode: Indicate if this QName comes from an Element or Attribute
- */
- unsigned int resolveQName
- (
- const XMLCh* const qName
- , XMLBuffer& nameBufToFill
- , XMLBuffer& prefixBufToFill
- , const ElemStack::MapModes mode
- );
-
- Grammar* getGrammar(const XMLCh* const nameSpaceKey);
-
/* tell if the validator comes from user */
bool isValidatorFromUser();
@@ -504,6 +505,8 @@
void setEntityHandler(XMLEntityHandler* const docTypeHandler);
void setErrorReporter(XMLErrorReporter* const errHandler);
void setErrorHandler(ErrorHandler* const handler);
+ void setGrammarResolver(GrammarResolver* const grammarResolver);
+ void setURIStringPool(XMLStringPool* const stringPool);
void setExitOnFirstFatal(const bool newValue);
void setValidationConstraintFatal(const bool newValue);
void setValidationScheme(const ValSchemes newScheme);
@@ -520,6 +523,7 @@
void setExternalNoNamespaceSchemaLocation(const char* const noNamespaceSchemaLocation);
void setLoadExternalDTD(const bool loadDTD);
void setNormalizeData(const bool normalizeData);
+ void setCalculateSrcOfs(const bool newValue);
// -----------------------------------------------------------------------
// Mutator methods
@@ -533,7 +537,6 @@
bool getDoValidation() const;
void setDoValidation(const bool validate);
-
// -----------------------------------------------------------------------
// Document scanning methods
//
@@ -542,10 +545,6 @@
// -----------------------------------------------------------------------
void scanDocument
(
- const InputSource& src
- );
- void scanDocument
- (
const XMLCh* const systemId
);
void scanDocument
@@ -569,21 +568,13 @@
, XMLPScanToken& toFill
);
- bool scanNext(XMLPScanToken& toFill);
-
void scanReset(XMLPScanToken& toFill);
bool checkXMLDecl(bool startWithAngle);
// -----------------------------------------------------------------------
// Grammar preparsing methods
- // -----------------------------------------------------------------------
- Grammar* loadGrammar
- (
- const InputSource& src
- , const short grammarType
- , const bool toCache = false
- );
+ // -----------------------------------------------------------------------
Grammar* loadGrammar
(
const XMLCh* const systemId
@@ -598,159 +589,46 @@
);
// -----------------------------------------------------------------------
- // Reset pool of cached grammars
- // -----------------------------------------------------------------------
- void resetCachedGrammarPool();
-
- // -----------------------------------------------------------------------
// Notification that lazy data has been deleted
// -----------------------------------------------------------------------
static void reinitScannerMutex();
-
static void reinitMsgLoader();
-private :
- // -----------------------------------------------------------------------
- // Unimplemented constructors and operators
- // -----------------------------------------------------------------------
- XMLScanner();
- XMLScanner(const XMLScanner&);
- void operator=(const XMLScanner&);
-
-
- // -----------------------------------------------------------------------
- // Private helper methods
- // -----------------------------------------------------------------------
- void commonInit();
- void initValidator(XMLValidator* theValidator);
- void resetURIStringPool();
- InputSource* resolveSystemId(const XMLCh* const sysId); // return owned by caller
-
- // Spaces are not allowed in URI, so %20 is used instead.
- // Convert %20 to spaces before resolving the URI
- void normalizeURI(const XMLCh* const systemURI, XMLBuffer& normalizedURI);
-
+protected:
// -----------------------------------------------------------------------
- // Private helper methods
- //
- // These are implemented in XMLScanner2.cpp, to keep the main file from
- // becoming so bloated. We can't have any bloated files.
+ // Protected pure virtual methods
// -----------------------------------------------------------------------
- unsigned int buildAttList
- (
- const RefVectorOf<KVStringPair>& providedAttrs
- , const unsigned int attCount
- , XMLElementDecl* elemDecl
- , RefVectorOf<XMLAttr>& toFill
- );
- void checkIDRefs();
- bool isLegalToken(const XMLPScanToken& toCheck);
- bool normalizeAttValue
- (
- const XMLAttDef* const attDef
- , const XMLCh* const value
- , XMLBuffer& toFill
- );
- bool normalizeAttRawValue
- (
- const XMLCh* const attrName
- , const XMLCh* const value
- , XMLBuffer& toFill
- );
-
- unsigned int resolvePrefix
- (
- const XMLCh* const prefix
- , const ElemStack::MapModes mode
- );
- unsigned int resolvePrefix
- (
- const XMLCh* const prefix
- , XMLBuffer& uriBufToFill
- , const ElemStack::MapModes mode
- );
- void scanReset(const InputSource& src);
- void sendCharData(XMLBuffer& toSend);
- XMLTokens senseNextToken(unsigned int& orgReader);
- void updateNSMap
+ virtual void scanCDSection() = 0;
+ virtual void scanCharData(XMLBuffer& toToUse) = 0;
+ virtual EntityExpRes scanEntityRef
(
- const XMLCh* const attrName
- , const XMLCh* const attrValue
- );
- void scanRawAttrListforNameSpaces(const RefVectorOf<KVStringPair>* theRawAttrList, int attCount);
- void parseSchemaLocation(const XMLCh* const schemaLocationStr);
- void resolveSchemaGrammar(const XMLCh* const loc, const XMLCh* const uri);
- bool switchGrammar(const XMLCh* const newGrammarNameSpace);
- bool laxElementValidation(QName* element, ContentLeafNameTypeVector* cv,
- const XMLContentModel* const cm,
- const unsigned int parentElemDepth);
- bool anyAttributeValidation(SchemaAttDef* attWildCard,
- unsigned int uriId,
- bool& skipThisOne,
- bool& laxThisOne);
+ const bool inAttVal
+ , XMLCh& firstCh
+ , XMLCh& secondCh
+ , bool& escaped
+ ) = 0;
+ virtual void scanDocTypeDecl() = 0;
+ virtual void scanReset(const InputSource& src) = 0;
+ virtual void sendCharData(XMLBuffer& toSend) = 0;
// -----------------------------------------------------------------------
- // Private scanning methods
+ // Protected scanning methods
// -----------------------------------------------------------------------
- bool basicAttrValueScan
- (
- const XMLCh* const attrName
- , XMLBuffer& toFill
- );
- bool getQuotedString(XMLBuffer& toFill);
- unsigned int rawAttrScan
- (
- const XMLCh* const elemName
- , RefVectorOf<KVStringPair>& toFill
- , bool& isEmpty
- );
- bool scanAttValue
- (
- const XMLAttDef* const attDef
- , XMLBuffer& toFill
- );
- void scanCDSection();
- void scanCharData(XMLBuffer& toToUse);
bool scanCharRef(XMLCh& toFill, XMLCh& second);
void scanComment();
- bool scanContent(const bool extEntity);
- void scanEndTag(bool& gotData);
- EntityExpRes scanEntityRef
- (
- const bool inAttVal
- , XMLCh& firstCh
- , XMLCh& secondCh
- , bool& escaped
- );
bool scanEq();
void scanMiscellaneous();
void scanPI();
void scanProlog();
- bool scanStartTag(bool& gotData);
- bool scanStartTagNS(bool& gotData);
void scanXMLDecl(const DeclTypes type);
- unsigned int scanUpToWSOr
- (
- XMLBuffer& toFill
- , const XMLCh chEndChar
- );
- void scanDocTypeDecl();
// -----------------------------------------------------------------------
// Private helper methods
// -----------------------------------------------------------------------
- void resizeElemState();
-
- // -----------------------------------------------------------------------
- // IdentityConstraints Activation methods
- // -----------------------------------------------------------------------
- void activateSelectorFor(IdentityConstraint* const ic, const int initialDepth);
-
- // -----------------------------------------------------------------------
- // Grammar preparsing methods
- // -----------------------------------------------------------------------
- Grammar* loadXMLSchemaGrammar(const InputSource& src, const bool toCache = false);
- Grammar* loadDTDGrammar(const InputSource& src, const bool toCache = false);
+ void checkIDRefs();
+ bool isLegalToken(const XMLPScanToken& toCheck);
+ XMLTokens senseNextToken(unsigned int& orgReader);
+ void initValidator(XMLValidator* theValidator);
// -----------------------------------------------------------------------
// Data members
@@ -780,10 +658,6 @@
// namespaces or not. If the installed validator indicates that it
// has to do namespaces, then this is ignored.
//
- // fElemStack
- // This is the element stack that is used to track the elements that
- // are currently being worked on.
- //
// fEntityHandler
// The client code's entity handler. If zero, then no entity handler
// callouts are done. We don't adopt it.
@@ -814,11 +688,6 @@
// it, which would normally throw again if the 'fail on first error'
// flag is one.
//
- // fRawAttrList
- // During the initial scan of the attributes we can only do a raw
- // scan for key/value pairs. So this vector is used to store them
- // until they can be processed (and put into fAttrList.)
- //
// fReaderMgr
// This is the reader manager, from which we get characters. It
// manages the reader stack for us, and provides a lot of convenience
@@ -848,12 +717,6 @@
// Either point to user's installed validator, or fDTDValidator
// or fSchemaValidator.
//
- // fDTDValidator
- // The DTD validator instance.
- //
- // fSchemaValidator
- // The Schema validator instance.
- //
// fValidatorFromUser
// This flag indicates whether the validator was installed from
// user. If false, then the validator was created by the Scanner.
@@ -873,9 +736,6 @@
// This flag indicates whether the client code wants full Schema
// constraint checking.
//
- // fSeeXsi
- // This flag indicates a schema has been seen.
- //
// fAttName
// fAttValue
// fCDataBuf
@@ -908,11 +768,6 @@
// fSchemaNamespaceId
// This is the id of the schema namespace URI.
//
- // fElemState
- // fElemStateSize
- // Stores an element next state from DFA content model - used for
- // wildcard validation
- //
// fGrammarResolver
// Grammar Pool that stores all the grammars. Key is namespace for
// schema and system id for external DTD. When caching a grammar, if
@@ -934,18 +789,6 @@
// string pool class. This pool is going to be shared by all Grammar.
// Use only if namespace is turned on.
//
- // fMatcherStack
- // Stack of active XPath matchers for identity constraints. All
- // active XPath matchers are notified of startElement, characters
- // and endElement callbacks in order to perform their matches.
- //
- // fValueStoreCache
- // Cache of value stores for identity constraint fields.
- //
- // fFieldActivator
- // Activates fields within a certain scope when a selector matches
- // its xpath.
- //
// fRootElemName
// No matter we are using DTD or Schema Grammar, if a DOCTYPE exists,
// we need to verify the root element name. So store the rootElement
@@ -968,6 +811,7 @@
// normalization that is defined in the schema.
//
// -----------------------------------------------------------------------
+ bool fCalculateSrcOfs;
bool fDoNamespaces;
bool fExitOnFirstFatal;
bool fValidationConstraintFatal;
@@ -978,58 +822,66 @@
bool fValidatorFromUser;
bool fDoSchema;
bool fSchemaFullChecking;
- bool fSeeXsi;
bool fToCacheGrammar;
bool fUseCachedGrammar;
+ bool fLoadExternalDTD;
+ bool fNormalizeData;
int fErrorCount;
unsigned int fEmptyNamespaceId;
unsigned int fUnknownNamespaceId;
unsigned int fXMLNamespaceId;
unsigned int fXMLNSNamespaceId;
unsigned int fSchemaNamespaceId;
- unsigned int fElemStateSize;
XMLUInt32 fScannerId;
XMLUInt32 fSequenceId;
- unsigned int* fElemState;
RefVectorOf<XMLAttr>* fAttrList;
XMLBufferMgr fBufMgr;
XMLDocumentHandler* fDocHandler;
DocTypeHandler* fDocTypeHandler;
- ElemStack fElemStack;
XMLEntityHandler* fEntityHandler;
XMLErrorReporter* fErrorReporter;
ErrorHandler* fErrorHandler;
RefHashTableOf<XMLRefInfo>* fIDRefList;
- RefVectorOf<KVStringPair>* fRawAttrList;
ReaderMgr fReaderMgr;
XMLValidator* fValidator;
- DTDValidator* fDTDValidator;
- SchemaValidator* fSchemaValidator;
ValSchemes fValScheme;
XMLBuffer fAttNameBuf;
XMLBuffer fAttValueBuf;
XMLBuffer fCDataBuf;
- XMLBuffer fNameBuf;
XMLBuffer fQNameBuf;
XMLBuffer fPrefixBuf;
XMLBuffer fURIBuf;
GrammarResolver* fGrammarResolver;
Grammar* fGrammar;
Grammar* fRootGrammar;
- DTDGrammar* fDTDGrammar;
- Grammar::GrammarType fGrammarType;
XMLStringPool* fURIStringPool;
- XPathMatcherStack* fMatcherStack;
- ValueStoreCache* fValueStoreCache;
- FieldActivator* fFieldActivator;
XMLCh* fRootElemName;
XMLCh* fExternalSchemaLocation;
XMLCh* fExternalNoNamespaceSchemaLocation;
- bool fLoadExternalDTD;
- bool fNormalizeData;
-};
+private :
+ // -----------------------------------------------------------------------
+ // Unimplemented constructors and operators
+ // -----------------------------------------------------------------------
+ XMLScanner();
+ XMLScanner(const XMLScanner&);
+ void operator=(const XMLScanner&);
+ // -----------------------------------------------------------------------
+ // Private helper methods
+ // -----------------------------------------------------------------------
+ void commonInit();
+
+ // -----------------------------------------------------------------------
+ // Private scanning methods
+ // -----------------------------------------------------------------------
+ bool getQuotedString(XMLBuffer& toFill);
+ unsigned int scanUpToWSOr
+ (
+ XMLBuffer& toFill
+ , const XMLCh chEndChar
+ );
+};
// ---------------------------------------------------------------------------
// XMLScanner: Getter methods
@@ -1089,14 +941,14 @@
return fValidationConstraintFatal;
}
-inline RefHashTableOf<XMLRefInfo>* XMLScanner::getIDRefList()
+inline bool XMLScanner::getInException() const
{
- return fIDRefList;
+ return fInException;
}
-inline bool XMLScanner::getInException() const
+inline RefHashTableOf<XMLRefInfo>* XMLScanner::getIDRefList()
{
- return fInException;
+ return fIDRefList;
}
inline const RefHashTableOf<XMLRefInfo>* XMLScanner::getIDRefList() const
@@ -1179,16 +1031,6 @@
return fXMLNSNamespaceId;
}
-inline NameIdPool<DTDEntityDecl>* XMLScanner::getEntityDeclPool()
-{
- return fDTDGrammar->getEntityDeclPool();
-}
-
-inline const NameIdPool<DTDEntityDecl>* XMLScanner::getEntityDeclPool() const
-{
- return fDTDGrammar->getEntityDeclPool();
-}
-
inline const XMLStringPool* XMLScanner::getURIStringPool() const
{
return fURIStringPool;
@@ -1234,14 +1076,14 @@
return fUseCachedGrammar;
}
-inline Grammar* XMLScanner::getRootGrammar() const
+inline bool XMLScanner::getCalculateSrcOfs() const
{
- return fRootGrammar;
+ return fCalculateSrcOfs;
}
-inline Grammar* XMLScanner::getGrammar(const XMLCh* const nameSpaceKey)
+inline Grammar* XMLScanner::getRootGrammar() const
{
- return fGrammarResolver->getGrammar(nameSpaceKey);
+ return fRootGrammar;
}
// ---------------------------------------------------------------------------
@@ -1257,41 +1099,33 @@
fDocTypeHandler = docTypeHandler;
}
-inline void XMLScanner::setDoNamespaces(const bool doNamespaces)
+inline void XMLScanner::setErrorHandler(ErrorHandler* const handler)
{
- fDoNamespaces = doNamespaces;
- if (fDoNamespaces) {
- if (!fURIStringPool) {
- fURIStringPool = new XMLStringPool();
- resetURIStringPool();
- }
- }
+ fErrorHandler = handler;
}
-inline void XMLScanner::setErrorReporter(XMLErrorReporter* const errHandler)
+inline void XMLScanner::setEntityHandler(XMLEntityHandler* const entityHandler)
{
- fErrorReporter = errHandler;
- fDTDValidator->setErrorReporter(fErrorReporter);
- fSchemaValidator->setErrorReporter(fErrorReporter);
+ fEntityHandler = entityHandler;
+ fReaderMgr.setEntityHandler(entityHandler);
}
-inline void XMLScanner::setErrorHandler(ErrorHandler* const handler)
+inline void XMLScanner::setErrorReporter(XMLErrorReporter* const errHandler)
{
- fErrorHandler = handler;
+ fErrorReporter = errHandler;
}
-inline void XMLScanner::setEntityHandler(XMLEntityHandler* const entityHandler)
+inline void XMLScanner::setGrammarResolver(GrammarResolver* const grammarResolver)
{
- fEntityHandler = entityHandler;
- fReaderMgr.setEntityHandler(entityHandler);
+ fGrammarResolver = grammarResolver;
}
inline void XMLScanner::setExitOnFirstFatal(const bool newValue)
{
fExitOnFirstFatal = newValue;
- fSchemaValidator->setExitOnFirstFatal(newValue);
}
+
inline void XMLScanner::setValidationConstraintFatal(const bool newValue)
{
fValidationConstraintFatal = newValue;
@@ -1309,18 +1143,14 @@
fValidate = false;
}
-inline void XMLScanner::setValidator(XMLValidator* const valToAdopt)
+inline void XMLScanner::setDoSchema(const bool doSchema)
{
- if (fValidatorFromUser)
- delete fValidator;
- fValidator = valToAdopt;
- fValidatorFromUser = true;
- initValidator(fValidator);
+ fDoSchema = doSchema;
}
-inline void XMLScanner::setDoSchema(const bool doSchema)
+inline void XMLScanner::setDoNamespaces(const bool doNamespaces)
{
- fDoSchema = doSchema;
+ fDoNamespaces = doNamespaces;
}
inline void XMLScanner::setValidationSchemaFullChecking(const bool schemaFullChecking)
@@ -1383,6 +1213,10 @@
fUseCachedGrammar = newValue;
}
+inline void XMLScanner::setCalculateSrcOfs(const bool newValue)
+{
+ fCalculateSrcOfs = newValue;
+}
// ---------------------------------------------------------------------------
// XMLScanner: Mutator methods
@@ -1391,7 +1225,6 @@
{
++fErrorCount;
}
-
// ---------------------------------------------------------------------------
// XMLScanner: Deprecated methods
1.27 +705 -3384 xml-xerces/c/src/xercesc/internal/XMLScanner.cpp
Index: XMLScanner.cpp
===================================================================
RCS file: /home/cvs/xml-xerces/c/src/xercesc/internal/XMLScanner.cpp,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -r1.26 -r1.27
--- XMLScanner.cpp 26 Nov 2002 20:20:42 -0000 1.26
+++ XMLScanner.cpp 4 Dec 2002 01:41:14 -0000 1.27
@@ -1,7 +1,7 @@
/*
* The Apache Software License, Version 1.1
*
- * Copyright (c) 1999-2001 The Apache Software Foundation. All rights
+ * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,44 +55,31 @@
*/
/*
- * $Id$
+ * $Id$
*/
// ---------------------------------------------------------------------------
// Includes
// ---------------------------------------------------------------------------
+#include <xercesc/internal/XMLScanner.hpp>
#include <xercesc/util/Janitor.hpp>
#include <xercesc/util/Mutexes.hpp>
#include <xercesc/util/PlatformUtils.hpp>
-#include <xercesc/util/RefVectorOf.hpp>
#include <xercesc/util/RuntimeException.hpp>
#include <xercesc/util/UnexpectedEOFException.hpp>
#include <xercesc/util/XMLMsgLoader.hpp>
#include <xercesc/util/XMLRegisterCleanup.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
-#include <xercesc/util/XMLUni.hpp>
-#include <xercesc/util/XMLURL.hpp>
-#include <xercesc/sax/InputSource.hpp>
-#include <xercesc/sax/SAXException.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xercesc/framework/URLInputSource.hpp>
#include <xercesc/framework/XMLDocumentHandler.hpp>
-#include <xercesc/framework/XMLErrorReporter.hpp>
#include <xercesc/framework/XMLEntityHandler.hpp>
#include <xercesc/framework/XMLPScanToken.hpp>
#include <xercesc/framework/XMLValidator.hpp>
-#include <xercesc/framework/XMLValidityCodes.hpp>
-#include <xercesc/internal/XMLScanner.hpp>
#include <xercesc/internal/EndOfEntityException.hpp>
#include <xercesc/validators/DTD/DocTypeHandler.hpp>
-#include <xercesc/validators/DTD/DTDScanner.hpp>
-#include <xercesc/validators/schema/SchemaSymbols.hpp>
-#include <xercesc/validators/schema/identity/FieldActivator.hpp>
-#include <xercesc/validators/schema/identity/XPathMatcherStack.hpp>
-#include <xercesc/validators/schema/identity/ValueStoreCache.hpp>
-#include <xercesc/validators/schema/identity/IC_Selector.hpp>
-#include <xercesc/validators/schema/identity/ValueStore.hpp>
+#include <xercesc/validators/common/GrammarResolver.hpp>
XERCES_CPP_NAMESPACE_BEGIN
@@ -108,35 +95,19 @@
static XMLMsgLoader* gMsgLoader = 0;
static XMLRegisterCleanup cleanupMsgLoader;
-// ---------------------------------------------------------------------------
-// Local const data
-//
-// These are the text for the require char refs that must always be present.
-// We init these into the entity pool upon construction.
-// ---------------------------------------------------------------------------
-static const XMLCh gAmp[] = { chLatin_a, chLatin_m, chLatin_p, chNull };
-static const XMLCh gLT[] = { chLatin_l, chLatin_t, chNull };
-static const XMLCh gGT[] = { chLatin_g, chLatin_t, chNull };
-static const XMLCh gQuot[] = { chLatin_q, chLatin_u, chLatin_o, chLatin_t, chNull };
-static const XMLCh gApos[] = { chLatin_a, chLatin_p, chLatin_o, chLatin_s, chNull };
-
// ---------------------------------------------------------------------------
// Local, static functions
// ---------------------------------------------------------------------------
-// -----------------------------------------------------------------------
// Cleanup for the message loader
-// -----------------------------------------------------------------------
void XMLScanner::reinitMsgLoader()
{
delete gMsgLoader;
gMsgLoader = 0;
}
-// -----------------------------------------------------------------------
// Cleanup for the scanner mutex
-// -----------------------------------------------------------------------
void XMLScanner::reinitScannerMutex()
{
delete sScannerMutex;
@@ -179,7 +150,8 @@
// ---------------------------------------------------------------------------
XMLScanner::XMLScanner(XMLValidator* const valToAdopt) :
- fDoNamespaces(false)
+ fCalculateSrcOfs(true)
+ , fDoNamespaces(false)
, fExitOnFirstFatal(true)
, fValidationConstraintFatal(false)
, fInException(false)
@@ -189,19 +161,18 @@
, fValidatorFromUser(false)
, fDoSchema(false)
, fSchemaFullChecking(false)
- , fSeeXsi(false)
, fToCacheGrammar(false)
, fUseCachedGrammar(false)
+ , fLoadExternalDTD(true)
+ , fNormalizeData(true)
, fErrorCount(0)
, fEmptyNamespaceId(0)
, fUnknownNamespaceId(0)
, fXMLNamespaceId(0)
, fXMLNSNamespaceId(0)
, fSchemaNamespaceId(0)
- , fElemStateSize(16)
, fScannerId(0)
, fSequenceId(0)
- , fElemState(0)
, fAttrList(0)
, fDocHandler(0)
, fDocTypeHandler(0)
@@ -209,24 +180,15 @@
, fErrorReporter(0)
, fErrorHandler(0)
, fIDRefList(0)
- , fRawAttrList(0)
, fValidator(valToAdopt)
- , fDTDValidator(0)
- , fSchemaValidator(0)
, fValScheme(Val_Never)
, fGrammarResolver(0)
, fGrammar(0)
, fRootGrammar(0)
- , fDTDGrammar(0)
, fURIStringPool(0)
- , fMatcherStack(0)
- , fValueStoreCache(0)
- , fFieldActivator(0)
, fRootElemName(0)
, fExternalSchemaLocation(0)
, fExternalNoNamespaceSchemaLocation(0)
- , fLoadExternalDTD(true)
- , fNormalizeData(true)
{
commonInit();
@@ -234,19 +196,16 @@
fValidatorFromUser = true;
initValidator(fValidator);
}
- else {
- //use fDTDValidator as the default validator
- fValidator = fDTDValidator;
- }
}
XMLScanner::XMLScanner( XMLDocumentHandler* const docHandler
- , DocTypeHandler* const docTypeHandler
- , XMLEntityHandler* const entityHandler
- , XMLErrorReporter* const errHandler
- , XMLValidator* const valToAdopt) :
+ , DocTypeHandler* const docTypeHandler
+ , XMLEntityHandler* const entityHandler
+ , XMLErrorReporter* const errHandler
+ , XMLValidator* const valToAdopt) :
- fDoNamespaces(false)
+ fCalculateSrcOfs(true)
+ , fDoNamespaces(false)
, fExitOnFirstFatal(true)
, fValidationConstraintFatal(false)
, fInException(false)
@@ -256,19 +215,18 @@
, fValidatorFromUser(false)
, fDoSchema(false)
, fSchemaFullChecking(false)
- , fSeeXsi(false)
, fToCacheGrammar(false)
, fUseCachedGrammar(false)
+ , fLoadExternalDTD(true)
+ , fNormalizeData(true)
, fErrorCount(0)
, fEmptyNamespaceId(0)
, fUnknownNamespaceId(0)
, fXMLNamespaceId(0)
, fXMLNSNamespaceId(0)
, fSchemaNamespaceId(0)
- , fElemStateSize(16)
, fScannerId(0)
, fSequenceId(0)
- , fElemState(0)
, fAttrList(0)
, fDocHandler(docHandler)
, fDocTypeHandler(docTypeHandler)
@@ -276,24 +234,15 @@
, fErrorReporter(errHandler)
, fErrorHandler(0)
, fIDRefList(0)
- , fRawAttrList(0)
, fValidator(valToAdopt)
- , fDTDValidator(0)
- , fSchemaValidator(0)
, fValScheme(Val_Never)
, fGrammarResolver(0)
, fGrammar(0)
, fRootGrammar(0)
- , fDTDGrammar(0)
, fURIStringPool(0)
- , fMatcherStack(0)
- , fValueStoreCache(0)
- , fFieldActivator(0)
, fRootElemName(0)
, fExternalSchemaLocation(0)
, fExternalNoNamespaceSchemaLocation(0)
- , fLoadExternalDTD(true)
- , fNormalizeData(true)
{
commonInit();
@@ -301,57 +250,42 @@
fValidatorFromUser = true;
initValidator(fValidator);
}
- else {
- //use fDTDValidator as the default validator
- fValidator = fDTDValidator;
- }
}
XMLScanner::~XMLScanner()
{
- delete [] fElemState;
delete fAttrList;
delete fIDRefList;
- delete fRawAttrList;
- if (fValidatorFromUser)
- delete fValidator;
-
- delete fDTDValidator;
- delete fSchemaValidator;
-
- //fGrammarResolver will delete the fGrammar as well
- delete fGrammarResolver;
-
- delete fURIStringPool;
-
- delete fFieldActivator;
- delete fMatcherStack;
- delete fValueStoreCache;
-
delete [] fRootElemName;
delete [] fExternalSchemaLocation;
delete [] fExternalNoNamespaceSchemaLocation;
}
+void XMLScanner::setValidator(XMLValidator* const valToAdopt)
+{
+ if (fValidatorFromUser)
+ delete fValidator;
+ fValidator = valToAdopt;
+ fValidatorFromUser = true;
+ initValidator(fValidator);
+}
+
+
+
// ---------------------------------------------------------------------------
// XMLScanner: Main entry point to scan a document
// ---------------------------------------------------------------------------
void XMLScanner::scanDocument( const XMLCh* const systemId)
{
- //
// First we try to parse it as a URL. If that fails, we assume its
// a file and try it that way.
- //
InputSource* srcToUse = 0;
try
{
- //
// Create a temporary URL. Since this is the primary document,
// it has to be fully qualified. If not, then assume we are just
// mistaking a file for a URL.
- //
-
XMLURL tmpURL(systemId);
if (tmpURL.isRelative()) {
srcToUse = new LocalFileInputSource(systemId);
@@ -362,7 +296,6 @@
}
}
-
catch(const MalformedURLException&)
{
srcToUse = new LocalFileInputSource(systemId);
@@ -370,10 +303,8 @@
catch(const XMLException& excToCatch)
{
- //
// For any other XMLException,
// emit the error and catch any user exception thrown from here.
- //
fInException = true;
if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
emitError
@@ -398,7 +329,6 @@
);
return;
}
-
catch(...)
{
// Just rethrow this, since its not our problem
@@ -418,172 +348,22 @@
}
-void XMLScanner::scanDocument(const InputSource& src)
-{
- //
- // Bump up the sequence id for this parser instance. This will invalidate
- // any previous progressive scan tokens.
- //
- fSequenceId++;
-
- try
- {
- //
- // Reset the scanner and its plugged in stuff for a new run. This
- // resets all the data structures, creates the initial reader and
- // pushes it on the stack, and sets up the base document path.
- //
- scanReset(src);
-
- // If we have a document handler, then call the start document
- if (fDocHandler)
- fDocHandler->startDocument();
-
- fValueStoreCache->startDocument();
-
- //
- // Scan the prolog part, which is everything before the root element
- // including the DTD subsets.
- //
- scanProlog();
-
- //
- // If we got to the end of input, then its not a valid XML file.
- // Else, go on to scan the content.
- //
- if (fReaderMgr.atEOF())
- {
- emitError(XMLErrs::EmptyMainEntity);
- }
- else
- {
- // Scan content, and tell it its not an external entity
- if (scanContent(false))
- {
- // Do post-parse validation if required
- if (fValidate)
- {
- //
- // We handle ID reference semantics at this level since
- // its required by XML 1.0.
- //
- checkIDRefs();
-
- // Then allow the validator to do any extra stuff it wants
- fValidator->postParseValidation();
- }
-
- // That went ok, so scan for any miscellaneous stuff
- if (!fReaderMgr.atEOF())
- scanMiscellaneous();
- }
- }
-
- if (fValidate)
- fValueStoreCache->endDocument();
-
- // If we have a document handler, then call the end document
- if (fDocHandler)
- fDocHandler->endDocument();
-
- // Reset the reader manager to close all files, sockets, etc...
- fReaderMgr.reset();
- }
-
- //
- // NOTE:
- //
- // In all of the error processing below, the emitError() call MUST come
- // before the flush of the reader mgr, or it will fail because it tries
- // to find out the position in the XML source of the error.
- //
- catch(const XMLErrs::Codes)
- {
- // This is a 'first fatal error' type exit, so reset and fall through
- fReaderMgr.reset();
- }
-
- catch(const XMLValid::Codes)
- {
- // This is a 'first fatal error' type exit, so reset and fall through
- fReaderMgr.reset();
- }
-
- catch(const XMLException& excToCatch)
- {
- //
- // Emit the error and catch any user exception thrown from here. Make
- // sure in all cases we flush the reader manager.
- //
- fInException = true;
- try
- {
- if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
- emitError
- (
- XMLErrs::XMLException_Warning
- , excToCatch.getType()
- , excToCatch.getMessage()
- );
- else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
- emitError
- (
- XMLErrs::XMLException_Fatal
- , excToCatch.getType()
- , excToCatch.getMessage()
- );
- else
- emitError
- (
- XMLErrs::XMLException_Error
- , excToCatch.getType()
- , excToCatch.getMessage()
- );
- }
-
- catch(...)
- {
- // Flush the reader manager and rethrow user's error
- fReaderMgr.reset();
- throw;
- }
-
- // If it returned, then reset the reader manager and fall through
- fReaderMgr.reset();
- }
-
- catch(...)
- {
- // Reset and rethrow
- fReaderMgr.reset();
- throw;
- }
-}
-
-
-//
// This method begins a progressive parse. It scans through the prolog and
// returns a token to be used on subsequent scanNext() calls. If the return
// value is true, then the token is legal and ready for further use. If it
// returns false, then the scan of the prolog failed and the token is not
// going to work on subsequent scanNext() calls.
-//
bool XMLScanner::scanFirst( const XMLCh* const systemId
, XMLPScanToken& toFill)
{
- //
// First we try to parse it as a URL. If that fails, we assume its
// a file and try it that way.
- //
InputSource* srcToUse = 0;
try
{
- //
// Create a temporary URL. Since this is the primary document,
// it has to be fully qualified. If not, then assume we are just
// mistaking a file for a URL.
- //
-
XMLURL tmpURL(systemId);
if (tmpURL.isRelative()) {
srcToUse = new LocalFileInputSource(systemId);
@@ -593,18 +373,14 @@
srcToUse = new URLInputSource(tmpURL);
}
}
-
catch(const MalformedURLException&)
{
srcToUse = new LocalFileInputSource(systemId);
}
-
catch(const XMLException& excToCatch)
{
- //
// For any other XMLException,
// emit the error and catch any user exception thrown from here.
- //
fInException = true;
if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
emitError
@@ -629,7 +405,6 @@
);
return false;
}
-
catch(...)
{
// Just rethrow this, since its not our problem
@@ -650,73 +425,56 @@
}
bool XMLScanner::scanFirst( const InputSource& src
- , XMLPScanToken& toFill)
+ , XMLPScanToken& toFill)
{
- //
// Bump up the sequence id for this new scan cycle. This will invalidate
// any previous tokens we've returned.
- //
fSequenceId++;
- //
// Reset the scanner and its plugged in stuff for a new run. This
// resets all the data structures, creates the initial reader and
// pushes it on the stack, and sets up the base document path
- //
scanReset(src);
// If we have a document handler, then call the start document
if (fDocHandler)
fDocHandler->startDocument();
- fValueStoreCache->startDocument();
-
try
{
- //
// Scan the prolog part, which is everything before the root element
// including the DTD subsets. This is all that is done on the scan
// first.
- //
scanProlog();
- //
// If we got to the end of input, then its not a valid XML file.
// Else, go on to scan the content.
- //
if (fReaderMgr.atEOF())
{
emitError(XMLErrs::EmptyMainEntity);
}
}
-
- //
// NOTE:
//
// In all of the error processing below, the emitError() call MUST come
// before the flush of the reader mgr, or it will fail because it tries
// to find out the position in the XML source of the error.
- //
catch(const XMLErrs::Codes)
{
// This is a 'first failure' exception so reset and return a failure
fReaderMgr.reset();
return false;
}
-
catch(const XMLValid::Codes)
{
// This is a 'first fatal error' type exit, so reset and reuturn failure
fReaderMgr.reset();
return false;
}
-
catch(const XMLException& excToCatch)
{
- //
// Emit the error and catch any user exception thrown from here. Make
// sure in all cases we flush the reader manager.
- //
fInException = true;
try
{
@@ -742,7 +500,6 @@
, excToCatch.getMessage()
);
}
-
catch(...)
{
// Reset and rethrow the user error
@@ -754,7 +511,6 @@
fReaderMgr.reset();
return false;
}
-
catch(...)
{
// Reset and rethrow original error
@@ -768,367 +524,102 @@
}
-bool XMLScanner::scanNext(XMLPScanToken& token)
+void XMLScanner::scanReset(XMLPScanToken& token)
{
// Make sure this token is still legal
if (!isLegalToken(token))
ThrowXML(RuntimeException, XMLExcepts::Scan_BadPScanToken);
- // Find the next token and remember the reader id
- unsigned int orgReader;
- XMLTokens curToken;
+ // Reset the reader manager
+ fReaderMgr.reset();
- bool retVal = true;
+ // And invalidate any tokens by bumping our sequence number
+ fSequenceId++;
- try
- {
- while (true)
- {
- //
- // We have to handle any end of entity exceptions that happen here.
- // We could be at the end of X nested entities, each of which will
- // generate an end of entity exception as we try to move forward.
- //
+ // Reset our error count
+ fErrorCount = 0;
+}
- try
- {
- curToken = senseNextToken(orgReader);
- break;
- }
- catch(const EndOfEntityException& toCatch)
- {
- // Send an end of entity reference event
- if (fDocHandler)
- fDocHandler->endEntityReference(toCatch.getEntity());
- }
- }
- if (curToken == Token_CharData)
- {
- scanCharData(fCDataBuf);
- }
- else if (curToken == Token_EOF)
+// ---------------------------------------------------------------------------
+// XMLScanner: Private helper methods.
+// ---------------------------------------------------------------------------
+
+// This method handles the common initialization, to avoid having to do
+// it redundantly in multiple constructors.
+void XMLScanner::commonInit()
+{
+ // We have to do a little init that involves statics, so we have to
+ // use the mutex to protect it.
+ {
+ XMLMutexLock lockInit(&gScannerMutex());
+
+ // If we haven't loaded our message yet, then do that
+ if (!gMsgLoader)
{
- if (!fElemStack.isEmpty())
- {
- const ElemStack::StackElem* topElem = fElemStack.popTop();
- emitError
- (
- XMLErrs::EndedWithTagsOnStack
- , topElem->fThisElement->getFullName()
- );
- }
+ gMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgXMLErrDomain);
+ if (!gMsgLoader)
+ XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
- retVal = false;
+ // Register this object to be cleaned up at termination
+ cleanupMsgLoader.registerCleanup(reinitMsgLoader);
}
- else
- {
- // Its some sort of markup
- bool gotData = true;
- switch(curToken)
- {
- case Token_CData :
- // Make sure we are within content
- if (fElemStack.isEmpty())
- emitError(XMLErrs::CDATAOutsideOfContent);
- scanCDSection();
- break;
- case Token_Comment :
- scanComment();
- break;
+ // And assign ourselves the next available scanner id
+ fScannerId = ++gScannerId;
+ }
- case Token_EndTag :
- scanEndTag(gotData);
- break;
+ // Create the attribute list, which is used to store attribute values
+ // during start tag processing. Give it a reasonable initial size that
+ // will serve for most folks, though it will grow as required.
+ fAttrList = new RefVectorOf<XMLAttr>(32);
- case Token_PI :
- scanPI();
- break;
+ // Create the id ref list. This is used to enforce XML 1.0 ID ref
+ // semantics, i.e. all id refs must refer to elements that exist
+ fIDRefList = new RefHashTableOf<XMLRefInfo>(109);
- case Token_StartTag :
- if (fDoNamespaces)
- scanStartTagNS(gotData);
- else
- scanStartTag(gotData);
- break;
+ // Create the GrammarResolver
+ //fGrammarResolver = new GrammarResolver();
+}
- default :
- fReaderMgr.skipToChar(chOpenAngle);
- break;
- }
- if (orgReader != fReaderMgr.getCurrentReaderNum())
- emitError(XMLErrs::PartialMarkupInEntity);
+void XMLScanner::initValidator(XMLValidator* theValidator) {
- // If we hit the end, then do the miscellaneous part
- if (!gotData)
- {
- // Do post-parse validation if required
- if (fValidate)
- {
- //
- // We handle ID reference semantics at this level since
- // its required by XML 1.0.
- //
- checkIDRefs();
+ // Tell the validator about the stuff it needs to know in order to
+ // do its work.
+ theValidator->setScannerInfo(this, &fReaderMgr, &fBufMgr);
+ theValidator->setErrorReporter(fErrorReporter);
+}
- // Then allow the validator to do any extra stuff it wants
- fValidator->postParseValidation();
- }
+// ---------------------------------------------------------------------------
+// XMLScanner: Error emitting methods
+// ---------------------------------------------------------------------------
- // That went ok, so scan for any miscellaneous stuff
- scanMiscellaneous();
+// These methods are called whenever the scanner wants to emit an error.
+// It handles getting the message loaded, doing token replacement, etc...
+// and then calling the error handler, if its installed.
+void XMLScanner::emitError(const XMLErrs::Codes toEmit)
+{
+ // Bump the error count if it is not a warning
+ if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
+ incrementErrorCount();
- if (fValidate)
- fValueStoreCache->endDocument();
+ if (fErrorReporter)
+ {
+ // Load the message into a local for display
+ const unsigned int msgSize = 1023;
+ XMLCh errText[msgSize + 1];
- if (fDocHandler)
- fDocHandler->endDocument();
- }
+ if (!gMsgLoader->loadMsg(toEmit, errText, msgSize))
+ {
+ // <TBD> Probably should load a default msg here
}
- }
- //
- // NOTE:
- //
- // In all of the error processing below, the emitError() call MUST come
- // before the flush of the reader mgr, or it will fail because it tries
- // to find out the position in the XML source of the error.
- //
- catch(const XMLErrs::Codes)
- {
- // This is a 'first failure' exception, so reset and return failure
- fReaderMgr.reset();
- return false;
- }
-
- catch(const XMLValid::Codes)
- {
- // This is a 'first fatal error' type exit, so reset and reuturn failure
- fReaderMgr.reset();
- return false;
- }
-
- // We have to propogate SAX exceptions
- catch(const SAXException&)
- {
- // Just reset our reader manager and rethrow SAX exception
- fReaderMgr.reset();
- throw;
- }
-
- catch(const XMLException& excToCatch)
- {
- //
- // Emit the error and catch any user exception thrown from here. Make
- // sure in all cases we flush the reader manager.
- //
- fInException = true;
- try
- {
- if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
- emitError
- (
- XMLErrs::XMLException_Warning
- , excToCatch.getType()
- , excToCatch.getMessage()
- );
- else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
- emitError
- (
- XMLErrs::XMLException_Fatal
- , excToCatch.getType()
- , excToCatch.getMessage()
- );
- else
- emitError
- (
- XMLErrs::XMLException_Error
- , excToCatch.getType()
- , excToCatch.getMessage()
- );
- }
-
- catch(...)
- {
- // Reset and rethrow user error
- fReaderMgr.reset();
- throw;
- }
-
- // Reset and return failure
- fReaderMgr.reset();
- return false;
- }
-
- catch(...)
- {
- // Reset and rethrow original error
- fReaderMgr.reset();
- throw;
- }
-
- // If we hit the end, then flush the reader manager
- if (!retVal)
- fReaderMgr.reset();
-
- return retVal;
-}
-
-
-void XMLScanner::scanReset(XMLPScanToken& token)
-{
- // Make sure this token is still legal
- if (!isLegalToken(token))
- ThrowXML(RuntimeException, XMLExcepts::Scan_BadPScanToken);
-
- // Reset the reader manager
- fReaderMgr.reset();
-
- // And invalidate any tokens by bumping our sequence number
- fSequenceId++;
-
- // Reset our error count
- fErrorCount = 0;
-}
-
-
-
-// ---------------------------------------------------------------------------
-// XMLScanner: Private helper methods. Most of these are implemented in
-// XMLScanner2.Cpp.
-// ---------------------------------------------------------------------------
-
-//
-// This method handles the common initialization, to avoid having to do
-// it redundantly in multiple constructors.
-//
-void XMLScanner::commonInit()
-{
-
- //
- // We have to do a little init that involves statics, so we have to
- // use the mutex to protect it.
- //
- {
- XMLMutexLock lockInit(&gScannerMutex());
-
- // If we haven't loaded our message yet, then do that
- if (!gMsgLoader)
- {
- gMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgXMLErrDomain);
- if (!gMsgLoader)
- XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
-
- // Register this object to be cleaned up at termination
- cleanupMsgLoader.registerCleanup(reinitMsgLoader);
- }
-
- // And assign ourselves the next available scanner id
- fScannerId = ++gScannerId;
- }
-
- //
- // Create the element state array
- //
- fElemState = new unsigned int[fElemStateSize];
-
- //
- // Create the attribute list, which is used to store attribute values
- // during start tag processing. Give it a reasonable initial size that
- // will serve for most folks, though it will grow as required.
- //
- fAttrList = new RefVectorOf<XMLAttr>(32);
-
- //
- // And we need one for the raw attribute scan. This just stores key/
- // value string pairs (prior to any processing.)
- //
- fRawAttrList = new RefVectorOf<KVStringPair>(32);
-
- //
- // Create the id ref list. This is used to enforce XML 1.0 ID ref
- // semantics, i.e. all id refs must refer to elements that exist
- //
- fIDRefList = new RefHashTableOf<XMLRefInfo>(109);
-
- // Create the GrammarResolver
- fGrammarResolver = new GrammarResolver();
-
- // Create the Validator and init them
- fDTDValidator = new DTDValidator();
- initValidator(fDTDValidator);
- fSchemaValidator = new SchemaValidator();
- initValidator(fSchemaValidator);
-
- // Create IdentityConstraint info
- fMatcherStack = new XPathMatcherStack();
- fValueStoreCache = new ValueStoreCache();
- fFieldActivator = new FieldActivator(fValueStoreCache, fMatcherStack);
- fValueStoreCache->setScanner(this);
-}
-
-
-
-void XMLScanner::initValidator(XMLValidator* theValidator) {
- //
- // Tell the validator about the stuff it needs to know in order to
- // do its work.
- //
- theValidator->setScannerInfo(this, &fReaderMgr, &fBufMgr);
- theValidator->setErrorReporter(fErrorReporter);
-
- if (theValidator->handlesSchema()) {
-
- ((SchemaValidator*) theValidator)->setGrammarResolver(fGrammarResolver);
- ((SchemaValidator*) theValidator)->setExitOnFirstFatal(fExitOnFirstFatal);
- }
-}
-
-void XMLScanner::resetURIStringPool() {
- fURIStringPool->flushAll();
-
- fEmptyNamespaceId = fURIStringPool->addOrFind(XMLUni::fgZeroLenString);
- fUnknownNamespaceId = fURIStringPool->addOrFind(XMLUni::fgUnknownURIName);
- fXMLNamespaceId = fURIStringPool->addOrFind(XMLUni::fgXMLURIName);
- fXMLNSNamespaceId = fURIStringPool->addOrFind(XMLUni::fgXMLNSURIName);
- fSchemaNamespaceId = fURIStringPool->addOrFind(SchemaSymbols::fgURI_XSI);
-}
-
-// ---------------------------------------------------------------------------
-// XMLScanner: Error emitting methods
-// ---------------------------------------------------------------------------
-
-//
-// These methods are called whenever the scanner wants to emit an error.
-// It handles getting the message loaded, doing token replacement, etc...
-// and then calling the error handler, if its installed.
-//
-void XMLScanner::emitError(const XMLErrs::Codes toEmit)
-{
- // Bump the error count if it is not a warning
- if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
- incrementErrorCount();
-
- if (fErrorReporter)
- {
- // Load the message into a local for display
- const unsigned int msgSize = 1023;
- XMLCh errText[msgSize + 1];
-
- if (!gMsgLoader->loadMsg(toEmit, errText, msgSize))
- {
- // <TBD> Probably should load a default msg here
- }
-
- //
// Create a LastExtEntityInfo structure and get the reader manager
// to fill it in for us. This will give us the information about
// the last reader on the stack that was an external entity of some
// sort (i.e. it will ignore internal entities.
- //
ReaderMgr::LastExtEntityInfo lastInfo;
fReaderMgr.getLastExtEntityInfo(lastInfo);
@@ -1162,10 +653,8 @@
if (fErrorReporter)
{
- //
// Load the message into alocal and replace any tokens found in
// the text.
- //
const unsigned int maxChars = 2047;
XMLCh errText[maxChars + 1];
@@ -1174,12 +663,10 @@
// <TBD> Should probably load a default message here
}
- //
// Create a LastExtEntityInfo structure and get the reader manager
// to fill it in for us. This will give us the information about
// the last reader on the stack that was an external entity of some
// sort (i.e. it will ignore internal entities.
- //
ReaderMgr::LastExtEntityInfo lastInfo;
fReaderMgr.getLastExtEntityInfo(lastInfo);
@@ -1213,10 +700,8 @@
if (fErrorReporter)
{
- //
// Load the message into alocal and replace any tokens found in
// the text.
- //
const unsigned int maxChars = 2047;
XMLCh errText[maxChars + 1];
@@ -1225,12 +710,10 @@
// <TBD> Should probably load a default message here
}
- //
// Create a LastExtEntityInfo structure and get the reader manager
// to fill it in for us. This will give us the information about
// the last reader on the stack that was an external entity of some
// sort (i.e. it will ignore internal entities.
- //
ReaderMgr::LastExtEntityInfo lastInfo;
fReaderMgr.getLastExtEntityInfo(lastInfo);
@@ -1257,7 +740,6 @@
// XMLScanner: Getter methods
// ---------------------------------------------------------------------------
-//
// This method allows the caller to query the current location of the scanner.
// It will return the sys/public ids of the current entity, and the line/col
// position within it.
@@ -1266,7 +748,7 @@
// currently scanning an entity, the position returned will be the end of
// the entity reference in the file that had the reference.
//
-bool
+/*bool
XMLScanner::getLastExtLocation( XMLCh* const sysIdToFill
, const unsigned int maxSysIdChars
, XMLCh* const pubIdToFill
@@ -1299,2553 +781,334 @@
XMLString::copyString(pubIdToFill, lastInfo.publicId);
}
return true;
-}
+}*/
// ---------------------------------------------------------------------------
// XMLScanner: Private scanning methods
// ---------------------------------------------------------------------------
-//
-// This method is called from scanStartTag() to handle the very raw initial
-// scan of the attributes. It just fills in the passed collection with
-// key/value pairs for each attribute. No processing is done on them at all.
-//
-unsigned int
-XMLScanner::rawAttrScan(const XMLCh* const elemName
- , RefVectorOf<KVStringPair>& toFill
- , bool& isEmpty)
+// This method is called after the end of the root element, to handle
+// any miscellaneous stuff hanging around.
+void XMLScanner::scanMiscellaneous()
{
- //
- // Keep up with how many attributes we've seen so far, and how many
- // elements are available in the vector. This way we can reuse old
- // elements until we run out and then expand it.
- //
- unsigned int attCount = 0;
- unsigned int curVecSize = toFill.size();
-
- // Assume it is not empty
- isEmpty = false;
+ // Get a buffer for this work
+ XMLBufBid bbCData(&fBufMgr);
- //
- // We loop until we either see a /> or >, handling key/value pairs util
- // we get there. We place them in the passed vector, which we will expand
- // as required to hold them.
- //
while (true)
{
- // Get the next character, which should be non-space
- XMLCh nextCh = fReaderMgr.peekNextChar();
-
- //
- // If the next character is not a slash or closed angle bracket,
- // then it must be whitespace, since whitespace is required
- // between the end of the last attribute and the name of the next
- // one.
- //
- if (attCount)
+ try
{
- if ((nextCh != chForwardSlash) && (nextCh != chCloseAngle))
- {
- if (XMLReader::isWhitespace(nextCh))
- {
- // Ok, skip by them and get another char
- fReaderMgr.getNextChar();
- fReaderMgr.skipPastSpaces();
- nextCh = fReaderMgr.peekNextChar();
- }
- else
- {
- // Emit the error but keep on going
- emitError(XMLErrs::ExpectedWhitespace);
- }
- }
- }
+ const XMLCh nextCh = fReaderMgr.peekNextChar();
- //
- // Ok, here we first check for any of the special case characters.
- // If its not one, then we do the normal case processing, which
- // assumes that we've hit an attribute value, Otherwise, we do all
- // the special case checks.
- //
- if (!XMLReader::isSpecialStartTagChar(nextCh))
- {
- //
- // Assume its going to be an attribute, so get a name from
- // the input.
- //
- if (!fReaderMgr.getName(fAttNameBuf))
- {
- emitError(XMLErrs::ExpectedAttrName);
- fReaderMgr.skipPastChar(chCloseAngle);
- return attCount;
- }
+ // Watch for end of file and break out
+ if (!nextCh)
+ break;
- // And next must be an equal sign
- if (!scanEq())
+ if (nextCh == chOpenAngle)
{
- static const XMLCh tmpList[] =
- {
- chSingleQuote, chDoubleQuote, chCloseAngle
- , chOpenAngle, chForwardSlash, chNull
- };
-
- emitError(XMLErrs::ExpectedEqSign);
-
- //
- // Try to sync back up by skipping forward until we either
- // hit something meaningful.
- //
- const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
-
- if ((chFound == chCloseAngle) || (chFound == chForwardSlash))
+ if (checkXMLDecl(true))
{
- // Jump back to top for normal processing of these
- continue;
+ // Can't have an XML decl here
+ emitError(XMLErrs::NotValidAfterContent);
+ fReaderMgr.skipPastChar(chCloseAngle);
}
- else if ((chFound == chSingleQuote)
- || (chFound == chDoubleQuote)
- || XMLReader::isWhitespace(chFound))
+ else if (fReaderMgr.skippedString(XMLUni::fgPIString))
{
- // Just fall through assuming that the value is to follow
+ scanPI();
}
- else if (chFound == chOpenAngle)
+ else if (fReaderMgr.skippedString(XMLUni::fgCommentString))
{
- // Assume a malformed tag and that new one is starting
- emitError(XMLErrs::UnterminatedStartTag, elemName);
- return attCount;
+ scanComment();
}
- else
+ else
{
- // Something went really wrong
- return attCount;
+ // This can't be possible, so just give up
+ emitError(XMLErrs::ExpectedCommentOrPI);
+ fReaderMgr.skipPastChar(chCloseAngle);
}
}
-
- //
- // Next should be the quoted attribute value. We just do a simple
- // and stupid scan of this value. The only thing we do here
- // is to expand entity references.
- //
- if (!basicAttrValueScan(fAttNameBuf.getRawBuffer(), fAttValueBuf))
+ else if (XMLReader::isWhitespace(nextCh))
{
- static const XMLCh tmpList[] =
- {
- chCloseAngle, chOpenAngle, chForwardSlash, chNull
- };
-
- emitError(XMLErrs::ExpectedAttrValue);
-
- //
- // It failed, so lets try to get synced back up. We skip
- // forward until we find some whitespace or one of the
- // chars in our list.
- //
- const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
-
- if ((chFound == chCloseAngle)
- || (chFound == chForwardSlash)
- || XMLReader::isWhitespace(chFound))
- {
- //
- // Just fall through and process this attribute, though
- // the value will be "".
- //
- }
- else if (chFound == chOpenAngle)
+ // If we have a doc handler, then gather up the spaces and
+ // call back. Otherwise, just skip over whitespace.
+ if (fDocHandler)
{
- // Assume a malformed tag and that new one is starting
- emitError(XMLErrs::UnterminatedStartTag, elemName);
- return attCount;
- }
- else
- {
- // Something went really wrong
- return attCount;
- }
- }
-
- //
- // Make sure that the name is basically well formed for namespace
- // enabled rules. It either has no colons, or it has one which
- // is neither the first or last char.
- //
- const int colonFirst = XMLString::indexOf(fAttNameBuf.getRawBuffer(), chColon);
- if (colonFirst != -1)
- {
- const int colonLast = XMLString::lastIndexOf(fAttNameBuf.getRawBuffer(), chColon);
-
- if (colonFirst != colonLast)
- {
- emitError(XMLErrs::TooManyColonsInName);
- continue;
- }
- else if ((colonFirst == 0)
- || (colonLast == (int)fAttNameBuf.getLen() - 1))
- {
- emitError(XMLErrs::InvalidColonPos);
- continue;
- }
- }
-
-
- //
- // And now lets add it to the passed collection. If we have not
- // filled it up yet, then we use the next element. Else we add
- // a new one.
- //
- KVStringPair* curPair = 0;
- if (attCount >= curVecSize)
- {
- curPair = new KVStringPair
- (
- fAttNameBuf.getRawBuffer()
- , fAttValueBuf.getRawBuffer()
- );
- toFill.addElement(curPair);
- }
- else
- {
- curPair = toFill.elementAt(attCount);
- curPair->set(fAttNameBuf.getRawBuffer(), fAttValueBuf.getRawBuffer());
- }
-
- // And bump the count of attributes we've gotten
- attCount++;
-
- // And go to the top again for another attribute
- continue;
- }
-
- //
- // It was some special case character so do all of the checks and
- // deal with it.
- //
- if (!nextCh)
- ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
-
- if (nextCh == chForwardSlash)
- {
- fReaderMgr.getNextChar();
- isEmpty = true;
- if (!fReaderMgr.skippedChar(chCloseAngle))
- emitError(XMLErrs::UnterminatedStartTag, elemName);
- break;
- }
- else if (nextCh == chCloseAngle)
- {
- fReaderMgr.getNextChar();
- break;
- }
- else if (nextCh == chOpenAngle)
- {
- //
- // Check for this one specially, since its going to be common
- // and it is kind of auto-recovering since we've already hit the
- // next open bracket, which is what we would have seeked to (and
- // skipped this whole tag.)
- //
- emitError(XMLErrs::UnterminatedStartTag, elemName);
- break;
- }
- else if ((nextCh == chSingleQuote) || (nextCh == chDoubleQuote))
- {
- //
- // Check for this one specially, which is probably a missing
- // attribute name, e.g. ="value". Just issue expected name
- // error and eat the quoted string, then jump back to the
- // top again.
- //
- emitError(XMLErrs::ExpectedAttrName);
- fReaderMgr.getNextChar();
- fReaderMgr.skipQuotedString(nextCh);
- fReaderMgr.skipPastSpaces();
- continue;
- }
- }
-
- return attCount;
-}
-
-
-//
-// This method will kick off the scanning of the primary content of the
-// document, i.e. the elements.
-//
-bool XMLScanner::scanContent(const bool extEntity)
-{
- //
- // Go into a loop until we hit the end of the root element, or we fall
- // out because there is no root element.
- //
- // We have to do kind of a deeply nested double loop here in order to
- // avoid doing the setup/teardown of the exception handler on each
- // round. Doing it this way we only do it when an exception actually
- // occurs.
- //
- bool gotData = true;
- bool inMarkup = false;
- while (gotData)
- {
- try
- {
- while (gotData)
- {
- // Sense what the next top level token is. According to what
- // this tells us, we will call something to handle that kind
- // of thing.
- //
- unsigned int orgReader;
- const XMLTokens curToken = senseNextToken(orgReader);
-
- //
- // Handle character data and end of file specially. Char data
- // is not markup so we don't want to handle it in the loop
- // below.
- //
- if (curToken == Token_CharData)
- {
- //
- // Scan the character data and call appropriate events. Let
- // him use our local character data buffer for efficiency.
- //
- scanCharData(fCDataBuf);
- continue;
- }
- else if (curToken == Token_EOF)
- {
- //
- // The element stack better be empty at this point or we
- // ended prematurely before all elements were closed.
- //
- if (!fElemStack.isEmpty())
- {
- const ElemStack::StackElem* topElem = fElemStack.popTop();
- emitError
- (
- XMLErrs::EndedWithTagsOnStack
- , topElem->fThisElement->getFullName()
- );
- }
-
- // Its the end of file, so clear the got data flag
- gotData = false;
- continue;
- }
-
- // We are in some sort of markup now
- inMarkup = true;
-
- //
- // According to the token we got, call the appropriate
- // scanning method.
- //
- switch(curToken)
- {
- case Token_CData :
- // Make sure we are within content
- if (fElemStack.isEmpty())
- emitError(XMLErrs::CDATAOutsideOfContent);
- scanCDSection();
- break;
-
- case Token_Comment :
- scanComment();
- break;
-
- case Token_EndTag :
- scanEndTag(gotData);
- break;
-
- case Token_PI :
- scanPI();
- break;
-
- case Token_StartTag :
- if (fDoNamespaces)
- scanStartTagNS(gotData);
- else
- scanStartTag(gotData);
- break;
-
- default :
- fReaderMgr.skipToChar(chOpenAngle);
- break;
- }
-
- if (orgReader != fReaderMgr.getCurrentReaderNum())
- emitError(XMLErrs::PartialMarkupInEntity);
-
- // And we are back out of markup again
- inMarkup = false;
- }
- }
-
- catch(const EndOfEntityException& toCatch)
- {
- //
- // If we were in some markup when this happened, then its a
- // partial markup error.
- //
- if (inMarkup)
- emitError(XMLErrs::PartialMarkupInEntity);
-
- // Send an end of entity reference event
- if (fDocHandler)
- fDocHandler->endEntityReference(toCatch.getEntity());
-
- inMarkup = false;
- }
- }
-
- // It went ok, so return success
- return true;
-}
-
-
-void XMLScanner::scanEndTag(bool& gotData)
-{
- //
- // Assume we will still have data until proven otherwise. It will only
- // ever be false if this is the end of the root element.
- //
- gotData = true;
-
- //
- // Check if the element stack is empty. If so, then this is an unbalanced
- // element (i.e. more ends than starts, perhaps because of bad text
- // causing one to be skipped.)
- //
- if (fElemStack.isEmpty())
- {
- emitError(XMLErrs::MoreEndThanStartTags);
- fReaderMgr.skipPastChar(chCloseAngle);
- ThrowXML(RuntimeException, XMLExcepts::Scan_UnbalancedStartEnd);
- }
-
- // After the </ is the element QName, so get a name from the input
- XMLBufBid bbQName(&fBufMgr);
- XMLBuffer& qnameBuf = bbQName.getBuffer();
- if (!fReaderMgr.getName(qnameBuf))
- {
- // It failed so we can't really do anything with it
- emitError(XMLErrs::ExpectedElementName);
- fReaderMgr.skipPastChar(chCloseAngle);
- return;
- }
-
- unsigned int uriId = fEmptyNamespaceId;
- XMLBufBid bbName(&fBufMgr);
- XMLBufBid bbPrefix(&fBufMgr);
- if (fDoNamespaces)
- {
- uriId = resolveQName
- (
- qnameBuf.getRawBuffer()
- , bbName.getBuffer()
- , bbPrefix.getBuffer()
- , ElemStack::Mode_Element
- );
- }
-
- //
- // Pop the stack of the element we are supposed to be ending. Remember
- // that we don't own this. The stack just keeps them and reuses them.
- //
- // NOTE: We CANNOT do this until we've resolved the element name because
- // the element stack top contains the prefix to URI mappings for this
- // element.
- //
- unsigned int topUri = fElemStack.getCurrentURI();
- const ElemStack::StackElem* topElem = fElemStack.popTop();
-
- // See if it was the root element, to avoid multiple calls below
- const bool isRoot = fElemStack.isEmpty();
-
- // Make sure that its the end of the element that we expect
- XMLElementDecl* tempElement = topElem->fThisElement;
- if (fDoNamespaces && fGrammarType == Grammar::SchemaGrammarType) {
- if ((topUri != uriId) || (!XMLString::equals(tempElement->getBaseName(), bbName.getRawBuffer())))
- {
- emitError
- (
- XMLErrs::ExpectedEndOfTagX
- , topElem->fThisElement->getFullName()
- );
- }
- }
- else {
- if (!XMLString::equals(tempElement->getFullName(), qnameBuf.getRawBuffer()))
- {
- emitError
- (
- XMLErrs::ExpectedEndOfTagX
- , topElem->fThisElement->getFullName()
- );
- }
- }
-
-
- // Make sure we are back on the same reader as where we started
- if (topElem->fReaderNum != fReaderMgr.getCurrentReaderNum())
- emitError(XMLErrs::PartialTagMarkupError);
-
- // Skip optional whitespace
- fReaderMgr.skipPastSpaces();
-
- // Make sure we find the closing bracket
- if (!fReaderMgr.skippedChar(chCloseAngle))
- {
- emitError
- (
- XMLErrs::UnterminatedEndTag
- , topElem->fThisElement->getFullName()
- );
- }
-
- //
- // If validation is enabled, then lets pass him the list of children and
- // this element and let him validate it.
- //
- if (fValidate)
- {
- int res = fValidator->checkContent
- (
- topElem->fThisElement
- , topElem->fChildren
- , topElem->fChildCount
- );
-
- if (res >= 0)
- {
- //
- // One of the elements is not valid for the content. NOTE that
- // if no children were provided but the content model requires
- // them, it comes back with a zero value. But we cannot use that
- // to index the child array in this case, and have to put out a
- // special message.
- //
- if (!topElem->fChildCount)
- {
- fValidator->emitError
- (
- XMLValid::EmptyNotValidForContent
- , topElem->fThisElement->getFormattedContentModel()
- );
- }
- else if ((unsigned int)res >= topElem->fChildCount)
- {
- fValidator->emitError
- (
- XMLValid::NotEnoughElemsForCM
- , topElem->fThisElement->getFormattedContentModel()
- );
- }
- else
- {
- fValidator->emitError
- (
- XMLValid::ElementNotValidForContent
- , topElem->fChildren[res]->getRawName()
- , topElem->fThisElement->getFormattedContentModel()
- );
- }
- }
-
- // reset xsi:type ComplexTypeInfo
- if (fGrammarType == Grammar::SchemaGrammarType) {
- ((SchemaElementDecl*)topElem->fThisElement)->setXsiComplexTypeInfo(0);
-
- // call matchers and de-activate context
- int oldCount = fMatcherStack->getMatcherCount();
-
- if (oldCount ||
- ((SchemaElementDecl*)topElem->fThisElement)->getIdentityConstraintCount()) {
-
- for (int i = oldCount - 1; i >= 0; i--) {
-
- XPathMatcher* matcher = fMatcherStack->getMatcherAt(i);
- matcher->endElement(*(topElem->fThisElement));
- }
-
- if (fMatcherStack->size() > 0) {
- fMatcherStack->popContext();
- }
-
- // handle everything *but* keyref's.
- int newCount = fMatcherStack->getMatcherCount();
-
- for (int j = oldCount - 1; j >= newCount; j--) {
-
- XPathMatcher* matcher = fMatcherStack->getMatcherAt(j);
- IdentityConstraint* ic = matcher->getIdentityConstraint();
-
- if (ic && (ic->getType() != IdentityConstraint::KEYREF)) {
-
- matcher->endDocumentFragment();
- fValueStoreCache->transplant(ic, matcher->getInitialDepth());
- }
- else if (!ic) {
- matcher->endDocumentFragment();
- }
- }
-
- // now handle keyref's...
- for (int k = oldCount - 1; k >= newCount; k--) {
-
- XPathMatcher* matcher = fMatcherStack->getMatcherAt(k);
- IdentityConstraint* ic = matcher->getIdentityConstraint();
-
- if (ic && (ic->getType() == IdentityConstraint::KEYREF)) {
-
- ValueStore* values = fValueStoreCache->getValueStoreFor(ic, matcher->getInitialDepth());
-
- if (values) { // nothing to do if nothing matched!
- values->endDcocumentFragment(fValueStoreCache);
- }
-
- matcher->endDocumentFragment();
- }
- }
-
- fValueStoreCache->endElement();
- }
- }
- }
-
- // If we have a doc handler, tell it about the end tag
- if (fDocHandler)
- {
- fDocHandler->endElement
- (
- *topElem->fThisElement
- , uriId
- , isRoot
- , bbPrefix.getRawBuffer()
- );
- }
-
- // If this was the root, then done with content
- gotData = !isRoot;
-
- if (gotData) {
- if (fDoNamespaces) {
- // Restore the grammar
- fGrammar = fElemStack.getCurrentGrammar();
- fGrammarType = fGrammar->getGrammarType();
- if (fGrammarType == Grammar::SchemaGrammarType && !fValidator->handlesSchema()) {
- if (fValidatorFromUser)
- ThrowXML(RuntimeException, XMLExcepts::Gen_NoSchemaValidator);
- else {
- fValidator = fSchemaValidator;
- }
- }
- else if (fGrammarType == Grammar::DTDGrammarType && !fValidator->handlesDTD()) {
- if (fValidatorFromUser)
- ThrowXML(RuntimeException, XMLExcepts::Gen_NoDTDValidator);
- else {
- fValidator = fDTDValidator;
- }
- }
-
- fValidator->setGrammar(fGrammar);
- }
-
- // Restore the validation flag
- fValidate = fElemStack.getValidationFlag();
- }
-}
-
-
-//
-// This method is called after the end of the root element, to handle
-// any miscellaneous stuff hanging around.
-//
-void XMLScanner::scanMiscellaneous()
-{
- // Get a buffer for this work
- XMLBufBid bbCData(&fBufMgr);
-
- while (true)
- {
- try
- {
- const XMLCh nextCh = fReaderMgr.peekNextChar();
-
- // Watch for end of file and break out
- if (!nextCh)
- break;
-
- if (nextCh == chOpenAngle)
- {
- if (checkXMLDecl(true))
- {
- // Can't have an XML decl here
- emitError(XMLErrs::NotValidAfterContent);
- fReaderMgr.skipPastChar(chCloseAngle);
- }
- else if (fReaderMgr.skippedString(XMLUni::fgPIString))
- {
- scanPI();
- }
- else if (fReaderMgr.skippedString(XMLUni::fgCommentString))
- {
- scanComment();
- }
- else
- {
- // This can't be possible, so just give up
- emitError(XMLErrs::ExpectedCommentOrPI);
- fReaderMgr.skipPastChar(chCloseAngle);
- }
- }
- else if (XMLReader::isWhitespace(nextCh))
- {
- //
- // If we have a doc handler, then gather up the spaces and
- // call back. Otherwise, just skip over whitespace.
- //
- if (fDocHandler)
- {
- fReaderMgr.getSpaces(bbCData.getBuffer());
- fDocHandler->ignorableWhitespace
- (
- bbCData.getRawBuffer()
- , bbCData.getLen()
- , false
- );
- }
- else
- {
- fReaderMgr.skipPastSpaces();
- }
- }
- else
- {
- emitError(XMLErrs::ExpectedCommentOrPI);
- fReaderMgr.skipPastChar(chCloseAngle);
- }
- }
-
- catch(const EndOfEntityException&)
- {
- //
- // Some entity leaked out of the content part of the document. Issue
- // a warning and keep going.
- //
- emitError(XMLErrs::EntityPropogated);
- }
- }
-}
-
-
-//
-// Scans a PI and calls the appropriate callbacks. At entry we have just
-// scanned the <? part, and need to now start on the PI target name.
-//
-void XMLScanner::scanPI()
-{
- const XMLCh* namePtr = 0;
- const XMLCh* targetPtr = 0;
-
- //
- // If there are any spaces here, then warn about it. If we aren't in
- // 'first error' mode, then we'll come back and can easily pick up
- // again by just skipping them.
- //
- if (fReaderMgr.lookingAtSpace())
- {
- emitError(XMLErrs::PINameExpected);
- fReaderMgr.skipPastSpaces();
- }
-
- // Get a buffer for the PI name and scan it in
- XMLBufBid bbName(&fBufMgr);
- if (!fReaderMgr.getName(bbName.getBuffer()))
- {
- emitError(XMLErrs::PINameExpected);
- fReaderMgr.skipPastChar(chCloseAngle);
- return;
- }
-
- // Point the name pointer at the raw data
- namePtr = bbName.getRawBuffer();
-
- // See if it is some form of 'xml' and emit a warning
- if (!XMLString::compareIString(namePtr, XMLUni::fgXMLString))
- emitError(XMLErrs::NoPIStartsWithXML);
-
- // If namespaces are enabled, then no colons allowed
- if (fDoNamespaces)
- {
- if (XMLString::indexOf(namePtr, chColon) != -1)
- emitError(XMLErrs::ColonNotLegalWithNS);
- }
-
- //
- // If we don't hit a space next, then the PI has no target. If we do
- // then get out the target. Get a buffer for it as well
- //
- XMLBufBid bbTarget(&fBufMgr);
- if (fReaderMgr.skippedSpace())
- {
- // Skip any leading spaces
- fReaderMgr.skipPastSpaces();
-
- bool gotLeadingSurrogate = false;
-
- // It does have a target, so lets move on to deal with that.
- while (1)
- {
- const XMLCh nextCh = fReaderMgr.getNextChar();
-
- // Watch for an end of file, which is always bad here
- if (!nextCh)
- {
- emitError(XMLErrs::UnterminatedPI);
- ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
- }
-
- // Watch for potential terminating character
- if (nextCh == chQuestion)
- {
- // It must be followed by '>' to be a termination of the target
- if (fReaderMgr.skippedChar(chCloseAngle))
- break;
- }
-
- // Check for correct surrogate pairs
- if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
- {
- if (gotLeadingSurrogate)
- emitError(XMLErrs::Expected2ndSurrogateChar);
- else
- gotLeadingSurrogate = true;
- }
- else
- {
- if (gotLeadingSurrogate)
- {
- if ((nextCh < 0xDC00) || (nextCh > 0xDFFF))
- emitError(XMLErrs::Expected2ndSurrogateChar);
- }
- // Its got to at least be a valid XML character
- else if (!XMLReader::isXMLChar(nextCh)) {
-
- XMLCh tmpBuf[9];
- XMLString::binToText
- (
- nextCh
- , tmpBuf
- , 8
- , 16
- );
- emitError(XMLErrs::InvalidCharacter, tmpBuf);
- }
-
- gotLeadingSurrogate = false;
- }
-
- bbTarget.append(nextCh);
- }
- }
- else
- {
- // No target, but make sure its terminated ok
- if (!fReaderMgr.skippedChar(chQuestion))
- {
- emitError(XMLErrs::UnterminatedPI);
- fReaderMgr.skipPastChar(chCloseAngle);
- return;
- }
-
- if (!fReaderMgr.skippedChar(chCloseAngle))
- {
- emitError(XMLErrs::UnterminatedPI);
- fReaderMgr.skipPastChar(chCloseAngle);
- return;
- }
- }
-
- // Point the target pointer at the raw data
- targetPtr = bbTarget.getRawBuffer();
-
- // If we have a handler, then call it
- if (fDocHandler)
- {
- fDocHandler->docPI
- (
- namePtr
- , targetPtr
- );
- }
-}
-
-//
-// Scans all the input from the start of the file to the root element.
-// There does not have to be anything in the prolog necessarily, but usually
-// there is at least an XMLDecl.
-//
-// On exit from here we are either at the end of the file or about to read
-// the opening < of the root element.
-//
-void XMLScanner::scanProlog()
-{
- // Get a buffer for whitespace processing
- XMLBufBid bbCData(&fBufMgr);
-
- //
- // Loop through the prolog. If there is no content, this could go all
- // the way to the end of the file.
- //
- try
- {
- while (true)
- {
- const XMLCh nextCh = fReaderMgr.peekNextChar();
-
- if (nextCh == chOpenAngle)
- {
- //
- // Ok, it could be the xml decl, a comment, the doc type line,
- // or the start of the root element.
- //
- if (checkXMLDecl(true))
- {
- // There shall be at lease --ONE-- space in between
- // the tag '<?xml' and the VersionInfo.
- //
- //
- // If we are not at line 1, col 6, then the decl was not
- // the first text, so its invalid.
- //
- const XMLReader* curReader = fReaderMgr.getCurrentReader();
- if ((curReader->getLineNumber() != 1)
- || (curReader->getColumnNumber() != 7))
- {
- emitError(XMLErrs::XMLDeclMustBeFirst);
- }
-
- scanXMLDecl(Decl_XML);
- }
- else if (fReaderMgr.skippedString(XMLUni::fgPIString))
- {
- scanPI();
- }
- else if (fReaderMgr.skippedString(XMLUni::fgCommentString))
- {
- scanComment();
- }
- else if (fReaderMgr.skippedString(XMLUni::fgDocTypeString))
- {
- scanDocTypeDecl();
-
- // if reusing grammar, this has been validated already in first scan
- // skip for performance
- if (fValidate && !fGrammar->getValidated()) {
- // validate the DTD scan so far
- fValidator->preContentValidation(fUseCachedGrammar, true);
- }
- }
- else
- {
- // Assume its the start of the root element
- return;
- }
- }
- else if (XMLReader::isWhitespace(nextCh))
- {
- //
- // If we have a document handler then gather up the
- // whitespace and call back. Otherwise just skip over spaces.
- //
- if (fDocHandler)
- {
- fReaderMgr.getSpaces(bbCData.getBuffer());
- fDocHandler->ignorableWhitespace
- (
- bbCData.getRawBuffer()
- , bbCData.getLen()
- , false
- );
- }
- else
- {
- fReaderMgr.skipPastSpaces();
- }
- }
- else
- {
- emitError(XMLErrs::InvalidDocumentStructure);
-
- // Watch for end of file and break out
- if (!nextCh)
- break;
- else
- fReaderMgr.skipPastChar(chCloseAngle);
- }
-
- }
- }
-
- catch(const EndOfEntityException&)
- {
- //
- // We should never get an end of entity here. They should only
- // occur within the doc type scanning method, and not leak out to
- // here.
- //
- emitError
- (
- XMLErrs::UnexpectedEOE
- , "in prolog"
- );
- }
-}
-
-//
-// This method handles the high level logic of scanning the DOCType
-// declaration. This calls the DTDScanner and kicks off both the scanning of
-// the internal subset and the scanning of the external subset, if any.
-//
-// When we get here the '<!DOCTYPE' part has already been scanned, which is
-// what told us that we had a doc type decl to parse.
-//
-
-void XMLScanner::scanDocTypeDecl()
-{
- //
- // We have a doc type. So, switch the Grammar.
- //
- switchGrammar(XMLUni::fgDTDEntityString);
-
- if (fDocTypeHandler)
- fDocTypeHandler->resetDocType();
-
- // There must be some space after DOCTYPE
- if (!fReaderMgr.skipPastSpaces())
- {
- emitError(XMLErrs::ExpectedWhitespace);
-
- // Just skip the Doctype declaration and return
- fReaderMgr.skipPastChar(chCloseAngle);
- return;
- }
-
- // Get a buffer for the root element
- XMLBufBid bbRootName(&fBufMgr);
-
- //
- // Get a name from the input, which should be the name of the root
- // element of the upcoming content.
- //
- fReaderMgr.getName(bbRootName.getBuffer());
- if (bbRootName.isEmpty())
- {
- emitError(XMLErrs::NoRootElemInDOCTYPE);
- fReaderMgr.skipPastChar(chCloseAngle);
- return;
- }
-
- //
- // Store the root element name for later check
- //
- setRootElemName(bbRootName.getRawBuffer());
-
- //
- // This element obviously is not going to exist in the element decl
- // pool yet, but we need to call docTypeDecl. So force it into
- // the element decl pool, marked as being there because it was in
- // the DOCTYPE. Later, when its declared, the status will be updated.
- //
- // Only do this if we are not reusing the validator! If we are reusing,
- // then look it up instead. It has to exist!
- //
- DTDElementDecl* rootDecl = new DTDElementDecl(bbRootName.getRawBuffer(), fEmptyNamespaceId);
-
- rootDecl->setCreateReason(DTDElementDecl::AsRootElem);
- rootDecl->setExternalElemDeclaration(true);
- ((DTDGrammar*)fGrammar)->setRootElemId(fGrammar->putElemDecl(rootDecl));
-
- // Skip any spaces after the name
- fReaderMgr.skipPastSpaces();
-
- //
- // And now if we are looking at a >, then we are done. It is not
- // required to have an internal or external subset, though why you
- // would not escapes me.
- //
- if (fReaderMgr.skippedChar(chCloseAngle)) {
- //
- // If we have a doc type handler and advanced callbacks are enabled,
- // call the doctype event.
- //
- if (fDocTypeHandler)
- fDocTypeHandler->doctypeDecl(*rootDecl, 0, 0, false);
- return;
- }
-
- // either internal/external subset
- if (fValScheme == Val_Auto && !fValidate)
- fValidate = true;
-
- bool hasIntSubset = false;
- bool hasExtSubset = false;
- XMLCh* sysId = 0;
- XMLCh* pubId = 0;
-
- DTDScanner dtdScanner((DTDGrammar*)fGrammar, fDocTypeHandler);
- dtdScanner.setScannerInfo(this, &fReaderMgr, &fBufMgr);
-
- //
- // If the next character is '[' then we have no external subset cause
- // there is no system id, just the opening character of the internal
- // subset. Else, has to be an id.
- //
- // Just look at the next char, don't eat it.
- if (fReaderMgr.peekNextChar() == chOpenSquare)
- {
- hasIntSubset = true;
- }
- else
- {
- // Indicate we have an external subset
- hasExtSubset = true;
- fHasNoDTD = false;
-
- // Get buffers for the ids
- XMLBufBid bbPubId(&fBufMgr);
- XMLBufBid bbSysId(&fBufMgr);
-
- // Get the external subset id
- if (!dtdScanner.scanId(bbPubId.getBuffer(), bbSysId.getBuffer(), DTDScanner::IDType_External))
- {
- fReaderMgr.skipPastChar(chCloseAngle);
- return;
- }
-
- // Get copies of the ids we got
- pubId = XMLString::replicate(bbPubId.getRawBuffer());
- sysId = XMLString::replicate(bbSysId.getRawBuffer());
-
- // Skip spaces and check again for the opening of an internal subset
- fReaderMgr.skipPastSpaces();
-
- // Just look at the next char, don't eat it.
- if (fReaderMgr.peekNextChar() == chOpenSquare) {
- hasIntSubset = true;
- }
- }
-
- // Insure that the ids get cleaned up, if they got allocated
- ArrayJanitor<XMLCh> janSysId(sysId);
- ArrayJanitor<XMLCh> janPubId(pubId);
-
- //
- // If we have a doc type handler and advanced callbacks are enabled,
- // call the doctype event.
- //
- if (fDocTypeHandler)
- fDocTypeHandler->doctypeDecl(*rootDecl, pubId, sysId, hasIntSubset, hasExtSubset);
-
- //
- // Ok, if we had an internal subset, we are just past the [ character
- // and need to parse that first.
- //
- if (hasIntSubset)
- {
- // Eat the opening square bracket
- fReaderMgr.getNextChar();
-
- // We can't have any internal subset if we are reusing the validator
- if (fUseCachedGrammar || fToCacheGrammar)
- ThrowXML(RuntimeException, XMLExcepts::Val_CantHaveIntSS);
-
- //
- // And try to scan the internal subset. If we fail, try to recover
- // by skipping forward tot he close angle and returning.
- //
- if (!dtdScanner.scanInternalSubset())
- {
- fReaderMgr.skipPastChar(chCloseAngle);
- return;
- }
-
- //
- // Do a sanity check that some expanded PE did not propogate out of
- // the doctype. This could happen if it was terminated early by bad
- // syntax.
- //
- if (fReaderMgr.getReaderDepth() > 1)
- {
- emitError(XMLErrs::PEPropogated);
-
- // Ask the reader manager to pop back down to the main level
- fReaderMgr.cleanStackBackTo(1);
- }
-
- fReaderMgr.skipPastSpaces();
- }
-
- // And that should leave us at the closing > of the DOCTYPE line
- if (!fReaderMgr.skippedChar(chCloseAngle))
- {
- //
- // Do a special check for the common scenario of an extra ] char at
- // the end. This is easy to recover from.
- //
- if (fReaderMgr.skippedChar(chCloseSquare)
- && fReaderMgr.skippedChar(chCloseAngle))
- {
- emitError(XMLErrs::ExtraCloseSquare);
- }
- else
- {
- emitError(XMLErrs::UnterminatedDOCTYPE);
- fReaderMgr.skipPastChar(chCloseAngle);
- }
- }
-
- //
- // If we had an external subset, then we need to deal with that one
- // next. If we are reusing the validator, then don't scan it.
- //
- if (hasExtSubset) {
-
- if (fUseCachedGrammar)
- {
- InputSource* sysIdSrc = resolveSystemId(sysId);
- Janitor<InputSource> janSysIdSrc(sysIdSrc);
- Grammar* grammar = fGrammarResolver->getGrammar(sysIdSrc->getSystemId());
-
- if (grammar && grammar->getGrammarType() == Grammar::DTDGrammarType) {
-
- fDTDGrammar = (DTDGrammar*) grammar;
- fGrammar = fDTDGrammar;
- fValidator->setGrammar(fGrammar);
- rootDecl = (DTDElementDecl*) fGrammar->getElemDecl(fEmptyNamespaceId, 0, bbRootName.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
-
- if (rootDecl)
- ((DTDGrammar*)fGrammar)->setRootElemId(rootDecl->getId());
- else {
- rootDecl = new DTDElementDecl(bbRootName.getRawBuffer(), fEmptyNamespaceId);
- rootDecl->setCreateReason(DTDElementDecl::AsRootElem);
- rootDecl->setExternalElemDeclaration(true);
- ((DTDGrammar*)fGrammar)->setRootElemId(fGrammar->putElemDecl(rootDecl));
- }
-
- return;
- }
- }
-
- if (fLoadExternalDTD || fValidate)
- {
- // And now create a reader to read this entity
- InputSource* srcUsed;
- XMLReader* reader = fReaderMgr.createReader
- (
- sysId
- , pubId
- , false
- , XMLReader::RefFrom_NonLiteral
- , XMLReader::Type_General
- , XMLReader::Source_External
- , srcUsed
- );
-
- // Put a janitor on the input source
- Janitor<InputSource> janSrc(srcUsed);
-
- //
- // If it failed then throw an exception
- //
- if (!reader)
- ThrowXML1(RuntimeException, XMLExcepts::Gen_CouldNotOpenDTD, srcUsed->getSystemId());
-
- if (fToCacheGrammar) {
-
- unsigned int stringId = fGrammarResolver->getStringPool()->addOrFind(srcUsed->getSystemId());
- const XMLCh* sysIdStr = fGrammarResolver->getStringPool()->getValueForId(stringId);
-
- fGrammarResolver->orphanGrammar(XMLUni::fgDTDEntityString);
- fGrammarResolver->putGrammar(sysIdStr, fGrammar);
- }
-
- //
- // In order to make the processing work consistently, we have to
- // make this look like an external entity. So create an entity
- // decl and fill it in and push it with the reader, as happens
- // with an external entity. Put a janitor on it to insure it gets
- // cleaned up. The reader manager does not adopt them.
- //
- const XMLCh gDTDStr[] = { chLatin_D, chLatin_T, chLatin_D , chNull };
- DTDEntityDecl* declDTD = new DTDEntityDecl(gDTDStr);
- declDTD->setSystemId(sysId);
- Janitor<DTDEntityDecl> janDecl(declDTD);
-
- // Mark this one as a throw at end
- reader->setThrowAtEnd(true);
-
- // And push it onto the stack, with its pseudo name
- fReaderMgr.pushReader(reader, declDTD);
-
- // Tell it its not in an include section
- dtdScanner.scanExtSubsetDecl(false);
- }
- }
-}
-
-bool XMLScanner::scanStartTag(bool& gotData)
-{
- //
- // Assume we will still have data until proven otherwise. It will only
- // ever be false if this is the root and its empty.
- //
- gotData = true;
-
- //
- // Get the QName. In this case, we are not doing namespaces, so we just
- // use it as is and don't have to break it into parts.
- //
- if (!fReaderMgr.getName(fQNameBuf))
- {
- emitError(XMLErrs::ExpectedElementName);
- fReaderMgr.skipToChar(chOpenAngle);
- return false;
- }
-
- // Assume it won't be an empty tag
- bool isEmpty = false;
-
- //
- // Lets try to look up the element in the validator's element decl pool
- // We can pass bogus values for the URI id and the base name. We know that
- // this can only be called if we are doing a DTD style validator and that
- // he will only look at the QName.
- //
- // We tell him to fault in a decl if he does not find one.
- //
- bool wasAdded = false;
- XMLElementDecl* elemDecl = fGrammar->findOrAddElemDecl
- (
- fEmptyNamespaceId
- , 0
- , 0
- , fQNameBuf.getRawBuffer()
- , Grammar::TOP_LEVEL_SCOPE
- , wasAdded
- );
-
- //
- // We do something different here according to whether we found the
- // element or not.
- //
- if (wasAdded)
- {
- // If validating then emit an error
- if (fValidate)
- {
- // This is to tell the reuse Validator that this element was
- // faulted-in, was not an element in the validator pool originally
- elemDecl->setCreateReason(XMLElementDecl::JustFaultIn);
-
- fValidator->emitError
- (
- XMLValid::ElementNotDefined
- , elemDecl->getFullName()
- );
- }
- }
- else
- {
- // If its not marked declared and validating, then emit an error
- if (fValidate && !elemDecl->isDeclared())
- {
- fValidator->emitError
- (
- XMLValid::ElementNotDefined
- , elemDecl->getFullName()
- );
- }
- }
-
- // See if its the root element
- const bool isRoot = fElemStack.isEmpty();
-
- // Expand the element stack and add the new element
- fElemStack.addLevel(elemDecl, fReaderMgr.getCurrentReaderNum());
- fElemStack.setValidationFlag(fValidate);
-
- // Validate the element
- if (fValidate)
- fValidator->validateElement(elemDecl);
-
- //
- // If this is the first element and we are validating, check the root
- // element.
- //
- if (isRoot)
- {
- fRootGrammar = fGrammar;
-
- if (fValidate)
- {
- // If a DocType exists, then check if it matches the root name there.
- if (fRootElemName && !XMLString::equals(fQNameBuf.getRawBuffer(), fRootElemName))
- fValidator->emitError(XMLValid::RootElemNotLikeDocType);
-
- // Some validators may also want to check the root, call the
- // XMLValidator::checkRootElement
- if (fValidatorFromUser && !fValidator->checkRootElement(elemDecl->getId()))
- fValidator->emitError(XMLValid::RootElemNotLikeDocType);
- }
- }
- else
- {
- //
- // If the element stack is not empty, then add this element as a
- // child of the previous top element. If its empty, this is the root
- // elem and is not the child of anything.
- //
- fElemStack.addChild(elemDecl->getElementName(), true);
- }
-
- //
- // Ask the element decl to clear out the 'provided' flag on all of its
- // att defs.
- //
- elemDecl->resetDefs();
-
- // Skip any whitespace after the name
- fReaderMgr.skipPastSpaces();
-
- //
- // We loop until we either see a /> or >, handling attribute/value
- // pairs until we get there.
- //
- unsigned int attCount = 0;
- unsigned int curAttListSize = fAttrList->size();
- while (true)
- {
- // And get the next non-space character
- XMLCh nextCh = fReaderMgr.peekNextChar();
-
- //
- // If the next character is not a slash or closed angle bracket,
- // then it must be whitespace, since whitespace is required
- // between the end of the last attribute and the name of the next
- // one.
- //
- if (attCount)
- {
- if ((nextCh != chForwardSlash) && (nextCh != chCloseAngle))
- {
- if (XMLReader::isWhitespace(nextCh))
- {
- // Ok, skip by them and peek another char
- fReaderMgr.skipPastSpaces();
- nextCh = fReaderMgr.peekNextChar();
- }
- else
- {
- // Emit the error but keep on going
- emitError(XMLErrs::ExpectedWhitespace);
- }
- }
- }
-
- //
- // Ok, here we first check for any of the special case characters.
- // If its not one, then we do the normal case processing, which
- // assumes that we've hit an attribute value, Otherwise, we do all
- // the special case checks.
- //
- if (!XMLReader::isSpecialStartTagChar(nextCh))
- {
- //
- // Assume its going to be an attribute, so get a name from
- // the input.
- //
- if (!fReaderMgr.getName(fAttNameBuf))
- {
- emitError(XMLErrs::ExpectedAttrName);
- fReaderMgr.skipPastChar(chCloseAngle);
- return false;
- }
-
- // And next must be an equal sign
- if (!scanEq())
- {
- static const XMLCh tmpList[] =
- {
- chSingleQuote, chDoubleQuote, chCloseAngle
- , chOpenAngle, chForwardSlash, chNull
- };
-
- emitError(XMLErrs::ExpectedEqSign);
-
- //
- // Try to sync back up by skipping forward until we either
- // hit something meaningful.
- //
- const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
-
- if ((chFound == chCloseAngle) || (chFound == chForwardSlash))
- {
- // Jump back to top for normal processing of these
- continue;
- }
- else if ((chFound == chSingleQuote)
- || (chFound == chDoubleQuote)
- || XMLReader::isWhitespace(chFound))
- {
- // Just fall through assuming that the value is to follow
- }
- else if (chFound == chOpenAngle)
- {
- // Assume a malformed tag and that new one is starting
- emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
- return false;
- }
- else
- {
- // Something went really wrong
- return false;
- }
- }
-
- //
- // See if this attribute is declared for this element. If we are
- // not validating of course it will not be at first, but we will
- // fault it into the pool (to avoid lots of redundant errors.)
- //
- wasAdded = false;
- XMLAttDef* attDef = elemDecl->findAttr
- (
- fAttNameBuf.getRawBuffer()
- , 0
- , 0
- , 0
- , XMLElementDecl::AddIfNotFound
- , wasAdded
- );
-
- if (wasAdded)
- {
- //
- // If there is a validation handler, then we are validating
- // so emit an error.
- //
- if (fValidate)
- {
- // This is to tell the Validator that this attribute was
- // faulted-in, was not an attribute in the attdef originally
- attDef->setCreateReason(XMLAttDef::JustFaultIn);
-
- fValidator->emitError
- (
- XMLValid::AttNotDefinedForElement
- , fAttNameBuf.getRawBuffer()
- , elemDecl->getFullName()
- );
- }
- }
- else
- {
- // If this attribute was faulted-in and first occurence,
- // then emit an error
- if (fValidate && attDef->getCreateReason() == XMLAttDef::JustFaultIn
- && !attDef->getProvided())
- {
- fValidator->emitError
- (
- XMLValid::AttNotDefinedForElement
- , fAttNameBuf.getRawBuffer()
- , elemDecl->getFullName()
- );
- }
- }
-
- //
- // If its already provided, then there are more than one of
- // this attribute in this start tag, so emit an error.
- //
- if (attDef->getProvided())
- {
- emitError
- (
- XMLErrs::AttrAlreadyUsedInSTag
- , attDef->getFullName()
- , elemDecl->getFullName()
- );
- }
- else
- {
- // Mark this one as already seen
- attDef->setProvided(true);
- }
-
- //
- // Skip any whitespace before the value and then scan the att
- // value. This will come back normalized with entity refs and
- // char refs expanded.
- //
- fReaderMgr.skipPastSpaces();
- if (!scanAttValue(attDef, fAttValueBuf))
- {
- static const XMLCh tmpList[] =
- {
- chCloseAngle, chOpenAngle, chForwardSlash, chNull
- };
-
- emitError(XMLErrs::ExpectedAttrValue);
-
- //
- // It failed, so lets try to get synced back up. We skip
- // forward until we find some whitespace or one of the
- // chars in our list.
- //
- const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
-
- if ((chFound == chCloseAngle)
- || (chFound == chForwardSlash)
- || XMLReader::isWhitespace(chFound))
- {
- //
- // Just fall through and process this attribute, though
- // the value will be "".
- //
- }
- else if (chFound == chOpenAngle)
- {
- // Assume a malformed tag and that new one is starting
- emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
- return false;
- }
- else
- {
- // Something went really wrong
- return false;
- }
- }
-
- //
- // Now that its all stretched out, lets look at its type and
- // determine if it has a valid value. It will output any needed
- // errors, but we just keep going. We only need to do this if
- // we are validating.
- //
- if (!wasAdded && attDef->getCreateReason() != XMLAttDef::JustFaultIn)
- {
- // Let the validator pass judgement on the attribute value
- if (fValidate)
- {
- fValidator->validateAttrValue
+ fReaderMgr.getSpaces(bbCData.getBuffer());
+ fDocHandler->ignorableWhitespace
(
- attDef
- , fAttValueBuf.getRawBuffer()
+ bbCData.getRawBuffer()
+ , bbCData.getLen()
, false
- , elemDecl
);
}
- }
-
- //
- // Add this attribute to the attribute list that we use to
- // pass them to the handler. We reuse its existing elements
- // but expand it as required.
- //
- XMLAttr* curAtt;
- if (attCount >= curAttListSize)
- {
- curAtt = new XMLAttr
- (
- -1
- , fAttNameBuf.getRawBuffer()
- , XMLUni::fgZeroLenString
- , fAttValueBuf.getRawBuffer()
- , attDef->getType()
- , true
- );
- fAttrList->addElement(curAtt);
- }
- else
- {
- curAtt = fAttrList->elementAt(attCount);
- curAtt->set
- (
- -1
- , fAttNameBuf.getRawBuffer()
- , XMLUni::fgZeroLenString
- , fAttValueBuf.getRawBuffer()
- , attDef->getType()
- );
- curAtt->setSpecified(true);
- }
- attCount++;
-
- // And jump back to the top of the loop
- continue;
- }
-
- //
- // It was some special case character so do all of the checks and
- // deal with it.
- //
- if (!nextCh)
- ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
-
- if (nextCh == chForwardSlash)
- {
- fReaderMgr.getNextChar();
- isEmpty = true;
- if (!fReaderMgr.skippedChar(chCloseAngle))
- emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
- break;
- }
- else if (nextCh == chCloseAngle)
- {
- fReaderMgr.getNextChar();
- break;
- }
- else if (nextCh == chOpenAngle)
- {
- //
- // Check for this one specially, since its going to be common
- // and it is kind of auto-recovering since we've already hit the
- // next open bracket, which is what we would have seeked to (and
- // skipped this whole tag.)
- //
- emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
- break;
- }
- else if ((nextCh == chSingleQuote) || (nextCh == chDoubleQuote))
- {
- //
- // Check for this one specially, which is probably a missing
- // attribute name, e.g. ="value". Just issue expected name
- // error and eat the quoted string, then jump back to the
- // top again.
- //
- emitError(XMLErrs::ExpectedAttrName);
- fReaderMgr.getNextChar();
- fReaderMgr.skipQuotedString(nextCh);
- fReaderMgr.skipPastSpaces();
- continue;
- }
- }
-
- //
- // Ok, so lets get an enumerator for the attributes of this element
- // and run through them for well formedness and validity checks. But
- // make sure that we had any attributes before we do it, since the list
- // would have have gotten faulted in anyway.
- //
- if (elemDecl->hasAttDefs())
- {
- XMLAttDefList& attDefList = elemDecl->getAttDefList();
- while (attDefList.hasMoreElements())
- {
- // Get the current att def, for convenience and its def type
- const XMLAttDef& curDef = attDefList.nextElement();
- const XMLAttDef::DefAttTypes defType = curDef.getDefaultType();
-
- if (!curDef.getProvided())
- {
- if (fValidate)
- {
- // If we are validating and its required, then an error
- if (defType == XMLAttDef::Required)
- {
- fValidator->emitError
- (
- XMLValid::RequiredAttrNotProvided
- , curDef.getFullName()
- );
- }
- else if ((defType == XMLAttDef::Default) ||
- (defType == XMLAttDef::Fixed) )
- {
- if (fStandalone && curDef.isExternal())
- {
- //
- // XML 1.0 Section 2.9
- // Document is standalone, so attributes must not be defaulted.
- //
- fValidator->emitError(XMLValid::NoDefAttForStandalone, curDef.getFullName(), elemDecl->getFullName());
- }
- }
- }
-
- // Fault in the value if needed, and bump the att count
- if ((defType == XMLAttDef::Default)
- || (defType == XMLAttDef::Fixed))
+ else
{
- // Let the validator pass judgement on the attribute value
- if (fValidate)
- {
- fValidator->validateAttrValue
- (
- &curDef
- , curDef.getValue()
- , false
- , elemDecl
- );
- }
-
- XMLAttr* curAtt;
- if (attCount >= curAttListSize)
- {
- curAtt = new XMLAttr
- (
- -1
- , curDef.getFullName()
- , XMLUni::fgZeroLenString
- , curDef.getValue()
- , curDef.getType()
- , false
- );
- fAttrList->addElement(curAtt);
- curAttListSize++;
- }
- else
- {
- curAtt = fAttrList->elementAt(attCount);
- curAtt->set
- (
- -1
- , curDef.getFullName()
- , XMLUni::fgZeroLenString
- , curDef.getValue()
- , curDef.getType()
- );
- curAtt->setSpecified(false);
- }
- attCount++;
+ fReaderMgr.skipPastSpaces();
}
}
- }
- }
-
- //
- // If empty, validate content right now if we are validating and then
- // pop the element stack top. Else, we have to update the current stack
- // top's namespace mapping elements.
- //
- if (isEmpty)
- {
- // If validating, then insure that its legal to have no content
- if (fValidate)
- {
- const int res = fValidator->checkContent(elemDecl, 0, 0);
- if (res >= 0)
+ else
{
- fValidator->emitError
- (
- XMLValid::ElementNotValidForContent
- , elemDecl->getFullName()
- , elemDecl->getFormattedContentModel()
- );
+ emitError(XMLErrs::ExpectedCommentOrPI);
+ fReaderMgr.skipPastChar(chCloseAngle);
}
}
-
- // Pop the element stack back off since it'll never be used now
- fElemStack.popTop();
-
- // If the elem stack is empty, then it was an empty root
- if (isRoot)
- gotData = false;
- else {
- // Restore the validation flag
- fValidate = fElemStack.getValidationFlag();
+ catch(const EndOfEntityException&)
+ {
+ // Some entity leaked out of the content part of the document. Issue
+ // a warning and keep going.
+ emitError(XMLErrs::EntityPropogated);
}
}
-
- //
- // If we have a document handler, then tell it about this start tag. We
- // don't have any URI id to send along, so send fEmptyNamespaceId. We also do not send
- // any prefix since its just one big name if we are not doing namespaces.
- //
- if (fDocHandler)
- {
- fDocHandler->startElement
- (
- *elemDecl
- , fEmptyNamespaceId
- , 0
- , *fAttrList
- , attCount
- , isEmpty
- , isRoot
- );
- }
-
- return true;
}
-//
-//
-// This method is called to scan a start tag when we are processing
-// namespaces. There are two different versions of this method, one for
-// namespace aware processing an done for non-namespace aware processing.
-//
-// This method is called after we've scanned the < of a start tag. So we
-// have to get the element name, then scan the attributes, after which
-// we are either going to see >, />, or attributes followed by one of those
-// sequences.
-//
-bool XMLScanner::scanStartTagNS(bool& gotData)
+// Scans a PI and calls the appropriate callbacks. At entry we have just
+// scanned the <? part, and need to now start on the PI target name.
+void XMLScanner::scanPI()
{
- //
- // Assume we will still have data until proven otherwise. It will only
- // ever be false if this is the root and its empty.
- //
- gotData = true;
+ const XMLCh* namePtr = 0;
+ const XMLCh* targetPtr = 0;
- //
- // The current position is after the open bracket, so we need to read in
- // in the element name.
- //
- if (!fReaderMgr.getName(fQNameBuf))
+ // If there are any spaces here, then warn about it. If we aren't in
+ // 'first error' mode, then we'll come back and can easily pick up
+ // again by just skipping them.
+ if (fReaderMgr.lookingAtSpace())
{
- emitError(XMLErrs::ExpectedElementName);
- fReaderMgr.skipToChar(chOpenAngle);
- return false;
+ emitError(XMLErrs::PINameExpected);
+ fReaderMgr.skipPastSpaces();
}
- //
- // Do a little sanity check here. One common problem is that
- // badly encoded files cause getName() to exit above on a
- // non-name char (an invalid XML char), then the scan start
- // tag below fails. This is misleading, so check here that
- // we are looking at a valid XML char.
- //
- if (!XMLReader::isXMLChar(fReaderMgr.peekNextChar()))
+ // Get a buffer for the PI name and scan it in
+ XMLBufBid bbName(&fBufMgr);
+ if (!fReaderMgr.getName(bbName.getBuffer()))
{
- XMLCh tmpBuf[9];
- XMLString::binToText
- (
- fReaderMgr.getNextChar()
- , tmpBuf
- , 8
- , 16
- );
- emitError(XMLErrs::InvalidCharacter, tmpBuf);
- }
-
- // See if its the root element
- const bool isRoot = fElemStack.isEmpty();
-
- // Skip any whitespace after the name
- fReaderMgr.skipPastSpaces();
-
- //
- // First we have to do the rawest attribute scan. We don't do any
- // normalization of them at all, since we don't know yet what type they
- // might be (since we need the element decl in order to do that.)
- //
- bool isEmpty;
- unsigned int attCount = rawAttrScan
- (
- fQNameBuf.getRawBuffer()
- , *fRawAttrList
- , isEmpty
- );
- const bool gotAttrs = (attCount != 0);
-
- // save the contentleafname and currentscope before addlevel, for later use
- ContentLeafNameTypeVector* cv = 0;
- XMLContentModel* cm = 0;
- int currentScope = Grammar::TOP_LEVEL_SCOPE;
- if (!isRoot && fGrammarType == Grammar::SchemaGrammarType) {
- SchemaElementDecl* tempElement = (SchemaElementDecl*) fElemStack.topElement()->fThisElement;
- SchemaElementDecl::ModelTypes modelType = tempElement->getModelType();
-
- if ((modelType == SchemaElementDecl::Mixed_Simple)
- || (modelType == SchemaElementDecl::Mixed_Complex)
- || (modelType == SchemaElementDecl::Children))
- {
- cm = tempElement->getContentModel();
- cv = cm->getContentLeafNameTypeVector();
- currentScope = fElemStack.getCurrentScope();
- }
- }
-
- //
- // Now, since we might have to update the namespace map for this element,
- // but we don't have the element decl yet, we just tell the element stack
- // to expand up to get ready.
- //
- unsigned int elemDepth = fElemStack.addLevel();
- fElemStack.setValidationFlag(fValidate);
-
- // Check if there is any external schema location specified, and if we are at root,
- // go through them first before scanning those specified in the instance document
- if (isRoot
- && fDoSchema
- && (fExternalSchemaLocation || fExternalNoNamespaceSchemaLocation)) {
-
- if (fExternalSchemaLocation)
- parseSchemaLocation(fExternalSchemaLocation);
- if (fExternalNoNamespaceSchemaLocation)
- resolveSchemaGrammar(fExternalNoNamespaceSchemaLocation, XMLUni::fgZeroLenString);
- }
-
- //
- // Make an initial pass through the list and find any xmlns attributes or
- // schema attributes.
- //
- if (attCount)
- scanRawAttrListforNameSpaces(fRawAttrList, attCount);
-
- //
- // Also find any default or fixed xmlns attributes in DTD defined for
- // this element.
- //
- if (fGrammarType == Grammar::DTDGrammarType) {
- XMLElementDecl* elemDecl = fGrammar->getElemDecl
- (
- fEmptyNamespaceId
- , 0
- , fQNameBuf.getRawBuffer()
- , Grammar::TOP_LEVEL_SCOPE
- );
- if (elemDecl) {
- if (elemDecl->hasAttDefs()) {
- XMLAttDefList& attDefList = elemDecl->getAttDefList();
- while (attDefList.hasMoreElements())
- {
- // Get the current att def, for convenience and its def type
- const XMLAttDef& curDef = attDefList.nextElement();
- const XMLAttDef::DefAttTypes defType = curDef.getDefaultType();
-
- // update the NSMap if there are any default/fixed xmlns attributes
- if ((defType == XMLAttDef::Default)
- || (defType == XMLAttDef::Fixed))
- {
- const XMLCh* rawPtr = curDef.getFullName();
- if (!XMLString::compareNString(rawPtr, XMLUni::fgXMLNSColonString, 6)
- || XMLString::equals(rawPtr, XMLUni::fgXMLNSString))
- updateNSMap(rawPtr, curDef.getValue());
- }
- }
- }
- }
- }
-
- //
- // Resolve the qualified name to a URI and name so that we can look up
- // the element decl for this element. We have now update the prefix to
- // namespace map so we should get the correct element now.
- //
- unsigned int uriId = resolveQName
- (
- fQNameBuf.getRawBuffer()
- , fNameBuf
- , fPrefixBuf
- , ElemStack::Mode_Element
- );
-
- //if schema, check if we should lax or skip the validation of this element
- bool laxThisOne = false;
- if (cv) {
- QName element(fPrefixBuf.getRawBuffer(), fNameBuf.getRawBuffer(), uriId);
- // elementDepth will be > 0, as cv is only constructed if element is not
- // root.
- laxThisOne = laxElementValidation(&element, cv, cm, elemDepth - 1);
- }
-
- //
- // Look up the element now in the grammar. This will get us back a
- // generic element decl object. We tell him to fault one in if he does
- // not find it.
- //
- bool wasAdded = false;
- XMLElementDecl* elemDecl;
- const XMLCh* nameRawBuf = fNameBuf.getRawBuffer();
- const XMLCh* qnameRawBuf = fQNameBuf.getRawBuffer();
-
- if (uriId != fEmptyNamespaceId) {
-
- // Check in current grammar before switching if necessary
- elemDecl = fGrammar->getElemDecl
- (
- uriId
- , nameRawBuf
- , qnameRawBuf
- , currentScope
- );
-
- if (!elemDecl && (fURIStringPool->getId(fGrammar->getTargetNamespace()) != uriId)) {
- // not found, switch to the specified grammar
- const XMLCh* uriStr = getURIText(uriId);
- if (!switchGrammar(uriStr) && fValidate && !laxThisOne)
- {
- fValidator->emitError
- (
- XMLValid::GrammarNotFound
- ,uriStr
- );
- }
-
- elemDecl = fGrammar->getElemDecl
- (
- uriId
- , nameRawBuf
- , qnameRawBuf
- , currentScope
- );
- }
-
- if (!elemDecl && currentScope != Grammar::TOP_LEVEL_SCOPE) {
- // if not found, then it may be a reference, try TOP_LEVEL_SCOPE
- elemDecl = fGrammar->getElemDecl
- (
- uriId
- , nameRawBuf
- , qnameRawBuf
- , Grammar::TOP_LEVEL_SCOPE
- );
-
- if(!elemDecl) {
- // still not found in specified uri
- // try emptyNamesapce see if element should be un-qualified.
- elemDecl = fGrammar->getElemDecl
- (
- fEmptyNamespaceId
- , nameRawBuf
- , qnameRawBuf
- , currentScope
- );
-
- if (elemDecl && elemDecl->getCreateReason() != XMLElementDecl::JustFaultIn && fValidate) {
- fValidator->emitError
- (
- XMLValid::ElementNotUnQualified
- , elemDecl->getFullName()
- );
- }
- }
- }
-
- if (!elemDecl) {
- // still not found, fault this in and issue error later
- elemDecl = fGrammar->putElemDecl(uriId
- , nameRawBuf
- , fPrefixBuf.getRawBuffer()
- , qnameRawBuf
- , currentScope
- , true);
- wasAdded = true;
- }
+ emitError(XMLErrs::PINameExpected);
+ fReaderMgr.skipPastChar(chCloseAngle);
+ return;
}
- else
- {
- //the element has no prefix,
- //thus it is either a non-qualified element defined in current targetNS
- //or an element that is defined in the globalNS
-
- //try unqualifed first
- elemDecl = fGrammar->getElemDecl
- (
- uriId
- , nameRawBuf
- , qnameRawBuf
- , currentScope
- );
-
- unsigned orgGrammarUri = fURIStringPool->getId(fGrammar->getTargetNamespace());
-
- if (!elemDecl && orgGrammarUri != fEmptyNamespaceId) {
- //not found, switch grammar and try globalNS
- if (!switchGrammar(XMLUni::fgZeroLenString) && fValidate && !laxThisOne)
- {
- fValidator->emitError
- (
- XMLValid::GrammarNotFound
- , XMLUni::fgZeroLenString
- );
- }
-
- elemDecl = fGrammar->getElemDecl
- (
- uriId
- , nameRawBuf
- , qnameRawBuf
- , currentScope
- );
- }
-
- if (!elemDecl && currentScope != Grammar::TOP_LEVEL_SCOPE) {
- // if not found, then it may be a reference, try TOP_LEVEL_SCOPE
- elemDecl = fGrammar->getElemDecl
- (
- uriId
- , nameRawBuf
- , qnameRawBuf
- , Grammar::TOP_LEVEL_SCOPE
- );
-
- if (!elemDecl && orgGrammarUri != fEmptyNamespaceId) {
- // still Not found in specified uri
- // go to original Grammar again to see if element needs to be fully qualified.
- const XMLCh* uriStr = getURIText(orgGrammarUri);
- if (!switchGrammar(uriStr) && fValidate && !laxThisOne)
- {
- fValidator->emitError
- (
- XMLValid::GrammarNotFound
- ,uriStr
- );
- }
- elemDecl = fGrammar->getElemDecl
- (
- orgGrammarUri
- , nameRawBuf
- , qnameRawBuf
- , currentScope
- );
+ // Point the name pointer at the raw data
+ namePtr = bbName.getRawBuffer();
- if (elemDecl && elemDecl->getCreateReason() != XMLElementDecl::JustFaultIn && fValidate) {
- fValidator->emitError
- (
- XMLValid::ElementNotQualified
- , elemDecl->getFullName()
- );
- }
- }
- }
+ // See if it is some form of 'xml' and emit a warning
+ if (!XMLString::compareIString(namePtr, XMLUni::fgXMLString))
+ emitError(XMLErrs::NoPIStartsWithXML);
- if (!elemDecl) {
- // still not found, fault this in and issue error later
- elemDecl = fGrammar->putElemDecl(uriId
- , nameRawBuf
- , fPrefixBuf.getRawBuffer()
- , qnameRawBuf
- , currentScope
- , true);
- wasAdded = true;
- }
+ // If namespaces are enabled, then no colons allowed
+ if (fDoNamespaces)
+ {
+ if (XMLString::indexOf(namePtr, chColon) != -1)
+ emitError(XMLErrs::ColonNotLegalWithNS);
}
- //
- // We do something different here according to whether we found the
- // element or not.
- //
- if (wasAdded)
+ // If we don't hit a space next, then the PI has no target. If we do
+ // then get out the target. Get a buffer for it as well
+ XMLBufBid bbTarget(&fBufMgr);
+ if (fReaderMgr.skippedSpace())
{
- if (laxThisOne) {
- fValidate = false;
- fElemStack.setValidationFlag(fValidate);
- }
+ // Skip any leading spaces
+ fReaderMgr.skipPastSpaces();
+
+ bool gotLeadingSurrogate = false;
- // If validating then emit an error
- if (fValidate)
+ // It does have a target, so lets move on to deal with that.
+ while (1)
{
- // This is to tell the reuse Validator that this element was
- // faulted-in, was not an element in the grammar pool originally
- elemDecl->setCreateReason(XMLElementDecl::JustFaultIn);
+ const XMLCh nextCh = fReaderMgr.getNextChar();
- fValidator->emitError
- (
- XMLValid::ElementNotDefined
- , elemDecl->getFullName()
- );
- }
- }
- else
- {
- // If its not marked declared and validating, then emit an error
- if (!elemDecl->isDeclared()) {
- if (laxThisOne) {
- fValidate = false;
- fElemStack.setValidationFlag(fValidate);
+ // Watch for an end of file, which is always bad here
+ if (!nextCh)
+ {
+ emitError(XMLErrs::UnterminatedPI);
+ ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
}
- if (fValidate)
+ // Watch for potential terminating character
+ if (nextCh == chQuestion)
{
- fValidator->emitError
- (
- XMLValid::ElementNotDefined
- , elemDecl->getFullName()
- );
+ // It must be followed by '>' to be a termination of the target
+ if (fReaderMgr.skippedChar(chCloseAngle))
+ break;
}
- }
- if (fGrammarType == Grammar::SchemaGrammarType)
- ((SchemaElementDecl*)elemDecl)->setXsiComplexTypeInfo(0);
- }
-
- //
- // Now we can update the element stack to set the current element
- // decl. We expanded the stack above, but couldn't store the element
- // decl because we didn't know it yet.
- //
- fElemStack.setElement(elemDecl, fReaderMgr.getCurrentReaderNum());
- fElemStack.setCurrentURI(uriId);
-
- if (isRoot)
- fRootGrammar = fGrammar;
+ // Check for correct surrogate pairs
+ if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
+ {
+ if (gotLeadingSurrogate)
+ emitError(XMLErrs::Expected2ndSurrogateChar);
+ else
+ gotLeadingSurrogate = true;
+ }
+ else
+ {
+ if (gotLeadingSurrogate)
+ {
+ if ((nextCh < 0xDC00) || (nextCh > 0xDFFF))
+ emitError(XMLErrs::Expected2ndSurrogateChar);
+ }
+ // Its got to at least be a valid XML character
+ else if (!XMLReader::isXMLChar(nextCh)) {
- // Validate the element
- if (fValidate)
- fValidator->validateElement(elemDecl);
-
- if (fGrammarType == Grammar::SchemaGrammarType) {
- ComplexTypeInfo* typeinfo = ((SchemaElementDecl*)elemDecl)->getComplexTypeInfo();
- if (typeinfo) {
- currentScope = typeinfo->getScopeDefined();
-
- // switch grammar if the typeinfo has a different grammar (happens when there is xsi:type)
- XMLCh* typeName = typeinfo->getTypeName();
- const XMLCh poundStr[] = {chPound, chNull};
- if (!XMLString::startsWith(typeName, poundStr)) {
- const int comma = XMLString::indexOf(typeName, chComma);
- if (comma > 0) {
- XMLBuffer prefixBuf(comma+1);
- prefixBuf.append(typeName, comma);
- const XMLCh* uriStr = prefixBuf.getRawBuffer();
- if (!switchGrammar(uriStr) && fValidate && !laxThisOne)
- {
- fValidator->emitError
- (
- XMLValid::GrammarNotFound
- , prefixBuf.getRawBuffer()
- );
- }
+ XMLCh tmpBuf[9];
+ XMLString::binToText
+ (
+ nextCh
+ , tmpBuf
+ , 8
+ , 16
+ );
+ emitError(XMLErrs::InvalidCharacter, tmpBuf);
}
+
+ gotLeadingSurrogate = false;
}
- }
- fElemStack.setCurrentScope(currentScope);
- // Set element next state
- if (elemDepth >= fElemStateSize) {
- resizeElemState();
+ bbTarget.append(nextCh);
}
-
- fElemState[elemDepth] = 0;
-
}
-
- fElemStack.setCurrentGrammar(fGrammar);
-
- //
- // If this is the first element and we are validating, check the root
- // element.
- //
- if (isRoot)
+ else
{
- if (fValidate)
+ // No target, but make sure its terminated ok
+ if (!fReaderMgr.skippedChar(chQuestion))
{
- // If a DocType exists, then check if it matches the root name there.
- if (fRootElemName && !XMLString::equals(qnameRawBuf, fRootElemName))
- fValidator->emitError(XMLValid::RootElemNotLikeDocType);
-
- // Some validators may also want to check the root, call the
- // XMLValidator::checkRootElement
- if (fValidatorFromUser && !fValidator->checkRootElement(elemDecl->getId()))
- fValidator->emitError(XMLValid::RootElemNotLikeDocType);
+ emitError(XMLErrs::UnterminatedPI);
+ fReaderMgr.skipPastChar(chCloseAngle);
+ return;
}
- }
- else
- {
- //
- // If the element stack is not empty, then add this element as a
- // child of the previous top element. If its empty, this is the root
- // elem and is not the child of anything.
- //
- fElemStack.addChild(elemDecl->getElementName(), true);
- }
-
- //
- // Now lets get the fAttrList filled in. This involves faulting in any
- // defaulted and fixed attributes and normalizing the values of any that
- // we got explicitly.
- //
- // We update the attCount value with the total number of attributes, but
- // it goes in with the number of values we got during the raw scan of
- // explictly provided attrs above.
- //
- attCount = buildAttList(*fRawAttrList, attCount, elemDecl, *fAttrList);
- //
- // activate identity constraints
- //
- if (fValidate && fGrammar && fGrammarType == Grammar::SchemaGrammarType) {
-
- unsigned int count = ((SchemaElementDecl*) elemDecl)->getIdentityConstraintCount();
-
- if (count || fMatcherStack->getMatcherCount()) {
-
- fValueStoreCache->startElement();
- fMatcherStack->pushContext();
- fValueStoreCache->initValueStoresFor((SchemaElementDecl*) elemDecl, (int) elemDepth);
-
- for (unsigned int i = 0; i < count; i++) {
- activateSelectorFor(((SchemaElementDecl*) elemDecl)->getIdentityConstraintAt(i), (int) elemDepth);
- }
-
- // call all active identity constraints
- count = fMatcherStack->getMatcherCount();
-
- for (unsigned int j = 0; j < count; j++) {
-
- XPathMatcher* matcher = fMatcherStack->getMatcherAt(j);
- matcher->startElement(*elemDecl, uriId, fPrefixBuf.getRawBuffer(), *fAttrList, attCount);
- }
+ if (!fReaderMgr.skippedChar(chCloseAngle))
+ {
+ emitError(XMLErrs::UnterminatedPI);
+ fReaderMgr.skipPastChar(chCloseAngle);
+ return;
}
}
- // Since the element may have default values, call start tag now regardless if it is empty or not
- // If we have a document handler, then tell it about this start tag
+ // Point the target pointer at the raw data
+ targetPtr = bbTarget.getRawBuffer();
+
+ // If we have a handler, then call it
if (fDocHandler)
{
- fDocHandler->startElement
+ fDocHandler->docPI
(
- *elemDecl
- , uriId
- , fPrefixBuf.getRawBuffer()
- , *fAttrList
- , attCount
- , false
- , isRoot
- );
+ namePtr
+ , targetPtr
+ );
}
+}
- //
- // If empty, validate content right now if we are validating and then
- // pop the element stack top. Else, we have to update the current stack
- // top's namespace mapping elements.
- //
- if (isEmpty)
- {
- // Pop the element stack back off since it'll never be used now
- fElemStack.popTop();
+// Scans all the input from the start of the file to the root element.
+// There does not have to be anything in the prolog necessarily, but usually
+// there is at least an XMLDecl.
+//
+// On exit from here we are either at the end of the file or about to read
+// the opening < of the root element.
+void XMLScanner::scanProlog()
+{
+ // Get a buffer for whitespace processing
+ XMLBufBid bbCData(&fBufMgr);
- // If validating, then insure that its legal to have no content
- if (fValidate)
+ // Loop through the prolog. If there is no content, this could go all
+ // the way to the end of the file.
+ try
+ {
+ while (true)
{
- const int res = fValidator->checkContent(elemDecl, 0, 0);
- if (res >= 0)
- {
- fValidator->emitError
- (
- XMLValid::ElementNotValidForContent
- , elemDecl->getFullName()
- , elemDecl->getFormattedContentModel()
- );
- }
-
- if (fGrammarType == Grammar::SchemaGrammarType) {
-
- // reset xsi:type ComplexTypeInfo
- ((SchemaElementDecl*)elemDecl)->setXsiComplexTypeInfo(0);
-
- // call matchers and de-activate context
- int oldCount = fMatcherStack->getMatcherCount();
-
- if (oldCount || ((SchemaElementDecl*) elemDecl)->getIdentityConstraintCount()) {
-
- for (int i = oldCount - 1; i >= 0; i--) {
-
- XPathMatcher* matcher = fMatcherStack->getMatcherAt(i);
- matcher->endElement(*elemDecl);
- }
-
- if (fMatcherStack->size() > 0) {
- fMatcherStack->popContext();
- }
-
- // handle everything *but* keyref's.
- int newCount = fMatcherStack->getMatcherCount();
-
- for (int j = oldCount - 1; j >= newCount; j--) {
-
- XPathMatcher* matcher = fMatcherStack->getMatcherAt(j);
- IdentityConstraint* ic = matcher->getIdentityConstraint();
+ const XMLCh nextCh = fReaderMgr.peekNextChar();
- if (ic && (ic->getType() != IdentityConstraint::KEYREF)) {
-
- matcher->endDocumentFragment();
- fValueStoreCache->transplant(ic, matcher->getInitialDepth());
- }
- else if (!ic) {
- matcher->endDocumentFragment();
- }
+ if (nextCh == chOpenAngle)
+ {
+ // Ok, it could be the xml decl, a comment, the doc type line,
+ // or the start of the root element.
+ if (checkXMLDecl(true))
+ {
+ // There shall be at lease --ONE-- space in between
+ // the tag '<?xml' and the VersionInfo.
+ //
+ // If we are not at line 1, col 6, then the decl was not
+ // the first text, so its invalid.
+ const XMLReader* curReader = fReaderMgr.getCurrentReader();
+ if ((curReader->getLineNumber() != 1)
+ || (curReader->getColumnNumber() != 7))
+ {
+ emitError(XMLErrs::XMLDeclMustBeFirst);
}
- // now handle keyref's...
- for (int k = oldCount - 1; k >= newCount; k--) {
-
- XPathMatcher* matcher = fMatcherStack->getMatcherAt(k);
- IdentityConstraint* ic = matcher->getIdentityConstraint();
-
- if (ic && (ic->getType() == IdentityConstraint::KEYREF)) {
-
- ValueStore* values = fValueStoreCache->getValueStoreFor(ic, matcher->getInitialDepth());
-
- if (values) { // nothing to do if nothing matched!
- values->endDcocumentFragment(fValueStoreCache);
- }
+ scanXMLDecl(Decl_XML);
+ }
+ else if (fReaderMgr.skippedString(XMLUni::fgPIString))
+ {
+ scanPI();
+ }
+ else if (fReaderMgr.skippedString(XMLUni::fgCommentString))
+ {
+ scanComment();
+ }
+ else if (fReaderMgr.skippedString(XMLUni::fgDocTypeString))
+ {
+ scanDocTypeDecl();
- matcher->endDocumentFragment();
- }
+ // if reusing grammar, this has been validated already in first scan
+ // skip for performance
+ if (fValidate && !fGrammar->getValidated()) {
+ // validate the DTD scan so far
+ fValidator->preContentValidation(fUseCachedGrammar, true);
}
-
- fValueStoreCache->endElement();
}
- }
- }
-
- // If we have a doc handler, tell it about the end tag
- if (fDocHandler)
- {
- fDocHandler->endElement
- (
- *elemDecl
- , uriId
- , isRoot
- , fPrefixBuf.getRawBuffer()
- );
- }
-
- // If the elem stack is empty, then it was an empty root
- if (isRoot)
- gotData = false;
- else
- {
- // Restore the grammar
- fGrammar = fElemStack.getCurrentGrammar();
- fGrammarType = fGrammar->getGrammarType();
- if (fGrammarType == Grammar::SchemaGrammarType && !fValidator->handlesSchema()) {
- if (fValidatorFromUser)
- ThrowXML(RuntimeException, XMLExcepts::Gen_NoSchemaValidator);
- else {
- fValidator = fSchemaValidator;
+ else
+ {
+ // Assume its the start of the root element
+ return;
}
}
- else if (fGrammarType == Grammar::DTDGrammarType && !fValidator->handlesDTD()) {
- if (fValidatorFromUser)
- ThrowXML(RuntimeException, XMLExcepts::Gen_NoDTDValidator);
- else {
- fValidator = fDTDValidator;
+ else if (XMLReader::isWhitespace(nextCh))
+ {
+ // If we have a document handler then gather up the
+ // whitespace and call back. Otherwise just skip over spaces.
+ if (fDocHandler)
+ {
+ fReaderMgr.getSpaces(bbCData.getBuffer());
+ fDocHandler->ignorableWhitespace
+ (
+ bbCData.getRawBuffer()
+ , bbCData.getLen()
+ , false
+ );
+ }
+ else
+ {
+ fReaderMgr.skipPastSpaces();
}
}
+ else
+ {
+ emitError(XMLErrs::InvalidDocumentStructure);
- fValidator->setGrammar(fGrammar);
+ // Watch for end of file and break out
+ if (!nextCh)
+ break;
+ else
+ fReaderMgr.skipPastChar(chCloseAngle);
+ }
- // Restore the validation flag
- fValidate = fElemStack.getValidationFlag();
}
}
-
- return true;
+ catch(const EndOfEntityException&)
+ {
+ // We should never get an end of entity here. They should only
+ // occur within the doc type scanning method, and not leak out to
+ // here.
+ emitError
+ (
+ XMLErrs::UnexpectedEOE
+ , "in prolog"
+ );
+ }
}
-//
// Scans the <?xml .... ?> line. This stuff is all sequential so we don't
// do any state machine loop here. We just bull straight through it. It ends
// past the closing bracket. If there is a document handler, then its called
@@ -3860,7 +1123,6 @@
// The parameter tells us which type of decl we should expect, Text or XML.
// [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
// [77] TextDecl::= '<?xml' VersionInfo? EncodingDecl S? '?>'
-//
void XMLScanner::scanXMLDecl(const DeclTypes type)
{
// Get us some buffers to use
@@ -3870,12 +1132,10 @@
XMLBufBid bbDummy(&fBufMgr);
XMLBufBid bbName(&fBufMgr);
- //
// We use this little enum and array to keep up with what we found
// and what order we found them in. This lets us get them free form
// without too much overhead, but still know that they were in the
// wrong order.
- //
enum Strings
{
VersionString
@@ -3887,10 +1147,8 @@
};
int flags[StringCount] = { -1, -1, -1, -1 };
- //
// Also set up a list of buffers in the right order so that we know
// where to put stuff.
- //
XMLBuffer* buffers[StringCount] ;
buffers[0] = &bbVersion.getBuffer();
buffers[1] = &bbEncoding.getBuffer();
@@ -3913,9 +1171,7 @@
if (!spaceCount && curCount)
emitError(XMLErrs::ExpectedWhitespace);
- //
// Get characters up to the next whitespace or equal's sign.
- //
if (!scanUpToWSOr(nameBuf, chEqual))
emitError(XMLErrs::ExpectedDeclString);
@@ -3929,10 +1185,8 @@
else
curString = UnknownString;
- //
// If its an unknown string, then give that error. Else check to
// see if this one has been done already and give that error.
- //
if (curString == UnknownString)
emitError(XMLErrs::ExpectedDeclString, nameBuf.getRawBuffer());
else if (flags[curString] != -1)
@@ -3940,17 +1194,13 @@
else if (flags[curString] == -1)
flags[curString] = ++curCount;
- //
// Scan for an equal's sign. If we don't find it, issue an error
// but keep trying to go on.
- //
if (!scanEq())
emitError(XMLErrs::ExpectedEqSign);
- //
// Get a quote string into the buffer for the string that we are
// currently working on.
- //
if (!getQuotedString(*buffers[curString]))
{
emitError(XMLErrs::ExpectedQuotedString);
@@ -3987,11 +1237,9 @@
}
}
- //
// Make sure that the strings present are in order. We don't care about
// which ones are present at this point, just that any there are in the
// right order.
- //
int curTop = 0;
for (int index = VersionString; index < StandaloneString; index++)
{
@@ -4006,10 +1254,8 @@
}
}
- //
// If its an XML decl, the version must be present.
// If its a Text decl, then encoding must be present AND standalone must not be present.
- //
if ((type == Decl_XML) && (flags[VersionString] == -1))
emitError(XMLErrs::XMLVersionRequired);
else if (type == Decl_Text) {
@@ -4035,7 +1281,6 @@
// for the last parameter!
const XMLCh* actualEnc = fReaderMgr.getCurrentEncodingStr();
- //
// Ok, we've now seen the real encoding string, if there was one, so
// lets call back on the current reader and tell it what the real
// encoding string was. If it fails, that's because it represents some
@@ -4045,7 +1290,6 @@
// NOTE: This can fail for a number of reasons, such as a bogus encoding
// name or because its in flagrant contradiction of the auto-sensed
// format.
- //
if (flags[EncodingString] != -1)
{
if (!fReaderMgr.getCurrentReader()->setEncoding(bbEncoding.getRawBuffer()))
@@ -4054,10 +1298,7 @@
actualEnc = bbEncoding.getRawBuffer();
}
- //
// If we have a document handler then call the XML Decl callback.
- //
- //
if (fDocHandler)
{
fDocHandler->XMLDecl
@@ -4100,87 +1341,12 @@
return false;
}
-unsigned int
-XMLScanner::resolveQName( const XMLCh* const qName
- , XMLBuffer& nameBuf
- , XMLBuffer& prefixBuf
- , const ElemStack::MapModes mode)
-{
- // Reset both target buffers in case we don't get anything for either
- nameBuf.reset();
- prefixBuf.reset();
-
- //
- // Lets split out the qName into a URI and name buffer first. The URI
- // can be empty.
- //
- const int colonPos = XMLString::indexOf(qName, chColon);
- unsigned int uriId = 0;
- if (colonPos == -1)
- {
- //
- // Its all name with no prefix, so put the whole thing into the name
- // buffer. Then map the empty string to a URI, since the empty string
- // represents the default namespace. This will either return some
- // explicit URI which the default namespace is mapped to, or the
- // the default global namespace.
- //
- nameBuf.append(qName);
- bool unknown;
- uriId = fElemStack.mapPrefixToURI(prefixBuf.getRawBuffer(), mode, unknown);
-
- #if defined(XERCES_DEBUG)
- if (unknown)
- {
- // <TBD> This one should never be unknown
- }
- #endif
- }
- else
- {
- //
- // Copy the chars up to but not including the colon into the prefix
- // buffer.
- //
- prefixBuf.append(qName, colonPos);
-
- // And copy over the rest of the chars to the name buffer
- nameBuf.append(&qName[colonPos+1]);
-
- //
- // Watch for the special namespace prefixes. We always map these to
- // special URIs. 'xml' gets mapped to the official URI that its defined
- // to map to by the NS spec. xmlns gets mapped to a special place holder
- // URI that we define (so that it maps to something checkable.)
- //
- if (XMLString::equals(prefixBuf.getRawBuffer(), XMLUni::fgXMLNSString)) {
- uriId = fXMLNSNamespaceId;
-
- // if this is an element, it is an error to have xmlns as prefix
- if (mode == ElemStack::Mode_Element)
- emitError(XMLErrs::NoXMLNSAsElementPrefix, qName);
- }
- else if (XMLString::equals(prefixBuf.getRawBuffer(), XMLUni::fgXMLString))
- uriId = fXMLNamespaceId;
- else
- {
- bool unknown;
- uriId = fElemStack.mapPrefixToURI(prefixBuf.getRawBuffer(), mode, unknown);
- if (unknown)
- emitError(XMLErrs::UnknownPrefix, prefixBuf.getRawBuffer());
- }
- }
- return uriId;
-}
-
bool XMLScanner::checkXMLDecl(bool startWithAngle) {
- //
+
// [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
// [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
//
// [3] S ::= (#x20 | #x9 | #xD | #xA)+
- //
-
if (startWithAngle) {
if (fReaderMgr.peekString(XMLUni::fgXMLDeclString)) {
if (fReaderMgr.skippedString(XMLUni::fgXMLDeclStringSpace)
@@ -4195,10 +1361,8 @@
|| fReaderMgr.skippedString(XMLUni::fgXMLDeclStringLFU)
|| fReaderMgr.skippedString(XMLUni::fgXMLDeclStringCRU))
{
- //
// Just in case, check for upper case. If found, issue
// an error, but keep going.
- //
emitError(XMLErrs::XMLDeclMustBeLowerCase);
return true;
}
@@ -4218,10 +1382,8 @@
|| fReaderMgr.skippedString(XMLUni::fgXMLStringLFU)
|| fReaderMgr.skippedString(XMLUni::fgXMLStringCRU))
{
- //
// Just in case, check for upper case. If found, issue
// an error, but keep going.
- //
emitError(XMLErrs::XMLDeclMustBeLowerCase);
return true;
}
@@ -4233,44 +1395,6 @@
// ---------------------------------------------------------------------------
-// XMLScanner: Helper methos
-// ---------------------------------------------------------------------------
-void XMLScanner::resizeElemState() {
-
- unsigned int newSize = fElemStateSize * 2;
- unsigned int* newElemState = new unsigned int[newSize];
-
- // Copy the existing values
- unsigned int index = 0;
- for (; index < fElemStateSize; index++)
- newElemState[index] = fElemState[index];
-
- for (; index < newSize; index++)
- newElemState[index] = 0;
-
- // Delete the old array and udpate our members
- delete [] fElemState;
- fElemState = newElemState;
- fElemStateSize = newSize;
-}
-
-// ---------------------------------------------------------------------------
-// XMLScanner: IC activation methos
-// ---------------------------------------------------------------------------
-void XMLScanner::activateSelectorFor(IdentityConstraint* const ic, const int initialDepth) {
-
- IC_Selector* selector = ic->getSelector();
-
- if (!selector)
- return;
-
- XPathMatcher* matcher = selector->createMatcher(fFieldActivator, initialDepth);
-
- fMatcherStack->addMatcher(matcher);
- matcher->startDocumentFragment();
-}
-
-// ---------------------------------------------------------------------------
// XMLScanner: Grammar preparsing
// ---------------------------------------------------------------------------
Grammar* XMLScanner::loadGrammar(const XMLCh* const systemId
@@ -4283,21 +1407,18 @@
srcToUse = fEntityHandler->resolveEntity(XMLUni::fgZeroLenString, systemId);
}
- //
// First we try to parse it as a URL. If that fails, we assume its
// a file and try it that way.
- //
if (!srcToUse) {
try
{
- //
// Create a temporary URL. Since this is the primary document,
// it has to be fully qualified. If not, then assume we are just
// mistaking a file for a URL.
- //
XMLURL tmpURL(systemId);
- if (tmpURL.isRelative()) {
+ if (tmpURL.isRelative())
+ {
srcToUse = new LocalFileInputSource(systemId);
}
else
@@ -4331,231 +1452,431 @@
}
-Grammar* XMLScanner::loadGrammar(const InputSource& src
- , const short grammarType
- , const bool toCache)
+// ---------------------------------------------------------------------------
+// XMLScanner: Setter methods
+// ---------------------------------------------------------------------------
+void XMLScanner::setURIStringPool(XMLStringPool* const stringPool)
{
- try
+ fURIStringPool = stringPool;
+ fEmptyNamespaceId = fURIStringPool->addOrFind(XMLUni::fgZeroLenString);
+ fUnknownNamespaceId = fURIStringPool->addOrFind(XMLUni::fgUnknownURIName);
+ fXMLNamespaceId = fURIStringPool->addOrFind(XMLUni::fgXMLURIName);
+ fXMLNSNamespaceId = fURIStringPool->addOrFind(XMLUni::fgXMLNSURIName);
+}
+
+// ---------------------------------------------------------------------------
+// XMLScanner: Private helper methods
+// ---------------------------------------------------------------------------
+
+// This method is called after the content scan to insure that all the
+// ID/IDREF attributes match up (i.e. that all IDREFs refer to IDs.) This is
+// an XML 1.0 rule, so we can do here in the core.
+void XMLScanner::checkIDRefs()
+{
+ // Iterate the id ref list. If we find any entries here which are used
+ // but not declared, then that's an error.
+ RefHashTableOfEnumerator<XMLRefInfo> refEnum(fIDRefList);
+ while (refEnum.hasMoreElements())
{
- fGrammarResolver->cacheGrammarFromParse(false);
- fGrammarResolver->useCachedGrammarInParse(false);
- fRootGrammar = 0;
+ // Get a ref to the current element
+ const XMLRefInfo& curRef = refEnum.nextElement();
- if (fValScheme == Val_Auto) {
- fValidate = true;
- }
+ // If its used but not declared, then its an error
+ if (!curRef.getDeclared() && curRef.getUsed() && fValidate)
+ fValidator->emitError(XMLValid::IDNotDeclared, curRef.getRefName());
+ }
+}
- // Reset some status flags
- fInException = false;
- fStandalone = false;
- fErrorCount = 0;
- fHasNoDTD = true;
- fSeeXsi = false;
- if (grammarType == Grammar::SchemaGrammarType) {
- return loadXMLSchemaGrammar(src, toCache);
- }
- else if (grammarType == Grammar::DTDGrammarType) {
- return loadDTDGrammar(src, toCache);
- }
+// This just does a simple check that the passed progressive scan token is
+// legal for this scanner.
+bool XMLScanner::isLegalToken(const XMLPScanToken& toCheck)
+{
+ return ((fScannerId == toCheck.fScannerId)
+ && (fSequenceId == toCheck.fSequenceId));
+}
- // Reset the reader manager to close all files, sockets, etc...
- fReaderMgr.reset();
- }
- //
- // NOTE:
- //
- // In all of the error processing below, the emitError() call MUST come
- // before the flush of the reader mgr, or it will fail because it tries
- // to find out the position in the XML source of the error.
- //
- catch(const XMLErrs::Codes)
+// This method will handle figuring out what the next top level token is
+// in the input stream. It will return an enumerated value that indicates
+// what it believes the next XML level token must be. It will eat as many
+// chars are required to figure out what is next.
+XMLScanner::XMLTokens XMLScanner::senseNextToken(unsigned int& orgReader)
+{
+ // Get the next character and use it to guesstimate what the next token
+ // is going to be. We turn on end of entity exceptions when we do this
+ // in order to catch the scenario where the current entity ended at
+ // the > of some markup.
+ XMLCh nextCh;
{
- // This is a 'first fatal error' type exit, so reset and fall through
- fReaderMgr.reset();
+ ThrowEOEJanitor janMgr(&fReaderMgr, true);
+ nextCh = fReaderMgr.peekNextChar();
}
- catch(const XMLValid::Codes)
- {
- // This is a 'first fatal error' type exit, so reset and fall through
- fReaderMgr.reset();
+ // Check for special chars. Start with the most
+ // obvious end of file, which should be legal here at top level.
+ if (!nextCh)
+ return Token_EOF;
- }
- catch(const XMLException& excToCatch)
+ // If it's not a '<' we must be in content.
+ //
+ // This includes entity references '&' of some sort. These must
+ // be character data because that's the only place a reference can
+ // occur in content.
+ if (nextCh != chOpenAngle)
+ return Token_CharData;
+
+ // Ok it had to have been a '<' character. So get it out of the reader
+ // and store the reader number where we saw it, passing it back to the
+ // caller.
+ fReaderMgr.getNextChar();
+ orgReader = fReaderMgr.getCurrentReaderNum();
+
+ // Ok, so lets go through the things that it could be at this point which
+ // are all some form of markup.
+ nextCh = fReaderMgr.peekNextChar();
+
+ if (nextCh == chForwardSlash)
{
- //
- // Emit the error and catch any user exception thrown from here. Make
- // sure in all cases we flush the reader manager.
- //
- fInException = true;
- try
+ fReaderMgr.getNextChar();
+ return Token_EndTag;
+ }
+ else if (nextCh == chBang)
+ {
+ static const XMLCh gCDATAStr[] =
{
- if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
- emitError
- (
- XMLErrs::DisplayErrorMessage
- , excToCatch.getMessage()
- );
- else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
- emitError
- (
- XMLErrs::XMLException_Fatal
- , excToCatch.getType()
- , excToCatch.getMessage()
- );
- else
- emitError
- (
- XMLErrs::XMLException_Error
- , excToCatch.getType()
- , excToCatch.getMessage()
- );
- }
+ chBang, chOpenSquare, chLatin_C, chLatin_D, chLatin_A
+ , chLatin_T, chLatin_A, chNull
+ };
- catch(...)
+ static const XMLCh gCommentString[] =
{
- // Flush the reader manager and rethrow user's error
- fReaderMgr.reset();
- throw;
- }
+ chBang, chDash, chDash, chNull
+ };
- // If it returned, then reset the reader manager and fall through
- fReaderMgr.reset();
- }
+ if (fReaderMgr.skippedString(gCDATAStr))
+ return Token_CData;
- catch(...)
+ if (fReaderMgr.skippedString(gCommentString))
+ return Token_Comment;
+
+ emitError(XMLErrs::ExpectedCommentOrCDATA);
+ return Token_Unknown;
+ }
+ else if (nextCh == chQuestion)
{
- // Reset and rethrow
- fReaderMgr.reset();
- throw;
+ // It must be a PI
+ fReaderMgr.getNextChar();
+ return Token_PI;
}
- return 0;
+ // Assume its an element name, so return with a start tag token. If it
+ // turns out not to be, then it will fail when it cannot get a valid tag.
+ return Token_StartTag;
}
-Grammar* XMLScanner::loadDTDGrammar(const InputSource& src,
- const bool toCache)
+// ---------------------------------------------------------------------------
+// XMLScanner: Private parsing methods
+// ---------------------------------------------------------------------------
+
+// This guy just scans out a single or double quoted string of characters.
+// It does not pass any judgement on the contents and assumes that it is
+// illegal to have another quote of the same kind inside the string's
+// contents.
+//
+// NOTE: This is for simple stuff like the strings in the XMLDecl which
+// cannot have any entities inside them. So this guy does not handle any
+// end of entity stuff.
+bool XMLScanner::getQuotedString(XMLBuffer& toFill)
{
- // Reset the validators
- fDTDValidator->reset();
- if (fValidatorFromUser)
- fValidator->reset();
+ // Reset the target buffer
+ toFill.reset();
- if (!fValidator->handlesDTD()) {
- if (fValidatorFromUser && fValidate)
- ThrowXML(RuntimeException, XMLExcepts::Gen_NoDTDValidator);
- else {
- fValidator = fDTDValidator;
- }
- }
+ // Get the next char which must be a single or double quote
+ XMLCh quoteCh;
+ if (!fReaderMgr.skipIfQuote(quoteCh))
+ return false;
- fDTDGrammar = new DTDGrammar();
- fGrammarResolver->putGrammar(XMLUni::fgDTDEntityString, fDTDGrammar);
- fGrammar = fDTDGrammar;
- fGrammarType = fGrammar->getGrammarType();
- fValidator->setGrammar(fGrammar);
+ while (true)
+ {
+ // Get another char
+ const XMLCh nextCh = fReaderMgr.getNextChar();
- //
- // And for all installed handlers, send reset events. This gives them
- // a chance to flush any cached data.
- //
- if (fDocHandler)
- fDocHandler->resetDocument();
- if (fEntityHandler)
- fEntityHandler->resetEntities();
- if (fErrorReporter)
- fErrorReporter->resetErrors();
+ // See if it matches the starting quote char
+ if (nextCh == quoteCh)
+ break;
- // Clear out the id reference list
- fIDRefList->removeAll();
+ // We should never get either an end of file null char here. If we
+ // do, just fail. It will be handled more gracefully in the higher
+ // level code that called us.
+ if (!nextCh)
+ return false;
- if (toCache) {
+ // Else add it to the buffer
+ toFill.append(nextCh);
+ }
+ return true;
+}
- unsigned int sysId = fGrammarResolver->getStringPool()->addOrFind(src.getSystemId());
- const XMLCh* sysIdStr = fGrammarResolver->getStringPool()->getValueForId(sysId);
- fGrammarResolver->orphanGrammar(XMLUni::fgDTDEntityString);
- fGrammarResolver->putGrammar(sysIdStr, fGrammar);
+// This method scans a character reference and returns the character that
+// was refered to. It assumes that we've already scanned the &# characters
+// that prefix the numeric code.
+bool XMLScanner::scanCharRef(XMLCh& toFill, XMLCh& second)
+{
+ bool gotOne = false;
+ unsigned int value = 0;
+
+ // Set the radix. Its supposed to be a lower case x if hex. But, in
+ // order to recover well, we check for an upper and put out an error
+ // for that.
+ unsigned int radix = 10;
+ if (fReaderMgr.skippedChar(chLatin_x))
+ {
+ radix = 16;
+ }
+ else if (fReaderMgr.skippedChar(chLatin_X))
+ {
+ emitError(XMLErrs::HexRadixMustBeLowerCase);
+ radix = 16;
}
- //
- // Handle the creation of the XML reader object for this input source.
- // This will provide us with transcoding and basic lexing services.
- //
- XMLReader* newReader = fReaderMgr.createReader
- (
- src
- , false
- , XMLReader::RefFrom_NonLiteral
- , XMLReader::Type_General
- , XMLReader::Source_External
- );
- if (!newReader) {
- if (src.getIssueFatalErrorIfNotFound())
- ThrowXML1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource, src.getSystemId());
+ while (true)
+ {
+ const XMLCh nextCh = fReaderMgr.peekNextChar();
+
+ // Watch for EOF
+ if (!nextCh)
+ ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
+
+ // Break out on the terminating semicolon
+ if (nextCh == chSemiColon)
+ {
+ fReaderMgr.getNextChar();
+ break;
+ }
+
+ // Convert this char to a binary value, or bail out if its not
+ // one.
+ unsigned int nextVal;
+ if ((nextCh >= chDigit_0) && (nextCh <= chDigit_9))
+ nextVal = (unsigned int)(nextCh - chDigit_0);
+ else if ((nextCh >= chLatin_A) && (nextCh <= chLatin_F))
+ nextVal= (unsigned int)(10 + (nextCh - chLatin_A));
+ else if ((nextCh >= chLatin_a) && (nextCh <= chLatin_f))
+ nextVal = (unsigned int)(10 + (nextCh - chLatin_a));
else
- ThrowXML1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource_Warning, src.getSystemId());
- }
+ {
+ // Return a zero
+ toFill = 0;
- //
- // In order to make the processing work consistently, we have to
- // make this look like an external entity. So create an entity
- // decl and fill it in and push it with the reader, as happens
- // with an external entity. Put a janitor on it to insure it gets
- // cleaned up. The reader manager does not adopt them.
- //
- const XMLCh gDTDStr[] = { chLatin_D, chLatin_T, chLatin_D , chNull };
- DTDEntityDecl* declDTD = new DTDEntityDecl(gDTDStr);
- declDTD->setSystemId(src.getSystemId());
- Janitor<DTDEntityDecl> janDecl(declDTD);
+ // If we got at least a sigit, then do an unterminated ref error.
+ // Else, do an expected a numerical ref thing.
+ if (gotOne)
+ emitError(XMLErrs::UnterminatedCharRef);
+ else
+ emitError(XMLErrs::ExpectedNumericalCharRef);
- // Mark this one as a throw at end
- newReader->setThrowAtEnd(true);
+ // Return failure
+ return false;
+ }
- // And push it onto the stack, with its pseudo name
- fReaderMgr.pushReader(newReader, declDTD);
+ // Make sure its valid for the radix. If not, then just eat the
+ // digit and go on after issueing an error. Else, update the
+ // running value with this new digit.
+ if (nextVal >= radix)
+ {
+ XMLCh tmpStr[2];
+ tmpStr[0] = nextCh;
+ tmpStr[1] = chNull;
+ emitError(XMLErrs::BadDigitForRadix, tmpStr);
+ }
+ else
+ {
+ value = (value * radix) + nextVal;
+ }
- //
- // If we have a doc type handler and advanced callbacks are enabled,
- // call the doctype event.
- //
- if (fDocTypeHandler) {
+ // Indicate that we got at least one good digit
+ gotOne = true;
+
+ // And eat the last char
+ fReaderMgr.getNextChar();
+ }
+
+ // [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] // any Unicode character, excluding the
+ // | [#xE000-#xFFFD] | [#x10000-#x10FFFF] // surrogate blocks, FFFE, and FFFF.
+ bool validChar = false;
+ if (value < 0x20)
+ {
+ if (value == 0x09 || value == 0x0A || value == 0x0D)
+ {
+ validChar = true;
+ }
+ }
+ else if (value <= 0xD7FF || (value >= 0xE000 && (value <= 0xFFFD || (value >= 0x10000 && value <= 0x10FFFF))))
+ {
+ validChar = true;
+ }
- // Create a dummy root
- DTDElementDecl* rootDecl = new DTDElementDecl(gDTDStr, fEmptyNamespaceId);
- rootDecl->setCreateReason(DTDElementDecl::AsRootElem);
- rootDecl->setExternalElemDeclaration(true);
- Janitor<DTDElementDecl> janSrc(rootDecl);
+ if (!validChar)
+ {
+ // Character reference was not in the valid range
+ emitError(XMLErrs::InvalidCharacterRef);
+ return false;
+ }
- fDocTypeHandler->doctypeDecl(*rootDecl, src.getPublicId(), src.getSystemId(), false, true);
+ // Return the char (or chars)
+ if (value >= 0x10000)
+ {
+ value -= 0x10000;
+ toFill = XMLCh((value >> 10) + 0xD800);
+ second = XMLCh((value & 0x3FF) + 0xDC00);
+ }
+ else
+ {
+ toFill = XMLCh(value);
+ second = 0;
}
- // Create DTDScanner
- DTDScanner dtdScanner((DTDGrammar*)fGrammar, fDocTypeHandler);
- dtdScanner.setScannerInfo(this, &fReaderMgr, &fBufMgr);
+ return true;
+}
+
+
+// We get here after the '<!--' part of the comment. We scan past the
+// terminating '-->' It will calls the appropriate handler with the comment
+// text, if one is provided. A comment can be in either the document or
+// the DTD, so the fInDocument flag is used to know which handler to send
+// it to.
+void XMLScanner::scanComment()
+{
+ enum States
+ {
+ InText
+ , OneDash
+ , TwoDashes
+ };
+
+ // Get a buffer for this
+ XMLBufBid bbComment(&fBufMgr);
+
+ // Get the comment text into a temp buffer. Be sure to use temp buffer
+ // two here, since its to be used for stuff that is potentially longer
+ // than just a name.
+ States curState = InText;
+ bool gotLeadingSurrogate = false;
+ while (true)
+ {
+ // Get the next character
+ const XMLCh nextCh = fReaderMgr.getNextChar();
+
+ // Watch for an end of file
+ if (!nextCh)
+ {
+ emitError(XMLErrs::UnterminatedComment);
+ ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
+ }
+
+ // Check for correct surrogate pairs
+ if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
+ {
+ if (gotLeadingSurrogate)
+ emitError(XMLErrs::Expected2ndSurrogateChar);
+ else
+ gotLeadingSurrogate = true;
+ }
+ else
+ {
+ if (gotLeadingSurrogate)
+ {
+ if ((nextCh < 0xDC00) || (nextCh > 0xDFFF))
+ emitError(XMLErrs::Expected2ndSurrogateChar);
+ }
+ // Its got to at least be a valid XML character
+ else if (!XMLReader::isXMLChar(nextCh)) {
+
+ XMLCh tmpBuf[9];
+ XMLString::binToText
+ (
+ nextCh
+ , tmpBuf
+ , 8
+ , 16
+ );
+ emitError(XMLErrs::InvalidCharacter, tmpBuf);
+ }
+
+ gotLeadingSurrogate = false;
+ }
- // Tell it its not in an include section
- dtdScanner.scanExtSubsetDecl(false);
+ if (curState == InText)
+ {
+ // If its a dash, go to OneDash state. Otherwise take as text
+ if (nextCh == chDash)
+ curState = OneDash;
+ else
+ bbComment.append(nextCh);
+ }
+ else if (curState == OneDash)
+ {
+ // If its another dash, then we change to the two dashes states.
+ // Otherwise, we have to put in the deficit dash and the new
+ // character and go back to InText.
+ if (nextCh == chDash)
+ {
+ curState = TwoDashes;
+ }
+ else
+ {
+ bbComment.append(chDash);
+ bbComment.append(nextCh);
+ curState = InText;
+ }
+ }
+ else if (curState == TwoDashes)
+ {
+ // The next character must be the closing bracket
+ if (nextCh != chCloseAngle)
+ {
+ emitError(XMLErrs::IllegalSequenceInComment);
+ fReaderMgr.skipPastChar(chCloseAngle);
+ return;
+ }
+ break;
+ }
+ }
- if (fValidate) {
- // validate the DTD scan so far
- fValidator->preContentValidation(false, true);
+ // If we have an available handler, call back with the comment.
+ if (fDocHandler)
+ {
+ fDocHandler->docComment
+ (
+ bbComment.getRawBuffer()
+ );
}
+}
- if (toCache)
- fGrammarResolver->cacheGrammars();
- return fDTDGrammar;
+// Most equal signs can have white space around them, so this little guy
+// just makes the calling code cleaner by eating whitespace.
+bool XMLScanner::scanEq()
+{
+ fReaderMgr.skipPastSpaces();
+ if (fReaderMgr.skippedChar(chEqual))
+ {
+ fReaderMgr.skipPastSpaces();
+ return true;
+ }
+ return false;
}
-// ---------------------------------------------------------------------------
-// XMLScanner: Rest pool of cached grammars
-// ---------------------------------------------------------------------------
-void XMLScanner::resetCachedGrammarPool()
+
+unsigned int
+XMLScanner::scanUpToWSOr(XMLBuffer& toFill, const XMLCh chEndChar)
{
- fGrammarResolver->resetCachedGrammar();
+ fReaderMgr.getUpToCharOrWS(toFill, chEndChar);
+ return toFill.getLen();
}
+
XERCES_CPP_NAMESPACE_END
---------------------------------------------------------------------
To unsubscribe, e-mail: xerces-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: xerces-cvs-help@xml.apache.org