source: icXML/icXML-devel/src/icxercesc/internal/XMLScanner.cpp @ 2774

Last change on this file since 2774 was 2774, checked in by cameron, 6 years ago

Various fixes

File size: 62.8 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: XMLScanner.cpp 882548 2009-11-20 13:44:14Z borisk $
20 */
21
22
23// ---------------------------------------------------------------------------
24//  Includes
25// ---------------------------------------------------------------------------
26#include <icxercesc/internal/XMLScanner.hpp>
27#include <icxercesc/internal/ValidationContextImpl.hpp>
28#include <xercesc/util/Janitor.hpp>
29#include <xercesc/util/Mutexes.hpp>
30#include <xercesc/util/RuntimeException.hpp>
31#include <xercesc/util/UnexpectedEOFException.hpp>
32#include <xercesc/util/XMLMsgLoader.hpp>
33#include <xercesc/util/XMLInitializer.hpp>
34#include <xercesc/framework/LocalFileInputSource.hpp>
35#include <xercesc/framework/URLInputSource.hpp>
36#include <xercesc/framework/XMLDocumentHandler.hpp>
37#include <xercesc/framework/XMLEntityHandler.hpp>
38#include <xercesc/framework/XMLPScanToken.hpp>
39#include <icxercesc/framework/XMLValidator.hpp>
40#include <xercesc/internal/EndOfEntityException.hpp>
41#include <xercesc/validators/DTD/DocTypeHandler.hpp>
42#include <icxercesc/validators/common/GrammarResolver.hpp>
43#include <xercesc/util/OutOfMemoryException.hpp>
44#include <xercesc/util/XMLResourceIdentifier.hpp>
45
46XERCES_CPP_NAMESPACE_BEGIN
47
48// ---------------------------------------------------------------------------
49//  Local static data
50// ---------------------------------------------------------------------------
51static XMLUInt32       gScannerId = 0;
52static XMLMutex*       sScannerMutex = 0;
53static XMLMsgLoader*   gMsgLoader = 0;
54
55void XMLInitializer::initializeXMLScanner()
56{
57        gMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgXMLErrDomain);
58
59        if (!gMsgLoader)
60          XMLPlatformUtils::panic(PanicHandler::Panic_CantLoadMsgDomain);
61
62        sScannerMutex = new XMLMutex(XMLPlatformUtils::fgMemoryManager);
63}
64
65void XMLInitializer::terminateXMLScanner()
66{
67        delete gMsgLoader;
68        gMsgLoader = 0;
69
70        delete sScannerMutex;
71        sScannerMutex = 0;
72}
73
74//
75//
76typedef JanitorMemFunCall<XMLScanner>   CleanupType;
77typedef JanitorMemFunCall<ReaderMgr>    ReaderMgrResetType;
78
79
80// ---------------------------------------------------------------------------
81//  XMLScanner: Constructors and Destructor
82// ---------------------------------------------------------------------------
83XMLScanner::XMLScanner
84(       XMLValidator* const valToAdopt
85        , GrammarResolver* const grammarResolver
86        , MemoryManager* const manager
87)
88        : fLowWaterMark (100)
89        , fStandardUriConformant(false)
90        , fCalculateSrcOfs(false)
91        , fDoNamespaces(false)
92        , fExitOnFirstFatal(true)
93        , fValidationConstraintFatal(false)
94        , fInException(false)
95        , fStandalone(false)
96        , fHasNoDTD(true)
97        , fValidate(false)
98        , fValidatorFromUser(false)
99        , fDoSchema(false)
100        , fSchemaFullChecking(false)
101        , fIdentityConstraintChecking(true)
102        , fToCacheGrammar(false)
103        , fUseCachedGrammar(false)
104        , fLoadExternalDTD(true)
105        , fLoadSchema(true)
106        , fNormalizeData(true)
107        , fGenerateSyntheticAnnotations(false)
108        , fValidateAnnotations(false)
109        , fIgnoreCachedDTD(false)
110        , fIgnoreAnnotations(false)
111        , fDisableDefaultEntityResolution(false)
112        , fSkipDTDValidation(false)
113        , fHandleMultipleImports(false)
114        , fErrorCount(0)
115        , fEntityExpansionLimit(0)
116        , fEntityExpansionCount(0)
117        , fScannerId(0)
118        , fSequenceId(0)
119        , fAttrList(32, true, manager)
120        , fDocHandler(0)
121        , fDocTypeHandler(0)
122        , fEntityHandler(0)
123        , fErrorReporter(0)
124        , fErrorHandler(0)
125        , fPSVIHandler(0)
126        , fValidationContext(0)
127        , fEntityDeclPoolRetrieved(false)
128        , fReaderMgr(manager)
129        , fValidator(valToAdopt)
130        , fValScheme(Val_Never)
131        , fGrammarResolver(grammarResolver)
132        , fGrammarPoolMemoryManager(grammarResolver->getGrammarPoolMemoryManager())
133        , fGrammar(0)
134        , fRootGrammar(0)
135        , fRootElemName(0)
136        , fExternalSchemaLocation(0)
137        , fExternalNoNamespaceSchemaLocation(0)
138        , fSecurityManager(0)
139        , fXMLVersion(XMLReader::XMLV1_0)
140        , fMemoryManager(manager)
141        , fBufMgr(manager)
142        , fElemStack(manager)
143        , fUriResolver(0)
144{
145        CleanupType cleanup(this, &XMLScanner::cleanUp);
146
147        try
148        {
149                commonInit();
150        }
151        catch(const OutOfMemoryException&)
152        {
153                // Don't cleanup when out of memory, since executing the
154                // code can cause problems.
155                cleanup.release();
156
157                throw;
158        }
159
160        cleanup.release();
161}
162
163XMLScanner::XMLScanner
164(
165        XMLDocumentHandler* const  docHandler
166        , DocTypeHandler* const    docTypeHandler
167        , XMLEntityHandler* const  entityHandler
168        , XMLErrorReporter* const  errHandler
169        , XMLValidator* const      valToAdopt
170        , GrammarResolver* const   grammarResolver
171        , MemoryManager* const     manager
172)
173        : fLowWaterMark (100)
174        , fStandardUriConformant(false)
175        , fCalculateSrcOfs(false)
176        , fDoNamespaces(false)
177        , fExitOnFirstFatal(true)
178        , fValidationConstraintFatal(false)
179        , fInException(false)
180        , fStandalone(false)
181        , fHasNoDTD(true)
182        , fValidate(false)
183        , fValidatorFromUser(false)
184        , fDoSchema(false)
185        , fSchemaFullChecking(false)
186        , fIdentityConstraintChecking(true)
187        , fToCacheGrammar(false)
188        , fUseCachedGrammar(false)
189        , fLoadExternalDTD(true)
190        , fLoadSchema(true)
191        , fNormalizeData(true)
192        , fGenerateSyntheticAnnotations(false)
193        , fValidateAnnotations(false)
194        , fIgnoreCachedDTD(false)
195        , fIgnoreAnnotations(false)
196        , fDisableDefaultEntityResolution(false)
197        , fSkipDTDValidation(false)
198        , fHandleMultipleImports(false)
199        , fErrorCount(0)
200        , fEntityExpansionLimit(0)
201        , fEntityExpansionCount(0)
202        , fScannerId(0)
203        , fSequenceId(0)
204        , fAttrList(32, true, manager)
205        , fDocHandler(docHandler)
206        , fDocTypeHandler(docTypeHandler)
207        , fEntityHandler(entityHandler)
208        , fErrorReporter(errHandler)
209        , fErrorHandler(0)
210        , fPSVIHandler(0)
211        , fValidationContext(0)
212        , fEntityDeclPoolRetrieved(false)
213        , fReaderMgr(manager)
214        , fValidator(valToAdopt)
215        , fValScheme(Val_Never)
216        , fGrammarResolver(grammarResolver)
217        , fGrammarPoolMemoryManager(grammarResolver->getGrammarPoolMemoryManager())
218        , fGrammar(0)
219        , fRootGrammar(0)
220        , fRootElemName(0)
221        , fExternalSchemaLocation(0)
222        , fExternalNoNamespaceSchemaLocation(0)
223        , fSecurityManager(0)
224        , fXMLVersion(XMLReader::XMLV1_0)
225        , fMemoryManager(manager)
226        , fBufMgr(manager)
227        , fElemStack(manager)
228{
229        CleanupType cleanup(this, &XMLScanner::cleanUp);
230
231        try
232        {
233                commonInit();
234        }
235        catch(const OutOfMemoryException&)
236        {
237                // Don't cleanup when out of memory, since executing the
238                // code can cause problems.
239                cleanup.release();
240
241                throw;
242        }
243
244        cleanup.release();
245}
246
247XMLScanner::~XMLScanner()
248{
249        cleanUp();
250}
251
252void XMLScanner::resetCachedGrammar ()
253{
254}
255
256void XMLScanner::setValidator(XMLValidator* const valToAdopt)
257{
258        if (fValidatorFromUser)
259                delete fValidator;
260        fValidator = valToAdopt;
261        fValidatorFromUser = true;
262        initValidator(fValidator);
263}
264
265// ---------------------------------------------------------------------------
266//  XMLScanner: Main entry point to scan a document
267// ---------------------------------------------------------------------------
268void XMLScanner::scanDocument(  const   XMLCh* const    systemId)
269{
270        //  First we try to parse it as a URL. If that fails, we assume its
271        //  a file and try it that way.
272        InputSource* srcToUse = 0;
273        try
274        {
275                //  Create a temporary URL. Since this is the primary document,
276                //  it has to be fully qualified. If not, then assume we are just
277                //  mistaking a file for a URL.
278                XMLURL tmpURL(fMemoryManager);
279
280                if (XMLURL::parse(systemId, tmpURL))
281                {
282                        if (tmpURL.isRelative())
283                        {
284                                if (!fStandardUriConformant)
285                                        srcToUse = new (fMemoryManager) LocalFileInputSource(systemId, fMemoryManager);
286                                else {
287                                        // since this is the top of the try/catch, cannot call ThrowXMLwithMemMgr
288                                        // emit the error directly
289                                        MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_NoProtocolPresent, fMemoryManager);
290                                        fInException = true;
291                                        emitError
292                                        (
293                                                XMLErrs::XMLException_Fatal
294                                                , e.getCode()
295                                                , e.getMessage()
296                                        );
297                                        return;
298                                }
299                        }
300                        else
301                        {
302                                if (fStandardUriConformant && tmpURL.hasInvalidChar()) {
303                                        MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_MalformedURL, fMemoryManager);
304                                        fInException = true;
305                                        emitError
306                                        (
307                                                XMLErrs::XMLException_Fatal
308                                                , e.getCode()
309                                                , e.getMessage()
310                                        );
311                                        return;
312                                }
313                                srcToUse = new (fMemoryManager) URLInputSource(tmpURL, fMemoryManager);
314                        }
315                }
316                else {
317
318                        if (!fStandardUriConformant)
319                                srcToUse = new (fMemoryManager) LocalFileInputSource(systemId, fMemoryManager);
320                        else {
321                                // since this is the top of the try/catch, cannot call ThrowXMLwithMemMgr
322                                // emit the error directly
323                                // lazy bypass ... since all MalformedURLException are fatal, no need to check the type
324                                MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_MalformedURL, fMemoryManager);
325                                fInException = true;
326                                emitError
327                                (
328                                        XMLErrs::XMLException_Fatal
329                                        , e.getCode()
330                                        , e.getMessage()
331                                );
332                                return;
333                        }
334                }
335        }
336        catch(const XMLException& excToCatch)
337        {
338                //  For any other XMLException,
339                //  emit the error and catch any user exception thrown from here.
340                fInException = true;
341                if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
342                        emitError
343                        (
344                                XMLErrs::XMLException_Warning
345                                , excToCatch.getCode()
346                                , excToCatch.getMessage()
347                        );
348                else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
349                        emitError
350                        (
351                                XMLErrs::XMLException_Fatal
352                                , excToCatch.getCode()
353                                , excToCatch.getMessage()
354                        );
355                else
356                        emitError
357                        (
358                                XMLErrs::XMLException_Error
359                                , excToCatch.getCode()
360                                , excToCatch.getMessage()
361                        );
362                return;
363        }
364
365        Janitor<InputSource> janSrc(srcToUse);
366        scanDocument(*srcToUse);
367
368}
369
370void XMLScanner::scanDocument(  const   char* const systemId)
371{
372        // We just delegate this to the XMLCh version after transcoding
373        XMLCh* tmpBuf = XMLString::transcode(systemId, fMemoryManager);
374        ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
375        scanDocument(tmpBuf);
376
377}
378
379
380//  This method begins a progressive parse. It scans through the prolog and
381//  returns a token to be used on subsequent scanNext() calls. If the return
382//  value is true, then the token is legal and ready for further use. If it
383//  returns false, then the scan of the prolog failed and the token is not
384//  going to work on subsequent scanNext() calls.
385//  This method begins a progressive parse. It scans through the prolog and
386//  returns a token to be used on subsequent scanNext() calls. If the return
387//  value is true, then the token is legal and ready for further use. If it
388//  returns false, then the scan of the prolog failed and the token is not
389//  going to work on subsequent scanNext() calls.
390bool XMLScanner::scanFirst( const   XMLCh* const    systemId
391                                                        ,       XMLPScanToken&  toFill)
392{
393        //  First we try to parse it as a URL. If that fails, we assume its
394        //  a file and try it that way.
395        InputSource* srcToUse = 0;
396        try
397        {
398                //  Create a temporary URL. Since this is the primary document,
399                //  it has to be fully qualified. If not, then assume we are just
400                //  mistaking a file for a URL.
401                XMLURL tmpURL(fMemoryManager);
402                if (XMLURL::parse(systemId, tmpURL)) {
403                        if (tmpURL.isRelative()) {
404                                if (!fStandardUriConformant)
405                                        srcToUse = new (fMemoryManager) LocalFileInputSource(systemId, fMemoryManager);
406                                else {
407                                        // since this is the top of the try/catch, cannot call ThrowXMLwithMemMgr
408                                        // emit the error directly
409                                        MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_NoProtocolPresent, fMemoryManager);
410                                        fInException = true;
411                                        emitError
412                                        (
413                                                XMLErrs::XMLException_Fatal
414                                                , e.getCode()
415                                                , e.getMessage()
416                                        );
417                                        return false;
418                                }
419                        }
420                        else
421                        {
422                                if (fStandardUriConformant && tmpURL.hasInvalidChar()) {
423                                        MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_MalformedURL, fMemoryManager);
424                                        fInException = true;
425                                        emitError
426                                        (
427                                                XMLErrs::XMLException_Fatal
428                                                , e.getCode()
429                                                , e.getMessage()
430                                        );
431                                        return false;
432                                }
433                                srcToUse = new (fMemoryManager) URLInputSource(tmpURL, fMemoryManager);
434                        }
435                }
436                else {
437                        if (!fStandardUriConformant)
438                                srcToUse = new (fMemoryManager) LocalFileInputSource(systemId,  fMemoryManager);
439                        else {
440                                // since this is the top of the try/catch, cannot call ThrowXMLwithMemMgr
441                                // emit the error directly
442                                // lazy bypass ... since all MalformedURLException are fatal, no need to check the type
443                                MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_MalformedURL);
444                                fInException = true;
445                                emitError
446                                (
447                                        XMLErrs::XMLException_Fatal
448                                        , e.getCode()
449                                        , e.getMessage()
450                                );
451                                return false;
452                        }
453                }
454        }
455        catch(const XMLException& excToCatch)
456        {
457                //  For any other XMLException,
458                //  emit the error and catch any user exception thrown from here.
459                fInException = true;
460                if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
461                        emitError
462                        (
463                                XMLErrs::XMLException_Warning
464                                , excToCatch.getCode()
465                                , excToCatch.getMessage()
466                        );
467                else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
468                        emitError
469                        (
470                                XMLErrs::XMLException_Fatal
471                                , excToCatch.getCode()
472                                , excToCatch.getMessage()
473                        );
474                else
475                        emitError
476                        (
477                                XMLErrs::XMLException_Error
478                                , excToCatch.getCode()
479                                , excToCatch.getMessage()
480                        );
481                return false;
482        }
483
484        Janitor<InputSource> janSrc(srcToUse);
485        return scanFirst(*srcToUse, toFill);
486}
487
488bool XMLScanner::scanFirst( const   char* const     systemId
489                                                        ,       XMLPScanToken&  toFill)
490{
491        // We just delegate this to the XMLCh version after transcoding
492        XMLCh* tmpBuf = XMLString::transcode(systemId, fMemoryManager);
493        ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
494        return scanFirst(tmpBuf, toFill);
495}
496
497bool XMLScanner::scanFirst( const   InputSource&    src
498                                                   ,       XMLPScanToken&  toFill)
499{
500        //  Bump up the sequence id for this new scan cycle. This will invalidate
501        //  any previous tokens we've returned.
502        fSequenceId++;
503
504        ReaderMgrResetType  resetReaderMgr(&fReaderMgr, &ReaderMgr::reset);
505
506   // Reset the scanner and its plugged in stuff for a new run.  This
507        // resets all the data structures, creates the initial reader and
508        // pushes it on the stack, and sets up the base document path
509        scanReset(src);
510
511        // If we have a document handler, then call the start document
512        if (fDocHandler)
513                fDocHandler->startDocument();
514
515        try
516        {
517                //  Scan the prolog part, which is everything before the root element
518                //  including the DTD subsets. This is all that is done on the scan
519                //  first.
520                scanProlog();
521
522                //  If we got to the end of input, then its not a valid XML file.
523                //  Else, go on to scan the content.
524                if (fReaderMgr.atEOF())
525                {
526                        emitError(XMLErrs::EmptyMainEntity);
527                }
528        }
529        //  NOTE:
530        //
531        //  In all of the error processing below, the emitError() call MUST come
532        //  before the flush of the reader mgr, or it will fail because it tries
533        //  to find out the position in the XML source of the error.
534        catch(const XMLErrs::Codes)
535        {
536                // This is a 'first failure' exception so return failure
537                return false;
538        }
539        catch(const XMLValid::Codes)
540        {
541                // This is a 'first fatal error' type exit, return failure
542                return false;
543        }
544        catch(const XMLException& excToCatch)
545        {
546                //  Emit the error and catch any user exception thrown from here. Make
547                //  sure in all cases we flush the reader manager.
548                fInException = true;
549                try
550                {
551                        if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
552                                emitError
553                                (
554                                        XMLErrs::XMLException_Warning
555                                        , excToCatch.getCode()
556                                        , excToCatch.getMessage()
557                                );
558                        else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
559                                emitError
560                                (
561                                        XMLErrs::XMLException_Fatal
562                                        , excToCatch.getCode()
563                                        , excToCatch.getMessage()
564                                );
565                        else
566                                emitError
567                                (
568                                        XMLErrs::XMLException_Error
569                                        , excToCatch.getCode()
570                                        , excToCatch.getMessage()
571                                );
572                }
573                catch(const OutOfMemoryException&)
574                {
575                        // This is a special case for out-of-memory
576                        // conditions, because resetting the ReaderMgr
577                        // can be problematic.
578                        resetReaderMgr.release();
579
580                        throw;
581                }
582
583                return false;
584        }
585        catch(const OutOfMemoryException&)
586        {
587                // This is a special case for out-of-memory
588                // conditions, because resetting the ReaderMgr
589                // can be problematic.
590                resetReaderMgr.release();
591
592                throw;
593        }
594
595        // Fill in the caller's token to make it legal and return success
596        toFill.set(fScannerId, fSequenceId);
597
598        // Release the object that will reset the ReaderMgr, since there's
599        // more to scan.
600        resetReaderMgr.release();
601
602        // Instruct this scanner to construct and initialize a progressive parser
603        scanFirst();
604
605        return true;
606}
607
608
609
610
611void XMLScanner::scanReset(XMLPScanToken& token)
612{
613        // Make sure this token is still legal
614        if (!isLegalToken(token))
615                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Scan_BadPScanToken, fMemoryManager);
616
617        // Reset the reader manager
618        fReaderMgr.reset();
619
620        // And invalidate any tokens by bumping our sequence number
621        fSequenceId++;
622
623        // Reset our error count
624        fErrorCount = 0;
625
626}
627
628void XMLScanner::setParseSettings(XMLScanner* const refScanner)
629{
630        setDocHandler(refScanner->getDocHandler());
631        setDocTypeHandler(refScanner->getDocTypeHandler());
632        setErrorHandler(refScanner->getErrorHandler());
633        setErrorReporter(refScanner->getErrorReporter());
634        setEntityHandler(refScanner->getEntityHandler());
635        setDoNamespaces(refScanner->getDoNamespaces());
636        setDoSchema(refScanner->getDoSchema());
637        setCalculateSrcOfs(refScanner->getCalculateSrcOfs());
638        setStandardUriConformant(refScanner->getStandardUriConformant());
639        setExitOnFirstFatal(refScanner->getExitOnFirstFatal());
640        setValidationConstraintFatal(refScanner->getValidationConstraintFatal());
641        setIdentityConstraintChecking(refScanner->getIdentityConstraintChecking());
642        setValidationSchemaFullChecking(refScanner->getValidationSchemaFullChecking());
643        cacheGrammarFromParse(refScanner->isCachingGrammarFromParse());
644        useCachedGrammarInParse(refScanner->isUsingCachedGrammarInParse());
645        setLoadExternalDTD(refScanner->getLoadExternalDTD());
646        setLoadSchema(refScanner->getLoadSchema());
647        setNormalizeData(refScanner->getNormalizeData());
648        setExternalSchemaLocation(refScanner->getExternalSchemaLocation());
649        setExternalNoNamespaceSchemaLocation(refScanner->getExternalNoNamespaceSchemaLocation());
650        setValidationScheme(refScanner->getValidationScheme());
651        setSecurityManager(refScanner->getSecurityManager());
652        setPSVIHandler(refScanner->getPSVIHandler());
653}
654
655// ---------------------------------------------------------------------------
656//  XMLScanner: Private helper methods.
657// ---------------------------------------------------------------------------
658
659//  This method handles the common initialization, to avoid having to do
660//  it redundantly in multiple constructors.
661void XMLScanner::commonInit()
662{
663        //  We have to do a little init that involves statics, so we have to
664        //  use the mutex to protect it.
665        {
666                XMLMutexLock lockInit(sScannerMutex);
667
668                // And assign ourselves the next available scanner id
669                fScannerId = ++gScannerId;
670        }
671
672        //  Create the id ref list. This is used to enforce XML 1.0 ID ref
673        //  semantics, i.e. all id refs must refer to elements that exist
674        fValidationContext = new (fMemoryManager) ValidationContextImpl(fMemoryManager);
675        fValidationContext->setScanner(this);
676
677        //  Create the GrammarResolver
678        //fGrammarResolver = new GrammarResolver();
679
680/*
681        // Register self as handler for XMLBufferFull events on the CDATA buffer
682        fCDataBuf.setFullHandler(this, fBufferSize);
683*/
684   if (fValidator)
685        {
686           fValidatorFromUser = true;
687           initValidator(fValidator);
688   }
689}
690
691void XMLScanner::cleanUp()
692{
693        delete fValidationContext;
694        fMemoryManager->deallocate(fRootElemName);
695        fMemoryManager->deallocate(fExternalSchemaLocation);
696        fMemoryManager->deallocate(fExternalNoNamespaceSchemaLocation);
697}
698
699void XMLScanner::initValidator(XMLValidator* theValidator)
700{
701        //  Tell the validator about the stuff it needs to know in order to do its work.
702        theValidator->setScannerInfo(this, &fReaderMgr, &fBufMgr);
703        theValidator->setErrorReporter(fErrorReporter);
704}
705
706// ---------------------------------------------------------------------------
707//  XMLScanner: Error emitting methods
708// ---------------------------------------------------------------------------
709
710//  These methods are called whenever the scanner wants to emit an error.
711//  It handles getting the message loaded, doing token replacement, etc...
712//  and then calling the error handler, if its installed.
713bool XMLScanner::emitErrorWillThrowException(const XMLErrs::Codes toEmit)
714{
715        if (XMLErrs::isFatal(toEmit) && fExitOnFirstFatal && !fInException)
716                return true;
717        return false;
718}
719
720void XMLScanner::emitError(const XMLErrs::Codes toEmit)
721{
722        // Bump the error count if it is not a warning
723        if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
724                incrementErrorCount();
725
726        if (fErrorReporter)
727        {
728                // Load the message into a local for display
729                const XMLSize_t msgSize = 1023;
730                XMLCh errText[msgSize + 1];
731
732                if (!gMsgLoader->loadMsg(toEmit, errText, msgSize))
733                {
734                                // <TBD> Probably should load a default msg here
735                }
736
737                //  Create a LastExtEntityInfo structure and get the reader manager
738                //  to fill it in for us. This will give us the information about
739                //  the last reader on the stack that was an external entity of some
740                //  sort (i.e. it will ignore internal entities.
741                ReaderMgr::LastExtEntityInfo lastInfo;
742                fReaderMgr.getLastExtEntityInfo(lastInfo);
743
744                fErrorReporter->error
745                (
746                        toEmit
747                        , XMLUni::fgXMLErrDomain
748                        , XMLErrs::errorType(toEmit)
749                        , errText
750                        , lastInfo.systemId
751                        , lastInfo.publicId
752                        , lastInfo.lineNumber
753                        , lastInfo.colNumber
754                );
755        }
756
757        // Bail out if its fatal an we are to give up on the first fatal error
758        if (emitErrorWillThrowException(toEmit))
759                throw toEmit;
760}
761
762void XMLScanner::emitError(const XMLErrs::Codes toEmit, const XMLFileLoc line, const XMLFileLoc col)
763{
764        // Bump the error count if it is not a warning
765        if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
766                incrementErrorCount();
767
768        if (fErrorReporter)
769        {
770                // Load the message into a local for display
771                const XMLSize_t msgSize = 1023;
772                XMLCh errText[msgSize + 1];
773
774                if (!gMsgLoader->loadMsg(toEmit, errText, msgSize))
775                {
776                                // <TBD> Probably should load a default msg here
777                }
778
779                fErrorReporter->error
780                (
781                        toEmit
782                        , XMLUni::fgXMLErrDomain
783                        , XMLErrs::errorType(toEmit)
784                        , errText
785                        , XMLUni::fgZeroLenString
786                        , XMLUni::fgZeroLenString
787                        , line
788                        , col
789                );
790        }
791
792        // Bail out if its fatal an we are to give up on the first fatal error
793        if (emitErrorWillThrowException(toEmit))
794                throw toEmit;
795}
796
797
798void XMLScanner::emitError( const   XMLErrs::Codes    toEmit
799                                                        , const XMLCh* const        text1
800                                                        , const XMLCh* const        text2
801                                                        , const XMLCh* const        text3
802                                                        , const XMLCh* const        text4)
803{
804        // Bump the error count if it is not a warning
805        if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
806                incrementErrorCount();
807
808        if (fErrorReporter)
809        {
810                //  Load the message into alocal and replace any tokens found in
811                //  the text.
812                const XMLSize_t maxChars = 2047;
813                XMLCh errText[maxChars + 1];
814
815                if (!gMsgLoader->loadMsg(toEmit, errText, maxChars, text1, text2, text3, text4, fMemoryManager))
816                {
817                        // <TBD> Should probably load a default message here
818                }
819
820                //  Create a LastExtEntityInfo structure and get the reader manager
821                //  to fill it in for us. This will give us the information about
822                //  the last reader on the stack that was an external entity of some
823                //  sort (i.e. it will ignore internal entities.
824                ReaderMgr::LastExtEntityInfo lastInfo;
825                fReaderMgr.getLastExtEntityInfo(lastInfo);
826
827                fErrorReporter->error
828                (
829                        toEmit
830                        , XMLUni::fgXMLErrDomain
831                        , XMLErrs::errorType(toEmit)
832                        , errText
833                        , lastInfo.systemId
834                        , lastInfo.publicId
835                        , lastInfo.lineNumber
836                        , lastInfo.colNumber
837                );
838        }
839
840        // Bail out if its fatal an we are to give up on the first fatal error
841        if (emitErrorWillThrowException(toEmit))
842                throw toEmit;
843}
844
845void XMLScanner::emitError( const   XMLErrs::Codes    toEmit
846                                                        , const char* const         text1
847                                                        , const char* const         text2
848                                                        , const char* const         text3
849                                                        , const char* const         text4)
850{
851        // Bump the error count if it is not a warning
852        if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
853                incrementErrorCount();
854
855        if (fErrorReporter)
856        {
857                //  Load the message into alocal and replace any tokens found in
858                //  the text.
859                const XMLSize_t maxChars = 2047;
860                XMLCh errText[maxChars + 1];
861
862                if (!gMsgLoader->loadMsg(toEmit, errText, maxChars, text1, text2, text3, text4, fMemoryManager))
863                {
864                                // <TBD> Should probably load a default message here
865                }
866
867                //  Create a LastExtEntityInfo structure and get the reader manager
868                //  to fill it in for us. This will give us the information about
869                //  the last reader on the stack that was an external entity of some
870                //  sort (i.e. it will ignore internal entities.
871                ReaderMgr::LastExtEntityInfo lastInfo;
872                fReaderMgr.getLastExtEntityInfo(lastInfo);
873
874                fErrorReporter->error
875                (
876                        toEmit
877                        , XMLUni::fgXMLErrDomain
878                        , XMLErrs::errorType(toEmit)
879                        , errText
880                        , lastInfo.systemId
881                        , lastInfo.publicId
882                        , lastInfo.lineNumber
883                        , lastInfo.colNumber
884                );
885        }
886
887        // Bail out if its fatal an we are to give up on the first fatal error
888        if (emitErrorWillThrowException(toEmit))
889                throw toEmit;
890}
891
892void XMLScanner::emitError( const   XMLErrs::Codes      toEmit
893                                                        , const XMLExcepts::Codes   originalExceptCode
894                                                        , const XMLCh* const        text1
895                                                        , const XMLCh* const        text2
896                                                        , const XMLCh* const        text3
897                                                        , const XMLCh* const        text4)
898{
899        // Bump the error count if it is not a warning
900        if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
901                incrementErrorCount();
902
903        if (fErrorReporter)
904        {
905                //  Load the message into alocal and replace any tokens found in
906                //  the text.
907                const XMLSize_t maxChars = 2047;
908                XMLCh errText[maxChars + 1];
909
910                if (!gMsgLoader->loadMsg(toEmit, errText, maxChars, text1, text2, text3, text4, fMemoryManager))
911                {
912                                // <TBD> Should probably load a default message here
913                }
914
915                //  Create a LastExtEntityInfo structure and get the reader manager
916                //  to fill it in for us. This will give us the information about
917                //  the last reader on the stack that was an external entity of some
918                //  sort (i.e. it will ignore internal entities.
919                ReaderMgr::LastExtEntityInfo lastInfo;
920                fReaderMgr.getLastExtEntityInfo(lastInfo);
921
922                fErrorReporter->error
923                (
924                        originalExceptCode
925                        , XMLUni::fgExceptDomain    //fgXMLErrDomain
926                        , XMLErrs::errorType(toEmit)
927                        , errText
928                        , lastInfo.systemId
929                        , lastInfo.publicId
930                        , lastInfo.lineNumber
931                        , lastInfo.colNumber
932                );
933        }
934
935        // Bail out if its fatal an we are to give up on the first fatal error
936        if (emitErrorWillThrowException(toEmit))
937                throw toEmit;
938}
939
940// --------------------------------------------------------------------------------------------------------
941
942//  Scans a PI and calls the appropriate callbacks. At entry we have just
943//  scanned the <? part, and need to now start on the PI target name.
944void XMLScanner::handlePI
945(
946    const XMLCh   * const     target
947        , const XMLCh     *       data
948        , const XMLSize_t
949)
950{
951        // If we have a handler, then call it
952        if (fDocHandler)
953        {
954        fDocHandler->docPI(target, data);
955        }
956
957        //mark PI is seen within the current element
958        if (!fElemStack.isEmpty())
959        {
960                fElemStack.setCommentOrPISeen();
961        }
962}
963
964// --------------------------------------------------------------------------------------------------------
965
966void XMLScanner::handleComment
967(
968        const XMLCh       * comment
969        , const XMLSize_t
970)
971{
972         // If we have an available handler, call back with the comment.
973        if (fDocHandler)
974        {
975                fDocHandler->docComment(comment);
976        }
977
978        //mark comment is seen within the current element
979        if (!fElemStack.isEmpty())
980        {
981                fElemStack.setCommentOrPISeen();
982        }
983}
984
985// --------------------------------------------------------------------------------------------------------
986
987void XMLScanner::handleCDATA
988(
989        const XMLCh       * cdata
990        , const XMLSize_t   length
991)
992{
993        if (fDocHandler)
994        {
995                fDocHandler->docCharacters(cdata, length, true);
996        }
997}
998
999// --------------------------------------------------------------------------------------------------------
1000
1001void XMLScanner::handleIgnorableWhitespace
1002(
1003        const XMLCh       * whitespace
1004        , const XMLSize_t   length
1005)
1006{
1007        if (fDocHandler)
1008        {
1009                fDocHandler->ignorableWhitespace
1010                (
1011                        whitespace
1012                        , length
1013                        , false
1014                );
1015        }
1016}
1017
1018// --------------------------------------------------------------------------------------------------------
1019
1020//  Scans the <?xml .... ?> line. This stuff is all sequential so we don't
1021//  do any state machine loop here. We just bull straight through it. It ends
1022//  past the closing bracket. If there is a document handler, then its called
1023//  on the XMLDecl callback.
1024//
1025//  On entry, the <?xml has been scanned, and we pick it up from there.
1026//
1027//  NOTE: In order to provide good recovery from bad XML here, we try to be
1028//  very flexible. No matter what order the stuff is in, we'll keep going
1029//  though we'll issue errors.
1030//
1031//  The parameter tells us which type of decl we should expect, Text or XML.
1032//    [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
1033//    [77] TextDecl::= '<?xml' VersionInfo? EncodingDecl S? '?>'
1034void XMLScanner::scanXMLDecl(const DeclTypes type)
1035{
1036        // Get us some buffers to use
1037        XMLBufBid bbVersion(&fBufMgr);
1038        XMLBufBid bbEncoding(&fBufMgr);
1039        XMLBufBid bbStand(&fBufMgr);
1040        XMLBufBid bbDummy(&fBufMgr);
1041        XMLBufBid bbName(&fBufMgr);
1042
1043        //  We use this little enum and array to keep up with what we found
1044        //  and what order we found them in. This lets us get them free form
1045        //  without too much overhead, but still know that they were in the
1046        //  wrong order.
1047        enum Strings
1048        {
1049                VersionString
1050                , EncodingString
1051                , StandaloneString
1052                , UnknownString
1053
1054                , StringCount
1055        };
1056        int flags[StringCount] = { -1, -1, -1, -1 };
1057
1058        //  Also set up a list of buffers in the right order so that we know
1059        //  where to put stuff.
1060        XMLBuffer* buffers[StringCount] ;
1061        buffers[0] = &bbVersion.getBuffer();
1062        buffers[1] = &bbEncoding.getBuffer();
1063        buffers[2] = &bbStand.getBuffer();
1064        buffers[3] = &bbDummy.getBuffer();
1065
1066        int curCount = 0;
1067        Strings curString;
1068        XMLBuffer& nameBuf = bbName.getBuffer();
1069        while (true)
1070        {
1071                // Skip any spaces
1072                bool skippedSomething;
1073                fReaderMgr.skipPastSpaces(skippedSomething, true);
1074
1075                // If we are looking at a question mark, then break out
1076                if (fReaderMgr.lookingAtChar(chQuestion))
1077                {
1078                        break;
1079                }
1080
1081                // If this is not the first string, then we require the spaces
1082                if (!skippedSomething && curCount)
1083                {
1084                        emitError(XMLErrs::ExpectedWhitespace);
1085                }
1086
1087                //  Get characters up to the next whitespace or equal's sign.
1088                if (!scanUpToWSOr(nameBuf, chEqual))
1089                {
1090                        emitError(XMLErrs::ExpectedDeclString);
1091                }
1092
1093                // See if it matches any of our expected strings
1094                if (XMLString::equals(nameBuf.getRawBuffer(), XMLUni::fgVersionString))
1095                {
1096                        curString = VersionString;
1097                }
1098                else if (XMLString::equals(nameBuf.getRawBuffer(), XMLUni::fgEncodingString))
1099                {
1100                        curString = EncodingString;
1101                }
1102                else if (XMLString::equals(nameBuf.getRawBuffer(), XMLUni::fgStandaloneString))
1103                {
1104                        curString = StandaloneString;
1105                }
1106                else
1107                {
1108                        curString = UnknownString;
1109                }
1110
1111                //  If its an unknown string, then give that error. Else check to
1112                //  see if this one has been done already and give that error.
1113                if (curString == UnknownString)
1114                        emitError(XMLErrs::ExpectedDeclString, nameBuf.getRawBuffer());
1115                else if (flags[curString] != -1)
1116                        emitError(XMLErrs::DeclStringRep, nameBuf.getRawBuffer());
1117                else if (flags[curString] == -1)
1118                        flags[curString] = ++curCount;
1119
1120                //  Scan for an equal's sign. If we don't find it, issue an error
1121                //  but keep trying to go on.
1122                if (!scanEq(true))
1123                        emitError(XMLErrs::ExpectedEqSign);
1124
1125                //  Get a quote string into the buffer for the string that we are
1126                //  currently working on.
1127                if (!getQuotedString(*buffers[curString]))
1128                {
1129                        emitError(XMLErrs::ExpectedQuotedString);
1130                        fReaderMgr.skipPastChar(chCloseAngle);
1131                        return;
1132                }
1133
1134                // And validate the value according which one it was
1135                const XMLCh* rawValue = buffers[curString]->getRawBuffer();
1136                if (curString == VersionString)
1137                {
1138                        if (XMLString::equals(rawValue, XMLUni::fgVersion1_0))
1139                        {
1140                                if (type == Decl_XML)
1141                                {
1142                                        fXMLVersion = XMLReader::XMLV1_0;
1143                                        fReaderMgr.setXMLVersion(XMLReader::XMLV1_0);
1144                                }
1145                        }
1146#ifdef ICXML_ENABLE_VERSION1_1
1147                        else if (XMLString::equals(rawValue, XMLUni::fgVersion1_1))
1148                        {
1149
1150                                if (type == Decl_XML)
1151                                {
1152                                        fXMLVersion = XMLReader::XMLV1_1;
1153                                        fReaderMgr.setXMLVersion(XMLReader::XMLV1_1);
1154                                }
1155                                else
1156                                {
1157                                        if (fXMLVersion != XMLReader::XMLV1_1)
1158                                                emitError(XMLErrs::UnsupportedXMLVersion, rawValue);
1159                                }
1160                        }
1161#endif
1162                        else
1163                                emitError(XMLErrs::UnsupportedXMLVersion, rawValue);
1164                }
1165                else if (curString == EncodingString)
1166                {
1167                        if (!XMLString::isValidEncName(rawValue))
1168                                emitError(XMLErrs::BadXMLEncoding, rawValue);
1169                }
1170                 else if (curString == StandaloneString)
1171                {
1172                        if (XMLString::equals(rawValue, XMLUni::fgYesString))
1173                                fStandalone = true;
1174                        else if (XMLString::equals(rawValue, XMLUni::fgNoString))
1175                                fStandalone = false;
1176                        else
1177                        {
1178                                emitError(XMLErrs::BadStandalone);
1179                                //if (!XMLString::compareIString(rawValue, XMLUni::fgYesString))
1180                                //else if (!XMLString::compareIString(rawValue, XMLUni::fgNoString))
1181                                if (buffers[curString]->getLen() == 3 &&
1182                                        (((rawValue[0] == chLatin_y) || (rawValue[0] == chLatin_Y)) &&
1183                                         ((rawValue[1] == chLatin_e) || (rawValue[1] == chLatin_E)) &&
1184                                         ((rawValue[2] == chLatin_s) || (rawValue[2] == chLatin_S))))
1185                                        fStandalone = true;
1186                                else if (buffers[curString]->getLen() == 2 &&
1187                                        (((rawValue[0] == chLatin_n) || (rawValue[0] == chLatin_N)) &&
1188                                         ((rawValue[1] == chLatin_o) || (rawValue[1] == chLatin_O))))
1189                                        fStandalone = false;
1190                        }
1191                }
1192        }
1193
1194        //  Make sure that the strings present are in order. We don't care about
1195        //  which ones are present at this point, just that any there are in the
1196        //  right order.
1197        int curTop = 0;
1198        for (int index = VersionString; index < StandaloneString; index++)
1199        {
1200                if (flags[index] != -1)
1201                {
1202                        if (flags[index] !=  curTop + 1)
1203                        {
1204                                emitError(XMLErrs::DeclStringsInWrongOrder);
1205                                break;
1206                        }
1207                        curTop = flags[index];
1208                }
1209        }
1210
1211        //  If its an XML decl, the version must be present.
1212        //  If its a Text decl, then encoding must be present AND standalone must not be present.
1213        if ((type == Decl_XML) && (flags[VersionString] == -1))
1214                emitError(XMLErrs::XMLVersionRequired);
1215        else if (type == Decl_Text) {
1216                if (flags[StandaloneString] != -1)
1217                        emitError(XMLErrs::StandaloneNotLegal);
1218                if (flags[EncodingString] == -1)
1219                        emitError(XMLErrs::EncodingRequired);
1220        }
1221
1222        if (!fReaderMgr.skippedChar(chQuestion))
1223        {
1224                emitError(XMLErrs::UnterminatedXMLDecl);
1225                fReaderMgr.skipPastChar(chCloseAngle);
1226        }
1227        else if (!fReaderMgr.skippedChar(chCloseAngle))
1228        {
1229                emitError(XMLErrs::UnterminatedXMLDecl);
1230                fReaderMgr.skipPastChar(chCloseAngle);
1231        }
1232
1233        //  Do this before we possibly update the reader with the
1234        //  actual encoding string. Otherwise, we will pass the wrong thing
1235        //  for the last parameter!
1236        const XMLCh* actualEnc = fReaderMgr.getCurrentEncodingStr();
1237
1238        //  Ok, we've now seen the real encoding string, if there was one, so
1239        //  lets call back on the current reader and tell it what the real
1240        //  encoding string was. If it fails, that's because it represents some
1241        //  sort of contradiction with the autosensed format, and it keeps the
1242        //  original encoding.
1243        //
1244        //  NOTE: This can fail for a number of reasons, such as a bogus encoding
1245        //  name or because its in flagrant contradiction of the auto-sensed
1246        //  format.
1247        if (flags[EncodingString] != -1)
1248        {
1249                if (!fReaderMgr.getCurrentReader()->setEncoding(bbEncoding.getRawBuffer()))
1250                        emitError(XMLErrs::ContradictoryEncoding, bbEncoding.getRawBuffer());
1251                else
1252                        actualEnc = bbEncoding.getRawBuffer();
1253        }
1254
1255        //  If we have a document handler then call the XML Decl callback.
1256        if (type == Decl_XML)
1257        {
1258                if (fDocHandler)
1259                        fDocHandler->XMLDecl
1260                        (
1261                                bbVersion.getRawBuffer()
1262                                , bbEncoding.getRawBuffer()
1263                                , bbStand.getRawBuffer()
1264                                , actualEnc
1265                        );
1266        }
1267        else if (type == Decl_Text)
1268        {
1269                if (fDocTypeHandler)
1270                        fDocTypeHandler->TextDecl
1271                        (
1272                                bbVersion.getRawBuffer()
1273                                , bbEncoding.getRawBuffer()
1274                        );
1275        }
1276}
1277
1278bool XMLScanner::checkXMLDecl(bool startWithAngle)
1279{
1280        // [23] XMLDecl     ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
1281        // [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
1282        //
1283        // [3]  S           ::= (#x20 | #x9 | #xD | #xA)+
1284        if (startWithAngle)
1285        {
1286                if (fReaderMgr.peekString(XMLUni::fgXMLDeclString))
1287                {
1288                        if (fReaderMgr.skippedString(XMLUni::fgXMLDeclStringSpace)
1289                           || fReaderMgr.skippedString(XMLUni::fgXMLDeclStringHTab)
1290                           || fReaderMgr.skippedString(XMLUni::fgXMLDeclStringLF)
1291                           || fReaderMgr.skippedString(XMLUni::fgXMLDeclStringCR))
1292                        {
1293                                return true;
1294                        }
1295                }
1296                else if (fReaderMgr.skippedString(XMLUni::fgXMLDeclStringSpaceU)
1297                   || fReaderMgr.skippedString(XMLUni::fgXMLDeclStringHTabU)
1298                   || fReaderMgr.skippedString(XMLUni::fgXMLDeclStringLFU)
1299                   || fReaderMgr.skippedString(XMLUni::fgXMLDeclStringCRU))
1300                {
1301                        //  Just in case, check for upper case. If found, issue
1302                        //  an error, but keep going.
1303                        emitError(XMLErrs::XMLDeclMustBeLowerCase);
1304                        return true;
1305                }
1306        }
1307        else
1308        {
1309                if (fReaderMgr.peekString(XMLUni::fgXMLString))
1310                {
1311                        if (fReaderMgr.skippedString(XMLUni::fgXMLStringSpace)
1312                           || fReaderMgr.skippedString(XMLUni::fgXMLStringHTab)
1313                           || fReaderMgr.skippedString(XMLUni::fgXMLStringLF)
1314                           || fReaderMgr.skippedString(XMLUni::fgXMLStringCR))
1315                        {
1316                                return true;
1317                        }
1318                }
1319                else if (fReaderMgr.skippedString(XMLUni::fgXMLStringSpaceU)
1320                   || fReaderMgr.skippedString(XMLUni::fgXMLStringHTabU)
1321                   || fReaderMgr.skippedString(XMLUni::fgXMLStringLFU)
1322                   || fReaderMgr.skippedString(XMLUni::fgXMLStringCRU))
1323                {
1324                        //  Just in case, check for upper case. If found, issue
1325                        //  an error, but keep going.
1326                        emitError(XMLErrs::XMLDeclMustBeLowerCase);
1327                        return true;
1328                }
1329        }
1330
1331        return false;
1332}
1333
1334
1335// ---------------------------------------------------------------------------
1336//  XMLScanner: Grammar preparsing
1337// ---------------------------------------------------------------------------
1338Grammar* XMLScanner::loadGrammar(const   XMLCh* const systemId
1339                                                                 , const short        grammarType
1340                                                                 , const bool         toCache)
1341{
1342        InputSource* srcToUse = 0;
1343
1344        if (fEntityHandler){
1345                ReaderMgr::LastExtEntityInfo lastInfo;
1346                fReaderMgr.getLastExtEntityInfo(lastInfo);
1347                XMLResourceIdentifier resourceIdentifier(XMLResourceIdentifier::ExternalEntity,
1348                                                        systemId, 0, XMLUni::fgZeroLenString, lastInfo.systemId,
1349                                                        &fReaderMgr);
1350                srcToUse = fEntityHandler->resolveEntity(&resourceIdentifier);
1351        }
1352
1353        //  First we try to parse it as a URL. If that fails, we assume its
1354        //  a file and try it that way.
1355        if (!srcToUse) {
1356                if (fDisableDefaultEntityResolution)
1357                        return 0;
1358
1359                try
1360                {
1361                        //  Create a temporary URL. Since this is the primary document,
1362                        //  it has to be fully qualified. If not, then assume we are just
1363                        //  mistaking a file for a URL.
1364                        XMLURL tmpURL(fMemoryManager);
1365
1366                        if (XMLURL::parse(systemId, tmpURL)) {
1367
1368                                if (tmpURL.isRelative())
1369                                {
1370                                        if (!fStandardUriConformant)
1371                                                srcToUse = new (fMemoryManager) LocalFileInputSource(systemId, fMemoryManager);
1372                                        else {
1373                                                // since this is the top of the try/catch, cannot call ThrowXMLwithMemMgr
1374                                                // emit the error directly
1375                                                MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_NoProtocolPresent, fMemoryManager);
1376                                                fInException = true;
1377                                                emitError
1378                                                (
1379                                                        XMLErrs::XMLException_Fatal
1380                                                        , e.getCode()
1381                                                        , e.getMessage()
1382                                                );
1383                                                return 0;
1384                                        }
1385                                }
1386                                else
1387                                {
1388                                        if (fStandardUriConformant && tmpURL.hasInvalidChar()) {
1389                                                MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_MalformedURL, fMemoryManager);
1390                                                fInException = true;
1391                                                emitError
1392                                                (
1393                                                        XMLErrs::XMLException_Fatal
1394                                                        , e.getCode()
1395                                                        , e.getMessage()
1396                                                );
1397                                                return 0;
1398                                        }
1399                                        srcToUse = new (fMemoryManager) URLInputSource(tmpURL, fMemoryManager);
1400                                }
1401                        }
1402                        else
1403                        {
1404                                if (!fStandardUriConformant)
1405                                        srcToUse = new (fMemoryManager) LocalFileInputSource(systemId, fMemoryManager);
1406                                else {
1407                                        // since this is the top of the try/catch, cannot call ThrowXMLwithMemMgr
1408                                        // emit the error directly
1409                                        // lazy bypass ... since all MalformedURLException are fatal, no need to check the type
1410                                        MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_MalformedURL);
1411                                        fInException = true;
1412                                        emitError
1413                                        (
1414                                                XMLErrs::XMLException_Fatal
1415                                                , e.getCode()
1416                                                , e.getMessage()
1417                                        );
1418                                        return 0;
1419                                }
1420                        }
1421                }
1422                catch(const XMLException& excToCatch)
1423                {
1424                        //  For any other XMLException,
1425                        //  emit the error and catch any user exception thrown from here.
1426                        fInException = true;
1427                        if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
1428                                emitError
1429                                (
1430                                        XMLErrs::XMLException_Warning
1431                                        , excToCatch.getCode()
1432                                        , excToCatch.getMessage()
1433                                );
1434                        else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
1435                                emitError
1436                                (
1437                                        XMLErrs::XMLException_Fatal
1438                                        , excToCatch.getCode()
1439                                        , excToCatch.getMessage()
1440                                );
1441                        else
1442                                emitError
1443                                (
1444                                        XMLErrs::XMLException_Error
1445                                        , excToCatch.getCode()
1446                                        , excToCatch.getMessage()
1447                                );
1448                                return 0;
1449                }
1450        }
1451
1452        Janitor<InputSource> janSrc(srcToUse);
1453        return loadGrammar(*srcToUse, grammarType, toCache);
1454}
1455
1456Grammar* XMLScanner::loadGrammar(const   char* const systemId
1457                                                                 , const short       grammarType
1458                                                                 , const bool        toCache)
1459{
1460        // We just delegate this to the XMLCh version after transcoding
1461        XMLCh* tmpBuf = XMLString::transcode(systemId, fMemoryManager);
1462        ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
1463        return loadGrammar(tmpBuf, grammarType, toCache);
1464}
1465
1466// ---------------------------------------------------------------------------
1467//  XMLScanner: Private helper methods
1468// ---------------------------------------------------------------------------
1469
1470/***
1471 * In reusing grammars (cacheing grammar from parse, or use cached grammar), internal
1472 * dtd is allowed conditionally.
1473 *
1474 * In the case of cacheing grammar from parse, it is NOT allowed.
1475 *
1476 * In the case of use cached grammar,
1477 *   if external dtd is present and it is parsed before, then it is not allowed,
1478 *   otherwise it is allowed.
1479 *
1480 ***/
1481void XMLScanner::checkInternalDTD(bool hasExtSubset
1482                                                                 ,const XMLCh* const sysId
1483                                                                 ,const XMLCh* const pubId)
1484{
1485        if (fToCacheGrammar)
1486                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Val_CantHaveIntSS, fMemoryManager);
1487
1488        if (fUseCachedGrammar && hasExtSubset && !fIgnoreCachedDTD)
1489        {
1490                InputSource* sysIdSrc = resolveSystemId(sysId, pubId);
1491                if (sysIdSrc) {
1492                        Janitor<InputSource> janSysIdSrc(sysIdSrc);
1493                        Grammar* grammar = fGrammarResolver->getGrammar(sysIdSrc->getSystemId());
1494
1495                        if (grammar && grammar->getGrammarType() == Grammar::DTDGrammarType)
1496                        {
1497                                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Val_CantHaveIntSS, fMemoryManager);
1498                        }
1499                }
1500        }
1501
1502}
1503
1504//  This method is called after the content scan to insure that all the
1505//  ID/IDREF attributes match up (i.e. that all IDREFs refer to IDs.) This is
1506//  an XML 1.0 rule, so we can do here in the core.
1507
1508void XMLScanner::checkIDRefs()
1509{
1510        //  Iterate the id ref list. If we find any entries here which are used
1511        //  but not declared, then that's an error.
1512        RefHashTableOfEnumerator<XMLRefInfo> refEnum(fValidationContext->getIdRefList(), false, fMemoryManager);
1513        while (refEnum.hasMoreElements())
1514        {
1515                // Get a ref to the current element
1516                const XMLRefInfo& curRef = refEnum.nextElement();
1517
1518                // If its used but not declared, then its an error
1519                if (!curRef.getDeclared() && curRef.getUsed() && fValidate)
1520                        fValidator->emitError(XMLValid::IDNotDeclared, curRef.getRefName());
1521        }
1522}
1523
1524
1525//  This just does a simple check that the passed progressive scan token is
1526//  legal for this scanner.
1527bool XMLScanner::isLegalToken(const XMLPScanToken& toCheck)
1528{
1529        return ((fScannerId == toCheck.fScannerId) && (fSequenceId == toCheck.fSequenceId));
1530}
1531
1532//  This method will handle figuring out what the next top level token is
1533//  in the input stream. It will return an enumerated value that indicates
1534//  what it believes the next XML level token must be. It will eat as many
1535//  chars are required to figure out what is next.
1536XMLScanner::XMLTokens XMLScanner::senseNextToken(XMLSize_t& orgReader)
1537{
1538#if 0
1539        //  Get the next character and use it to guesstimate what the next token
1540        //  is going to be. We turn on end of entity exceptions when we do this
1541        //  in order to catch the scenario where the current entity ended at
1542        //  the > of some markup.
1543        XMLCh nextCh=0;
1544
1545        XMLReader* curReader=fReaderMgr.getCurrentReader();
1546        // avoid setting up the ThrowEOEJanitor if we know that we have data in the current reader
1547        if(curReader && curReader->charsLeftInBuffer()>0)
1548                nextCh = fReaderMgr.peekNextChar();
1549        else
1550        {
1551                ThrowEOEJanitor janMgr(&fReaderMgr, true);
1552                nextCh = fReaderMgr.peekNextChar();
1553        }
1554
1555        //  If it's not a '<' we must be in content (unless it's a EOF)
1556        //
1557        //  This includes entity references '&' of some sort. These must
1558        //  be character data because that's the only place a reference can
1559        //  occur in content.
1560        if (nextCh != chOpenAngle)
1561                return nextCh ? Token_CharData : Token_EOF;
1562
1563        //  Ok it had to have been a '<' character. So get it out of the reader
1564        //  and store the reader number where we saw it, passing it back to the
1565        //  caller.
1566        fReaderMgr.getNextChar();
1567        orgReader = fReaderMgr.getCurrentReaderNum();
1568
1569        //  Ok, so lets go through the things that it could be at this point which
1570        //  are all some form of markup.
1571        switch(fReaderMgr.peekNextChar())
1572        {
1573        case chForwardSlash:
1574                {
1575                        fReaderMgr.getNextChar();
1576                        return Token_EndTag;
1577                }
1578        case chBang:
1579                {
1580                        static const XMLCh gCDATAStr[] =
1581                        {
1582                                        chBang, chOpenSquare, chLatin_C, chLatin_D, chLatin_A
1583                                ,   chLatin_T, chLatin_A, chNull
1584                        };
1585
1586                        static const XMLCh gCommentString[] =
1587                        {
1588                                chBang, chDash, chDash, chNull
1589                        };
1590
1591                        if (fReaderMgr.skippedString(gCDATAStr))
1592                                return Token_CData;
1593
1594                        if (fReaderMgr.skippedString(gCommentString))
1595                                return Token_Comment;
1596
1597                        emitError(XMLErrs::ExpectedCommentOrCDATA);
1598                        return Token_Unknown;
1599                }
1600        case chQuestion:
1601                {
1602                        // It must be a PI
1603                        fReaderMgr.getNextChar();
1604                        return Token_PI;
1605                }
1606        }
1607        //  Assume its an element name, so return with a start tag token. If it
1608        //  turns out not to be, then it will fail when it cannot get a valid tag.
1609        return Token_StartTag;
1610#else
1611        DEPRECATED_FEATURE_IN_ICXML;
1612#endif
1613}
1614
1615//  Scans a PI and calls the appropriate callbacks. At entry we have just
1616//  scanned the <? part, and need to now start on the PI target name.
1617void XMLScanner::scanPI()
1618{
1619#ifndef EXCLUDE_TRADITIONAL_XERCES_FUNCTIONS_AND_VARIABLES
1620        const XMLCh* namePtr = 0;
1621        const XMLCh* targetPtr = 0;
1622
1623        //  If there are any spaces here, then warn about it. If we aren't in
1624        //  'first error' mode, then we'll come back and can easily pick up
1625        //  again by just skipping them.
1626        if (fReaderMgr.lookingAtSpace())
1627        {
1628                emitError(XMLErrs::PINameExpected);
1629                fReaderMgr.skipPastSpaces();
1630        }
1631
1632        // Get a buffer for the PI name and scan it in
1633        XMLBufBid bbName(&fBufMgr);
1634        if (!fReaderMgr.getName(bbName.getBuffer()))
1635        {
1636                emitError(XMLErrs::PINameExpected);
1637                fReaderMgr.skipPastChar(chCloseAngle);
1638                return;
1639        }
1640
1641        // Point the name pointer at the raw data
1642        namePtr = bbName.getRawBuffer();
1643
1644        // See if it is some form of 'xml' and emit a warning
1645        //if (!XMLString::compareIString(namePtr, XMLUni::fgXMLString))
1646        if (bbName.getLen() == 3 &&
1647                (((namePtr[0] == chLatin_x) || (namePtr[0] == chLatin_X)) &&
1648                 ((namePtr[1] == chLatin_m) || (namePtr[1] == chLatin_M)) &&
1649                 ((namePtr[2] == chLatin_l) || (namePtr[2] == chLatin_L))))
1650                emitError(XMLErrs::NoPIStartsWithXML);
1651
1652        // If namespaces are enabled, then no colons allowed
1653        if (fDoNamespaces)
1654        {
1655                if (XMLString::indexOf(namePtr, chColon) != -1)
1656                        emitError(XMLErrs::ColonNotLegalWithNS);
1657        }
1658
1659        //  If we don't hit a space next, then the PI has no target. If we do
1660        //  then get out the target. Get a buffer for it as well
1661        XMLBufBid bbTarget(&fBufMgr);
1662        if (fReaderMgr.skippedSpace())
1663        {
1664                // Skip any leading spaces
1665                fReaderMgr.skipPastSpaces();
1666
1667                bool gotLeadingSurrogate = false;
1668
1669                // It does have a target, so lets move on to deal with that.
1670                while (1)
1671                {
1672                        const XMLCh nextCh = fReaderMgr.getNextChar();
1673
1674                        // Watch for an end of file, which is always bad here
1675                        if (!nextCh)
1676                        {
1677                                emitError(XMLErrs::UnterminatedPI);
1678                                ThrowXMLwithMemMgr(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF, fMemoryManager);
1679                        }
1680
1681                        // Watch for potential terminating character
1682                        if (nextCh == chQuestion)
1683                        {
1684                                // It must be followed by '>' to be a termination of the target
1685                                if (fReaderMgr.skippedChar(chCloseAngle))
1686                                        break;
1687                        }
1688
1689                        // Check for correct surrogate pairs
1690                        if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
1691                        {
1692                                if (gotLeadingSurrogate)
1693                                        emitError(XMLErrs::Expected2ndSurrogateChar);
1694                                else
1695                                        gotLeadingSurrogate = true;
1696                        }
1697                         else
1698                        {
1699                                if (gotLeadingSurrogate)
1700                                {
1701                                        if ((nextCh < 0xDC00) || (nextCh > 0xDFFF))
1702                                                emitError(XMLErrs::Expected2ndSurrogateChar);
1703                                }
1704                                // Its got to at least be a valid XML character
1705                                else if (!fReaderMgr.getCurrentReader()->isXMLChar(nextCh)) {
1706
1707                                        XMLCh tmpBuf[9];
1708                                        XMLString::binToText
1709                                        (
1710                                                nextCh
1711                                                , tmpBuf
1712                                                , 8
1713                                                , 16
1714                                                , fMemoryManager
1715                                        );
1716                                        emitError(XMLErrs::InvalidCharacter, tmpBuf);
1717                                }
1718
1719                                gotLeadingSurrogate = false;
1720                        }
1721
1722                        bbTarget.append(nextCh);
1723                }
1724        }
1725        else
1726        {
1727                // No target, but make sure its terminated ok
1728                if (!fReaderMgr.skippedChar(chQuestion))
1729                {
1730                        emitError(XMLErrs::UnterminatedPI);
1731                        fReaderMgr.skipPastChar(chCloseAngle);
1732                        return;
1733                }
1734
1735                if (!fReaderMgr.skippedChar(chCloseAngle))
1736                {
1737                        emitError(XMLErrs::UnterminatedPI);
1738                        fReaderMgr.skipPastChar(chCloseAngle);
1739                        return;
1740                }
1741        }
1742
1743        // Point the target pointer at the raw data
1744        targetPtr = bbTarget.getRawBuffer();
1745
1746        // If we have a handler, then call it
1747        if (fDocHandler)
1748        {
1749                fDocHandler->docPI
1750                (
1751                        namePtr
1752                        , targetPtr
1753           );
1754        }
1755
1756        //mark PI is seen within the current element
1757        if (! fElemStack.isEmpty())
1758                fElemStack.setCommentOrPISeen();
1759#else
1760        DEPRECATED_FEATURE_IN_ICXML;
1761#endif
1762}
1763
1764//  We get here after the '<!--' part of the comment. We scan past the
1765//  terminating '-->' It will calls the appropriate handler with the comment
1766//  text, if one is provided. A comment can be in either the document or
1767//  the DTD, so the fInDocument flag is used to know which handler to send
1768//  it to.
1769void XMLScanner::scanComment()
1770{
1771#ifndef EXCLUDE_TRADITIONAL_XERCES_FUNCTIONS_AND_VARIABLES
1772
1773        enum States
1774        {
1775                InText
1776                , OneDash
1777                , TwoDashes
1778        };
1779
1780        // Get a buffer for this
1781        XMLBufBid bbComment(&fBufMgr);
1782
1783        //  Get the comment text into a temp buffer. Be sure to use temp buffer
1784        //  two here, since its to be used for stuff that is potentially longer
1785        //  than just a name.
1786        States curState = InText;
1787        bool gotLeadingSurrogate = false;
1788        while (true)
1789        {
1790                // Get the next character
1791                const XMLCh nextCh = fReaderMgr.getNextChar();
1792
1793                //  Watch for an end of file
1794                if (!nextCh)
1795                {
1796                        emitError(XMLErrs::UnterminatedComment);
1797                        ThrowXMLwithMemMgr(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF, fMemoryManager);
1798                }
1799
1800                // Check for correct surrogate pairs
1801                if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
1802                {
1803                        if (gotLeadingSurrogate)
1804                                emitError(XMLErrs::Expected2ndSurrogateChar);
1805                        else
1806                                gotLeadingSurrogate = true;
1807                }
1808                else
1809                {
1810                        if (gotLeadingSurrogate)
1811                        {
1812                                if ((nextCh < 0xDC00) || (nextCh > 0xDFFF))
1813                                        emitError(XMLErrs::Expected2ndSurrogateChar);
1814                        }
1815                        // Its got to at least be a valid XML character
1816                        else if (!fReaderMgr.getCurrentReader()->isXMLChar(nextCh)) {
1817
1818                                XMLCh tmpBuf[9];
1819                                XMLString::binToText
1820                                (
1821                                        nextCh
1822                                        , tmpBuf
1823                                        , 8
1824                                        , 16
1825                                        , fMemoryManager
1826                                );
1827                                emitError(XMLErrs::InvalidCharacter, tmpBuf);
1828                        }
1829
1830                        gotLeadingSurrogate = false;
1831                }
1832
1833                if (curState == InText)
1834                {
1835                        // If its a dash, go to OneDash state. Otherwise take as text
1836                        if (nextCh == chDash)
1837                                curState = OneDash;
1838                        else
1839                                bbComment.append(nextCh);
1840                }
1841                else if (curState == OneDash)
1842                {
1843                        //  If its another dash, then we change to the two dashes states.
1844                        //  Otherwise, we have to put in the deficit dash and the new
1845                        //  character and go back to InText.
1846                        if (nextCh == chDash)
1847                        {
1848                                curState = TwoDashes;
1849                        }
1850                        else
1851                        {
1852                                bbComment.append(chDash);
1853                                bbComment.append(nextCh);
1854                                curState = InText;
1855                        }
1856                }
1857                else if (curState == TwoDashes)
1858                {
1859                        // The next character must be the closing bracket
1860                        if (nextCh != chCloseAngle)
1861                        {
1862                                emitError(XMLErrs::IllegalSequenceInComment);
1863                                fReaderMgr.skipPastChar(chCloseAngle);
1864                                return;
1865                        }
1866                        break;
1867                }
1868        }
1869
1870        // If we have an available handler, call back with the comment.
1871        if (fDocHandler)
1872        {
1873                fDocHandler->docComment
1874                (
1875                        bbComment.getRawBuffer()
1876                );
1877        }
1878
1879        DEBUG_MESSAGE("scanComment(" << bbComment.getRawBuffer() << ')');
1880
1881        //mark comment is seen within the current element
1882        if (! fElemStack.isEmpty())
1883                fElemStack.setCommentOrPISeen();
1884#else
1885        DEPRECATED_FEATURE_IN_ICXML;
1886#endif
1887}
1888
1889
1890//  Scans all the input from the start of the file to the root element.
1891//  There does not have to be anything in the prolog necessarily, but usually
1892//  there is at least an XMLDecl.
1893//
1894//  On exit from here we are either at the end of the file or about to read
1895//  the opening < of the root element.
1896void XMLScanner::scanProlog()
1897{
1898        bool sawDocTypeDecl = false;
1899        // Get a buffer for whitespace processing
1900        XMLBufBid bbCData(&fBufMgr);
1901
1902        //  Loop through the prolog. If there is no content, this could go all
1903        //  the way to the end of the file.
1904        try
1905        {
1906                for (;;)
1907                {
1908                        const XMLCh nextCh = fReaderMgr.peekNextChar();
1909
1910                        if (nextCh == chOpenAngle)
1911                        {
1912                                //  Ok, it could be the xml decl, a comment, the doc type line,
1913                                //  or the start of the root element.
1914                                if (checkXMLDecl(true))
1915                                {
1916                                        // There shall be at lease --ONE-- space in between
1917                                        // the tag '<?xml' and the VersionInfo.
1918                                        //
1919                                        //  If we are not at line 1, col 6, then the decl was not
1920                                        //  the first text, so its invalid.
1921                                        const XMLReader* curReader = fReaderMgr.getCurrentReader();
1922                                        if ((curReader->getLineNumber() != 1) || (curReader->getColumnNumber() != 7))
1923                                        {
1924                                                emitError(XMLErrs::XMLDeclMustBeFirst);
1925                                        }
1926
1927                                        scanXMLDecl(Decl_XML);
1928                                }
1929                                else if (fReaderMgr.skippedString(XMLUni::fgPIString))
1930                                {
1931                                        scanPI();
1932                                }
1933                                else if (fReaderMgr.skippedString(XMLUni::fgCommentString))
1934                                {
1935                                        scanComment();
1936                                }
1937                                else if (fReaderMgr.skippedString(XMLUni::fgDocTypeString))
1938                                {
1939                                        if (sawDocTypeDecl)
1940                                        {
1941                                                emitError(XMLErrs::DuplicateDocTypeDecl);
1942                                        }
1943                                        scanDocTypeDecl();
1944                                        sawDocTypeDecl = true;
1945
1946                                        // if reusing grammar, this has been validated already in first scan
1947                                        // skip for performance
1948                                        if (fValidate && fGrammar && !fGrammar->getValidated())
1949                                        {
1950                                                //  validate the DTD scan so far
1951                                                fValidator->preContentValidation(fUseCachedGrammar, true);
1952                                        }
1953                                }
1954                                else
1955                                {
1956                                        // Assume its the start of the root element
1957                                        return;
1958                                }
1959                        }
1960                        else if (fReaderMgr.getCurrentReader()->isWhitespace(nextCh))
1961                        {
1962                                //  If we have a document handler then gather up the
1963                                //  whitespace and call back. Otherwise just skip over spaces.
1964                                if (fDocHandler)
1965                                {
1966                                        fReaderMgr.getSpaces(bbCData.getBuffer());
1967                                        fDocHandler->ignorableWhitespace
1968                                        (
1969                                                bbCData.getRawBuffer()
1970                                                , bbCData.getLen()
1971                                                , false
1972                                        );
1973                                }
1974                                else
1975                                {
1976                                        fReaderMgr.skipPastSpaces();
1977                                }
1978                        }
1979                        else
1980                        {
1981                                emitError(XMLErrs::InvalidDocumentStructure);
1982
1983                                // Watch for end of file and break out
1984                                if (!nextCh)
1985                                        break;
1986                                else
1987                                        fReaderMgr.skipPastChar(chCloseAngle);
1988                        }
1989
1990                }
1991        }
1992        catch(const EndOfEntityException&)
1993        {
1994                //  We should never get an end of entity here. They should only
1995                //  occur within the doc type scanning method, and not leak out to
1996                //  here.
1997                emitError
1998                (
1999                        XMLErrs::UnexpectedEOE
2000                        , "in prolog"
2001                );
2002        }
2003}
2004
2005
2006// ---------------------------------------------------------------------------
2007//  XMLScanner: Private parsing methods
2008// ---------------------------------------------------------------------------
2009
2010//  This guy just scans out a single or double quoted string of characters.
2011//  It does not pass any judgement on the contents and assumes that it is
2012//  illegal to have another quote of the same kind inside the string's
2013//  contents.
2014//
2015//  NOTE: This is for simple stuff like the strings in the XMLDecl which
2016//  cannot have any entities inside them. So this guy does not handle any
2017//  end of entity stuff.
2018bool XMLScanner::getQuotedString(XMLBuffer& toFill)
2019{
2020#ifndef EXCLUDE_TRADITIONAL_XERCES_FUNCTIONS_AND_VARIABLES
2021        // Reset the target buffer
2022        toFill.reset();
2023
2024        // Get the next char which must be a single or double quote
2025        XMLCh quoteCh;
2026        if (!fReaderMgr.skipIfQuote(quoteCh))
2027                return false;
2028
2029                XMLCh nextCh;
2030        // Get another char and see if it matches the starting quote char
2031        while ((nextCh=fReaderMgr.getNextChar())!=quoteCh)
2032        {
2033                //  We should never get either an end of file null char here. If we
2034                //  do, just fail. It will be handled more gracefully in the higher
2035                //  level code that called us.
2036                if (!nextCh)
2037                        return false;
2038
2039                // Else add it to the buffer
2040                toFill.append(nextCh);
2041        }
2042        return true;
2043#else
2044        DEPRECATED_FEATURE_IN_ICXML;
2045#endif
2046}
2047
2048//  This method scans a character reference and returns the character that
2049//  was refered to. It assumes that we've already scanned the &# characters
2050//  that prefix the numeric code.
2051bool XMLScanner::scanCharRef(XMLBuffer & toFill)
2052{
2053        bool gotOne = false;
2054        unsigned int value = 0;
2055
2056        //  Set the radix. Its supposed to be a lower case x if hex. But, in
2057        //  order to recover well, we check for an upper and put out an error
2058        //  for that.
2059        unsigned int radix = 10;
2060        if (fReaderMgr.skippedChar(chLatin_x))
2061        {
2062                radix = 16;
2063        }
2064        else if (fReaderMgr.skippedChar(chLatin_X))
2065        {
2066                emitError(XMLErrs::HexRadixMustBeLowerCase);
2067                radix = 16;
2068        }
2069
2070        while (true)
2071        {
2072                const XMLCh nextCh = fReaderMgr.peekNextChar();
2073
2074                // Watch for EOF
2075                if (!nextCh)
2076                        ThrowXMLwithMemMgr(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF, fMemoryManager);
2077
2078                // Break out on the terminating semicolon
2079                if (nextCh == chSemiColon)
2080                {
2081                        fReaderMgr.getNextChar();
2082                        break;
2083                }
2084
2085                //  Convert this char to a binary value, or bail out if its not
2086                //  one.
2087                unsigned int nextVal;
2088                if ((nextCh >= chDigit_0) && (nextCh <= chDigit_9))
2089                        nextVal = (unsigned int)(nextCh - chDigit_0);
2090                else if ((nextCh >= chLatin_A) && (nextCh <= chLatin_F))
2091                        nextVal= (unsigned int)(10 + (nextCh - chLatin_A));
2092                else if ((nextCh >= chLatin_a) && (nextCh <= chLatin_f))
2093                        nextVal = (unsigned int)(10 + (nextCh - chLatin_a));
2094                else
2095                {
2096                        //  If we got at least a sigit, then do an unterminated ref error.
2097                        //  Else, do an expected a numerical ref thing.
2098                        if (gotOne)
2099                                emitError(XMLErrs::UnterminatedCharRef);
2100                        else
2101                                emitError(XMLErrs::ExpectedNumericalCharRef);
2102                        // Return failure
2103                        return false;
2104                }
2105
2106                //  Make sure its valid for the radix. If not, then just eat the
2107                //  digit and go on after issueing an error. Else, update the
2108                //  running value with this new digit.
2109                if (nextVal >= radix)
2110                {
2111                        XMLCh tmpStr[2];
2112                        tmpStr[0] = nextCh;
2113                        tmpStr[1] = chNull;
2114                        emitError(XMLErrs::BadDigitForRadix, tmpStr);
2115                }
2116                else
2117                {
2118                        value = (value * radix) + nextVal;
2119                        // Guard against overflow.
2120                        if (value > 0x10FFFF)
2121                        {
2122                                // Character reference was not in the valid range
2123                                emitError(XMLErrs::InvalidCharacterRef);
2124                                return false;
2125                        }
2126                }
2127
2128                // Indicate that we got at least one good digit
2129                gotOne = true;
2130
2131                // And eat the last char
2132                fReaderMgr.getNextChar();
2133        }
2134
2135        // Return the char (or chars)
2136        // And check if the character expanded is valid or not
2137        if (value >= 0x10000 && value <= 0x10FFFF)
2138        {
2139                value -= 0x10000;
2140                toFill.append(XMLCh((value >> 10) + 0xD800));
2141                toFill.append(XMLCh((value & 0x3FF) + 0xDC00));
2142        }
2143        else if (value <= 0xFFFD)
2144        {
2145                XMLCh Char = XMLCh(value);
2146                toFill.append(Char);
2147                if (!fReaderMgr.getCurrentReader()->isXMLChar(Char) && !fReaderMgr.getCurrentReader()->isControlChar(Char))
2148                {
2149                        // Character reference was not in the valid range
2150                        emitError(XMLErrs::InvalidCharacterRef);
2151                        return false;
2152                }
2153        }
2154        else
2155        {
2156                // Character reference was not in the valid range
2157                emitError(XMLErrs::InvalidCharacterRef);
2158                return false;
2159        }
2160
2161        return true;
2162}
2163
2164//  Most equal signs can have white space around them, so this little guy
2165//  just makes the calling code cleaner by eating whitespace.
2166bool XMLScanner::scanEq(bool inDecl)
2167{
2168#ifndef EXCLUDE_TRADITIONAL_XERCES_FUNCTIONS_AND_VARIABLES
2169        if (inDecl)
2170        {
2171                bool skippedSomething;
2172                fReaderMgr.skipPastSpaces(skippedSomething, inDecl);
2173                if (fReaderMgr.skippedChar(chEqual))
2174                {
2175                        fReaderMgr.skipPastSpaces(skippedSomething, inDecl);
2176                        return true;
2177                }
2178        }
2179        else
2180        {
2181                fReaderMgr.skipPastSpaces();
2182                if (fReaderMgr.skippedChar(chEqual))
2183                {
2184                        fReaderMgr.skipPastSpaces();
2185                        return true;
2186                }
2187        }
2188        return false;
2189#else
2190        DEPRECATED_FEATURE_IN_ICXML;
2191#endif
2192}
2193
2194
2195XMLSize_t
2196XMLScanner::scanUpToWSOr(XMLBuffer& toFill, const XMLCh chEndChar)
2197{
2198#ifndef EXCLUDE_TRADITIONAL_XERCES_FUNCTIONS_AND_VARIABLES
2199        fReaderMgr.getUpToCharOrWS(toFill, chEndChar);
2200        return toFill.getLen();
2201#else
2202        DEPRECATED_FEATURE_IN_ICXML;
2203#endif
2204}
2205
2206
2207
2208unsigned int
2209XMLScanner::resolveQName(  const XMLCh* const           qName
2210                                                 ,       XMLBuffer&             prefixBuf
2211                                                 , const ElemStack::MapModes    mode
2212                                                 ,       int&                   prefixColonPos)
2213{
2214        DEPRECATED_FEATURE_IN_ICXML;
2215}
2216
2217unsigned int
2218XMLScanner::resolveQNameWithColon(  const XMLCh* const          qName
2219                                                                  ,       XMLBuffer&            prefixBuf
2220                                                                  , const ElemStack::MapModes   mode
2221                                                                  , const int                   prefixColonPos)
2222{
2223        DEPRECATED_FEATURE_IN_ICXML;
2224}
2225
2226// ---------------------------------------------------------------------------
2227//  XMLScanner: Private scanning methods
2228// ---------------------------------------------------------------------------
2229
2230//  This method is called after the end of the root element, to handle
2231//  any miscellaneous stuff hanging around.
2232void XMLScanner::scanMiscellaneous()
2233{
2234        DEPRECATED_FEATURE_IN_ICXML;
2235}
2236
2237/******************************************************************************************************
2238  ICXML - DEPRECATED FUNCTIONS
2239 ******************************************************************************************************/
2240unsigned int XMLScanner::resolvePrefix(const XMLCh* const, const ElemStack::MapModes)
2241{
2242        DEPRECATED_FEATURE_IN_ICXML;
2243}
2244
2245unsigned int *XMLScanner::getNewUIntPtr()
2246{
2247        DEPRECATED_FEATURE_IN_ICXML;
2248}
2249
2250void XMLScanner::resetUIntPool()
2251{
2252        DEPRECATED_FEATURE_IN_ICXML;
2253}
2254
2255void XMLScanner::recreateUIntPool()
2256{
2257        DEPRECATED_FEATURE_IN_ICXML;
2258}
2259
2260void XMLScanner::setURIStringPool(XMLStringPool* const)
2261{
2262        DEPRECATED_FEATURE_IN_ICXML;
2263}
2264
2265bool XMLScanner::getURIText(const unsigned int, XMLBuffer &) const
2266{
2267        DEPRECATED_FEATURE_IN_ICXML;
2268}
2269
2270bool XMLScanner::scanCharRef(XMLCh &, XMLCh &)
2271{
2272        DEPRECATED_FEATURE_IN_ICXML;
2273}
2274
2275XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.