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

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

Changes to icxercesc files

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