source: icXML/icXML-devel/src/icxercesc/internal/DGXMLScanner.cpp @ 2721

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

Fix imports in icXML modified Xerces files

File size: 100.7 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: DGXMLScanner.cpp 833045 2009-11-05 13:21:27Z borisk $
20 */
21
22
23// ---------------------------------------------------------------------------
24//  Includes
25// ---------------------------------------------------------------------------
26#include <icxercesc/internal/DGXMLScanner.hpp>
27#include <xercesc/util/Janitor.hpp>
28#include <xercesc/util/RuntimeException.hpp>
29#include <xercesc/util/UnexpectedEOFException.hpp>
30#include <xercesc/util/XMLUri.hpp>
31#include <xercesc/framework/URLInputSource.hpp>
32#include <xercesc/framework/LocalFileInputSource.hpp>
33#include <xercesc/framework/XMLDocumentHandler.hpp>
34#include <xercesc/framework/XMLEntityHandler.hpp>
35#include <xercesc/framework/XMLPScanToken.hpp>
36#include <icxercesc/framework/XMLGrammarPool.hpp>
37#include <xercesc/framework/XMLDTDDescription.hpp>
38#include <xercesc/internal/EndOfEntityException.hpp>
39#include <icxercesc/validators/common/GrammarResolver.hpp>
40#include <xercesc/validators/DTD/DocTypeHandler.hpp>
41#include <xercesc/validators/DTD/DTDScanner.hpp>
42#include <icxercesc/validators/DTD/DTDValidator.hpp>
43#include <xercesc/util/OutOfMemoryException.hpp>
44#include <xercesc/util/XMLResourceIdentifier.hpp>
45
46XERCES_CPP_NAMESPACE_BEGIN
47
48
49typedef JanitorMemFunCall<DGXMLScanner> CleanupType;
50typedef JanitorMemFunCall<ReaderMgr>    ReaderMgrResetType;
51
52
53// ---------------------------------------------------------------------------
54//  DGXMLScanner: Constructors and Destructor
55// ---------------------------------------------------------------------------
56DGXMLScanner::DGXMLScanner(XMLValidator* const valToAdopt
57                                                 , GrammarResolver* const grammarResolver
58                                                 , MemoryManager* const manager) :
59
60        XMLScanner(valToAdopt, grammarResolver, manager)
61        , fAttrNSList(0)
62        , fDTDValidator(0)
63        , fDTDGrammar(0)
64        , fDTDElemNonDeclPool(0)
65        , fElemCount(0)
66        , fAttDefRegistry(0)
67        , fUndeclaredAttrRegistry(0)
68#ifdef MOVE_BUFFERS_OUT_OF_XMLSCANNER
69        , fAttNameBuf(1023, manager)
70        , fAttValueBuf(1023, manager)
71        , fCDataBuf(1023, manager)
72        , fQNameBuf(1023, manager)
73        , fPrefixBuf(1023, manager)
74        , fURIBuf(1023, manager)
75        , fWSNormalizeBuf(1023, manager)
76#endif
77{
78        CleanupType cleanup(this, &DGXMLScanner::cleanUp);
79
80        try
81        {
82                commonInit();
83        }
84        catch(const OutOfMemoryException&)
85        {
86                // Don't cleanup when out of memory, since executing the
87                // code can cause problems.
88                cleanup.release();
89
90                throw;
91        }
92
93        cleanup.release();
94}
95
96DGXMLScanner::DGXMLScanner( XMLDocumentHandler* const docHandler
97                                                  , DocTypeHandler* const     docTypeHandler
98                                                  , XMLEntityHandler* const   entityHandler
99                                                  , XMLErrorReporter* const   errHandler
100                                                  , XMLValidator* const       valToAdopt
101                                                  , GrammarResolver* const    grammarResolver
102                                                  , MemoryManager* const      manager) :
103
104        XMLScanner(docHandler, docTypeHandler, entityHandler, errHandler, valToAdopt, grammarResolver, manager)
105        , fAttrNSList(0)
106        , fDTDValidator(0)
107        , fDTDGrammar(0)
108        , fDTDElemNonDeclPool(0)
109        , fElemCount(0)
110        , fAttDefRegistry(0)
111        , fUndeclaredAttrRegistry(0)
112#ifdef MOVE_BUFFERS_OUT_OF_XMLSCANNER
113        , fAttNameBuf(1023, manager)
114        , fAttValueBuf(1023, manager)
115        , fCDataBuf(1023, manager)
116        , fQNameBuf(1023, manager)
117        , fPrefixBuf(1023, manager)
118        , fURIBuf(1023, manager)
119        , fWSNormalizeBuf(1023, manager)
120#endif
121{
122        CleanupType cleanup(this, &DGXMLScanner::cleanUp);
123
124        try
125        {
126                commonInit();
127        }
128        catch(const OutOfMemoryException&)
129        {
130                // Don't cleanup when out of memory, since executing the
131                // code can cause problems.
132                cleanup.release();
133
134                throw;
135        }
136
137        cleanup.release();
138}
139
140DGXMLScanner::~DGXMLScanner()
141{
142        cleanUp();
143}
144
145// ---------------------------------------------------------------------------
146//  XMLScanner: Getter methods
147// ---------------------------------------------------------------------------
148NameIdPool<DTDEntityDecl>* DGXMLScanner::getEntityDeclPool()
149{
150        if(!fGrammar)
151                return 0;
152        return ((DTDGrammar*)fGrammar)->getEntityDeclPool();
153}
154
155const NameIdPool<DTDEntityDecl>* DGXMLScanner::getEntityDeclPool() const
156{
157        if(!fGrammar)
158                return 0;
159        return ((DTDGrammar*)fGrammar)->getEntityDeclPool();
160}
161
162// ---------------------------------------------------------------------------
163//  DGXMLScanner: Main entry point to scan a document
164// ---------------------------------------------------------------------------
165void DGXMLScanner::scanDocument(const InputSource& src)
166{
167#ifdef DGXML_SCANNER_DEPRECATED
168        DEPRECATED_FEATURE_IN_ICXML;
169#else
170        //  Bump up the sequence id for this parser instance. This will invalidate
171        //  any previous progressive scan tokens.
172        fSequenceId++;
173
174        ReaderMgrResetType  resetReaderMgr(&fReaderMgr, &ReaderMgr::reset);
175
176        try
177        {
178                //  Reset the scanner and its plugged in stuff for a new run. This
179                //  resets all the data structures, creates the initial reader and
180                //  pushes it on the stack, and sets up the base document path.
181                scanReset(src);
182
183                // If we have a document handler, then call the start document
184                if (fDocHandler)
185                        fDocHandler->startDocument();
186
187                //  Scan the prolog part, which is everything before the root element
188                //  including the DTD subsets.
189                scanProlog();
190
191                //  If we got to the end of input, then its not a valid XML file.
192                //  Else, go on to scan the content.
193                if (fReaderMgr.atEOF())
194                {
195                        emitError(XMLErrs::EmptyMainEntity);
196                }
197                else
198                {
199                        // Scan content, and tell it its not an external entity
200                        if (scanContent())
201                        {
202                                // Do post-parse validation if required
203                                if (fValidate)
204                                {
205                                        //  We handle ID reference semantics at this level since
206                                        //  its required by XML 1.0.
207                                        checkIDRefs();
208
209                                        // Then allow the validator to do any extra stuff it wants
210//                    fValidator->postParseValidation();
211                                }
212
213                                // That went ok, so scan for any miscellaneous stuff
214                                if (!fReaderMgr.atEOF())
215                                        scanMiscellaneous();
216                        }
217                }
218
219                // If we have a document handler, then call the end document
220                if (fDocHandler)
221                        fDocHandler->endDocument();
222        }
223        //  NOTE:
224        //
225        //  In all of the error processing below, the emitError() call MUST come
226        //  before the flush of the reader mgr, or it will fail because it tries
227        //  to find out the position in the XML source of the error.
228        catch(const XMLErrs::Codes)
229        {
230                // This is a 'first failure' exception, so fall through
231        }
232        catch(const XMLValid::Codes)
233        {
234                // This is a 'first fatal error' type exit, so fall through
235        }
236        catch(const XMLException& excToCatch)
237        {
238                //  Emit the error and catch any user exception thrown from here. Make
239                //  sure in all cases we flush the reader manager.
240                fInException = true;
241                try
242                {
243                        if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
244                                emitError
245                                (
246                                        XMLErrs::XMLException_Warning
247                                        , excToCatch.getCode()
248                                        , excToCatch.getMessage()
249                                );
250                        else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
251                                emitError
252                                (
253                                        XMLErrs::XMLException_Fatal
254                                        , excToCatch.getCode()
255                                        , excToCatch.getMessage()
256                                );
257                        else
258                                emitError
259                                (
260                                        XMLErrs::XMLException_Error
261                                        , excToCatch.getCode()
262                                        , excToCatch.getMessage()
263                                );
264                }
265                catch(const OutOfMemoryException&)
266                {
267                        // This is a special case for out-of-memory
268                        // conditions, because resetting the ReaderMgr
269                        // can be problematic.
270                        resetReaderMgr.release();
271
272                        throw;
273                }
274        }
275        catch(const OutOfMemoryException&)
276        {
277                // This is a special case for out-of-memory
278                // conditions, because resetting the ReaderMgr
279                // can be problematic.
280                resetReaderMgr.release();
281
282                throw;
283        }
284#endif
285}
286
287bool DGXMLScanner::scanNext(XMLPScanToken& token)
288{
289#ifdef DGXML_SCANNER_DEPRECATED
290        DEPRECATED_FEATURE_IN_ICXML;
291#else
292        // Make sure this token is still legal
293        if (!isLegalToken(token))
294                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Scan_BadPScanToken, fMemoryManager);
295
296        // Find the next token and remember the reader id
297        XMLSize_t orgReader;
298        XMLTokens curToken;
299
300        ReaderMgrResetType  resetReaderMgr(&fReaderMgr, &ReaderMgr::reset);
301
302        bool retVal = true;
303
304        try
305        {
306                while (true)
307                {
308                        //  We have to handle any end of entity exceptions that happen here.
309                        //  We could be at the end of X nested entities, each of which will
310                        //  generate an end of entity exception as we try to move forward.
311                        try
312                        {
313                                curToken = senseNextToken(orgReader);
314                                break;
315                        }
316                        catch(const EndOfEntityException& toCatch)
317                        {
318                                // Send an end of entity reference event
319                                if (fDocHandler)
320                                        fDocHandler->endEntityReference(toCatch.getEntity());
321                        }
322                }
323
324                if (curToken == Token_CharData)
325                {
326                        scanCharData(fCDataBuf);
327                }
328                else if (curToken == Token_EOF)
329                {
330                        if (!fElemStack.isEmpty())
331                        {
332                                const ElemStack::StackElem* topElem = fElemStack.popTop();
333                                emitError
334                                (
335                                        XMLErrs::EndedWithTagsOnStack
336                                        , topElem->fThisElement->getFullName()
337                                );
338                        }
339
340                        retVal = false;
341                }
342                else
343                {
344                        // Its some sort of markup
345                        bool gotData = true;
346                        switch(curToken)
347                        {
348                                case Token_CData :
349                                        // Make sure we are within content
350                                        if (fElemStack.isEmpty())
351                                                emitError(XMLErrs::CDATAOutsideOfContent);
352                                        scanCDSection();
353                                        break;
354
355                                case Token_Comment :
356                                        scanComment();
357                                        break;
358
359                                case Token_EndTag :
360                                        scanEndTag(gotData);
361                                        break;
362
363                                case Token_PI :
364                                        scanPI();
365                                        break;
366
367                                case Token_StartTag :
368                                        if (fDoNamespaces)
369                                                scanStartTagNS(gotData);
370                                        else
371                                                scanStartTag(gotData);
372                                        break;
373
374                                default :
375                                        fReaderMgr.skipToChar(chOpenAngle);
376                                        break;
377                        }
378
379                        if (orgReader != fReaderMgr.getCurrentReaderNum())
380                                emitError(XMLErrs::PartialMarkupInEntity);
381
382                        // If we hit the end, then do the miscellaneous part
383                        if (!gotData)
384                        {
385                                // Do post-parse validation if required
386                                if (fValidate)
387                                {
388                                        //  We handle ID reference semantics at this level since
389                                        //  its required by XML 1.0.
390                                        checkIDRefs();
391
392                                        // Then allow the validator to do any extra stuff it wants
393//                    fValidator->postParseValidation();
394                                }
395
396                                // That went ok, so scan for any miscellaneous stuff
397                                scanMiscellaneous();
398
399                                if (fDocHandler)
400                                        fDocHandler->endDocument();
401                        }
402                }
403        }
404        //  NOTE:
405        //
406        //  In all of the error processing below, the emitError() call MUST come
407        //  before the flush of the reader mgr, or it will fail because it tries
408        //  to find out the position in the XML source of the error.
409        catch(const XMLErrs::Codes)
410        {
411                // This is a 'first failure' exception, so return failure
412                retVal = false;
413        }
414        catch(const XMLValid::Codes)
415        {
416                // This is a 'first fatal error' type exit, so return failure
417                retVal = false;
418        }
419        catch(const XMLException& excToCatch)
420        {
421                //  Emit the error and catch any user exception thrown from here. Make
422                //  sure in all cases we flush the reader manager.
423                fInException = true;
424                try
425                {
426                        if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
427                                emitError
428                                (
429                                        XMLErrs::XMLException_Warning
430                                        , excToCatch.getCode()
431                                        , excToCatch.getMessage()
432                                );
433                        else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
434                                emitError
435                                (
436                                        XMLErrs::XMLException_Fatal
437                                        , excToCatch.getCode()
438                                        , excToCatch.getMessage()
439                                );
440                        else
441                                emitError
442                                (
443                                        XMLErrs::XMLException_Error
444                                        , excToCatch.getCode()
445                                        , excToCatch.getMessage()
446                                );
447                }
448                catch(const OutOfMemoryException&)
449                {
450                        // This is a special case for out-of-memory
451                        // conditions, because resetting the ReaderMgr
452                        // can be problematic.
453                        resetReaderMgr.release();
454
455                        throw;
456                }
457
458                retVal = false;
459        }
460        catch(const OutOfMemoryException&)
461        {
462                // This is a special case for out-of-memory
463                // conditions, because resetting the ReaderMgr
464                // can be problematic.
465                resetReaderMgr.release();
466
467                throw;
468        }
469
470        // If we are not at the end, release the object that will
471        // reset the ReaderMgr.
472        if (retVal)
473                resetReaderMgr.release();
474
475        return retVal;
476#endif
477}
478
479
480// ---------------------------------------------------------------------------
481//  DGXMLScanner: Private scanning methods
482// ---------------------------------------------------------------------------
483
484//  This method will kick off the scanning of the primary content of the
485//  document, i.e. the elements.
486bool DGXMLScanner::scanContent()
487{
488#ifdef DGXML_SCANNER_DEPRECATED
489        DEPRECATED_FEATURE_IN_ICXML;
490#else
491        //  Go into a loop until we hit the end of the root element, or we fall
492        //  out because there is no root element.
493        //
494        //  We have to do kind of a deeply nested double loop here in order to
495        //  avoid doing the setup/teardown of the exception handler on each
496        //  round. Doing it this way we only do it when an exception actually
497        //  occurs.
498        bool gotData = true;
499        bool inMarkup = false;
500        while (gotData)
501        {
502                try
503                {
504                        while (gotData)
505                        {
506                                //  Sense what the next top level token is. According to what
507                                //  this tells us, we will call something to handle that kind
508                                //  of thing.
509                                XMLSize_t orgReader;
510                                const XMLTokens curToken = senseNextToken(orgReader);
511
512                                //  Handle character data and end of file specially. Char data
513                                //  is not markup so we don't want to handle it in the loop
514                                //  below.
515                                if (curToken == Token_CharData)
516                                {
517                                        //  Scan the character data and call appropriate events. Let
518                                        //  him use our local character data buffer for efficiency.
519                                        scanCharData(fCDataBuf);
520                                        continue;
521                                }
522                                else if (curToken == Token_EOF)
523                                {
524                                        //  The element stack better be empty at this point or we
525                                        //  ended prematurely before all elements were closed.
526                                        if (!fElemStack.isEmpty())
527                                        {
528                                                const ElemStack::StackElem* topElem = fElemStack.popTop();
529                                                emitError
530                                                (
531                                                        XMLErrs::EndedWithTagsOnStack
532                                                        , topElem->fThisElement->getFullName()
533                                                );
534                                        }
535
536                                        // Its the end of file, so clear the got data flag
537                                        gotData = false;
538                                        continue;
539                                }
540
541                                // We are in some sort of markup now
542                                inMarkup = true;
543
544                                //  According to the token we got, call the appropriate
545                                //  scanning method.
546                                switch(curToken)
547                                {
548                                        case Token_CData :
549                                                // Make sure we are within content
550                                                if (fElemStack.isEmpty())
551                                                        emitError(XMLErrs::CDATAOutsideOfContent);
552                                                scanCDSection();
553                                                break;
554
555                                        case Token_Comment :
556                                                scanComment();
557                                                break;
558
559                                        case Token_EndTag :
560                                                scanEndTag(gotData);
561                                                break;
562
563                                        case Token_PI :
564                                                scanPI();
565                                                break;
566
567                                        case Token_StartTag :
568                                                if (fDoNamespaces)
569                                                        scanStartTagNS(gotData);
570                                                else
571                                                        scanStartTag(gotData);
572                                                break;
573
574                                        default :
575                                                fReaderMgr.skipToChar(chOpenAngle);
576                                                break;
577                                }
578
579                                if (orgReader != fReaderMgr.getCurrentReaderNum())
580                                        emitError(XMLErrs::PartialMarkupInEntity);
581
582                                // And we are back out of markup again
583                                inMarkup = false;
584                        }
585                }
586                catch(const EndOfEntityException& toCatch)
587                {
588                        //  If we were in some markup when this happened, then its a
589                        //  partial markup error.
590                        if (inMarkup)
591                                emitError(XMLErrs::PartialMarkupInEntity);
592
593                        // Send an end of entity reference event
594                        if (fDocHandler)
595                                fDocHandler->endEntityReference(toCatch.getEntity());
596
597                        inMarkup = false;
598                }
599        }
600
601        // It went ok, so return success
602        return true;
603#endif
604}
605
606
607void DGXMLScanner::scanEndTag(bool& gotData)
608{
609#ifdef DGXML_SCANNER_DEPRECATED
610        DEPRECATED_FEATURE_IN_ICXML;
611#else
612        //  Assume we will still have data until proven otherwise. It will only
613        //  ever be false if this is the end of the root element.
614        gotData = true;
615
616        //  Check if the element stack is empty. If so, then this is an unbalanced
617        //  element (i.e. more ends than starts, perhaps because of bad text
618        //  causing one to be skipped.)
619        if (fElemStack.isEmpty())
620        {
621                emitError(XMLErrs::MoreEndThanStartTags);
622                fReaderMgr.skipPastChar(chCloseAngle);
623                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Scan_UnbalancedStartEnd, fMemoryManager);
624        }
625
626        //  Pop the stack of the element we are supposed to be ending. Remember
627        //  that we don't own this. The stack just keeps them and reuses them.
628
629        unsigned int uriId = (fDoNamespaces)
630                ? fElemStack.getCurrentURI() :
631                #ifdef TEST_NAMESPACE_RESOLVER
632                XMLNamespaceResolver::fEmptyUriId;
633                #else
634                fEmptyNamespaceId;
635                #endif
636
637        //  Pop the stack of the element we are supposed to be ending. Remember
638        //  that we don't own this. The stack just keeps them and reuses them.
639        const ElemStack::StackElem* topElem = fElemStack.popTop();
640        XMLElementDecl *tempElement = topElem->fThisElement;
641
642        // See if it was the root element, to avoid multiple calls below
643        const bool isRoot = fElemStack.isEmpty();
644
645        // Make sure that its the end of the element that we expect
646        if (!fReaderMgr.skippedStringLong(tempElement->getFullName()))
647        {
648                emitError
649                (
650                        XMLErrs::ExpectedEndOfTagX
651                        , tempElement->getFullName()
652                );
653                fReaderMgr.skipPastChar(chCloseAngle);
654                return;
655        }
656
657        // Make sure we are back on the same reader as where we started
658        if (topElem->fReaderNum != fReaderMgr.getCurrentReaderNum())
659                emitError(XMLErrs::PartialTagMarkupError);
660
661        // Skip optional whitespace
662        fReaderMgr.skipPastSpaces();
663
664        // Make sure we find the closing bracket
665        if (!fReaderMgr.skippedChar(chCloseAngle))
666        {
667                emitError
668                (
669                        XMLErrs::UnterminatedEndTag
670                        , topElem->fThisElement->getFullName()
671                );
672        }
673
674        //  If validation is enabled, then lets pass him the list of children and
675        //  this element and let him validate it.
676        if (fValidate)
677        {
678
679           //
680           // XML1.0-3rd
681           // Validity Constraint:
682           // The declaration matches EMPTY and the element has no content (not even
683           // entity references, comments, PIs or white space).
684           //
685           if ( (topElem->fCommentOrPISeen)               &&
686                        (((DTDElementDecl*) topElem->fThisElement)->getModelType() == DTDElementDecl::Empty))
687           {
688                   fValidator->emitError
689                           (
690                           XMLValid::EmptyElemHasContent
691                           , topElem->fThisElement->getFullName()
692                           );
693           }
694
695           //
696           // XML1.0-3rd
697           // Validity Constraint:
698           //
699           // The declaration matches children and the sequence of child elements
700           // belongs to the language generated by the regular expression in the
701           // content model, with optional white space, comments and PIs
702           // (i.e. markup matching production [27] Misc) between the start-tag and
703           // the first child element, between child elements, or between the last
704           // child element and the end-tag.
705           //
706           // Note that
707           //    a CDATA section containing only white space or
708           //    a reference to an entity whose replacement text is character references
709           //       expanding to white space do not match the nonterminal S, and hence
710           //       cannot appear in these positions; however,
711           //    a reference to an internal entity with a literal value consisting
712           //       of character references expanding to white space does match S,
713           //       since its replacement text is the white space resulting from expansion
714           //       of the character references.
715           //
716#if 0
717           if ( (topElem->fReferenceEscaped)               &&
718                        (((DTDElementDecl*) topElem->fThisElement)->getModelType() == DTDElementDecl::Children))
719           {
720                   fValidator->emitError
721                           (
722                           XMLValid::ElemChildrenHasInvalidWS
723                           , topElem->fThisElement->getFullName()
724                           );
725           }
726#endif
727#ifndef STORE_CHILDREN_INFORMATION_IN_PARSER
728                XMLSize_t failure;
729                bool res = fValidator->checkContent
730                (
731                        topElem->fThisElement
732                        , topElem->fChildren
733                        , topElem->fChildCount
734                        , &failure
735                );
736                if (!res)
737                {
738                        //  One of the elements is not valid for the content. NOTE that
739                        //  if no children were provided but the content model requires
740                        //  them, it comes back with a zero value. But we cannot use that
741                        //  to index the child array in this case, and have to put out a
742                        //  special message.
743                        if (!topElem->fChildCount)
744                        {
745                                fValidator->emitError
746                                (
747                                        XMLValid::EmptyNotValidForContent
748                                        , topElem->fThisElement->getFormattedContentModel()
749                                );
750                        }
751                        else if (failure >= topElem->fChildCount)
752                        {
753                                fValidator->emitError
754                                (
755                                        XMLValid::NotEnoughElemsForCM
756                                        , topElem->fThisElement->getFormattedContentModel()
757                                );
758                        }
759                        else
760                        {
761
762                                fValidator->emitError
763                                (
764                                        XMLValid::ElementNotValidForContent
765                                        , topElem->fChildren[failure]->getRawName()
766                                        , topElem->fThisElement->getFormattedContentModel()
767                                );
768                        }
769                }
770#endif
771        }
772
773        // If we have a doc handler, tell it about the end tag
774        if (fDocHandler)
775        {
776                fDocHandler->endElement
777                (
778                        *topElem->fThisElement
779                        , uriId
780                        , isRoot
781                        , (fDoNamespaces)
782                                ? topElem->fThisElement->getElementName()->getPrefix()
783                                : XMLUni::fgZeroLenString
784                );
785        }
786
787        // If this was the root, then done with content
788        gotData = !isRoot;
789#endif
790}
791
792
793//  This method handles the high level logic of scanning the DOCType
794//  declaration. This calls the DTDScanner and kicks off both the scanning of
795//  the internal subset and the scanning of the external subset, if any.
796//
797//  When we get here the '<!DOCTYPE' part has already been scanned, which is
798//  what told us that we had a doc type decl to parse.
799void DGXMLScanner::scanDocTypeDecl()
800{
801#ifdef DGXML_SCANNER_DEPRECATED
802        DEPRECATED_FEATURE_IN_ICXML;
803#else
804        if (fDocTypeHandler)
805                fDocTypeHandler->resetDocType();
806
807        // There must be some space after DOCTYPE
808        bool skippedSomething;
809        fReaderMgr.skipPastSpaces(skippedSomething);
810        if (!skippedSomething)
811        {
812                emitError(XMLErrs::ExpectedWhitespace);
813
814                // Just skip the Doctype declaration and return
815                fReaderMgr.skipPastChar(chCloseAngle);
816                return;
817        }
818
819        // Get a buffer for the root element
820        XMLBufBid bbRootName(&fBufMgr);
821
822        //  Get a name from the input, which should be the name of the root
823        //  element of the upcoming content.
824        int  colonPosition;
825        bool validName = fDoNamespaces ? fReaderMgr.getQName(bbRootName.getBuffer(), &colonPosition) :
826                                                                         fReaderMgr.getName(bbRootName.getBuffer());
827        if (!validName)
828        {
829                if (bbRootName.isEmpty())
830                        emitError(XMLErrs::NoRootElemInDOCTYPE);
831                else
832                        emitError(XMLErrs::InvalidRootElemInDOCTYPE, bbRootName.getRawBuffer());
833                fReaderMgr.skipPastChar(chCloseAngle);
834                return;
835        }
836
837        //  Store the root element name for later check
838        setRootElemName(bbRootName.getRawBuffer());
839
840        //  This element obviously is not going to exist in the element decl
841        //  pool yet, but we need to call docTypeDecl. So force it into
842        //  the element decl pool, marked as being there because it was in
843        //  the DOCTYPE. Later, when its declared, the status will be updated.
844        //
845        //  Only do this if we are not reusing the validator! If we are reusing,
846        //  then look it up instead. It has to exist!
847        MemoryManager* const  rootDeclMgr =
848                fUseCachedGrammar ? fMemoryManager : fGrammarPoolMemoryManager;
849
850        DTDElementDecl* rootDecl = new (rootDeclMgr) DTDElementDecl
851        (
852                bbRootName.getRawBuffer()
853                #ifdef TEST_NAMESPACE_RESOLVER
854                , XMLNamespaceResolver::fEmptyUriId
855                #else
856                , fEmptyNamespaceId
857                #endif
858                , DTDElementDecl::Any
859                , rootDeclMgr
860        );
861
862        Janitor<DTDElementDecl> rootDeclJanitor(rootDecl);
863        rootDecl->setCreateReason(DTDElementDecl::AsRootElem);
864        rootDecl->setExternalElemDeclaration(true);
865        if(!fUseCachedGrammar)
866        {
867                fGrammar->putElemDecl(rootDecl);
868                rootDeclJanitor.release();
869        } else
870        {
871                // put this in the undeclared pool so it gets deleted...
872                XMLElementDecl* elemDecl = fDTDElemNonDeclPool->getByKey(bbRootName.getRawBuffer());
873                if (elemDecl)
874                {
875                        rootDecl->setId(elemDecl->getId());
876                }
877                else
878                {
879                        rootDecl->setId(fDTDElemNonDeclPool->put((DTDElementDecl*)rootDecl));
880                        rootDeclJanitor.release();
881                }
882        }
883
884        // Skip any spaces after the name
885        fReaderMgr.skipPastSpaces();
886
887        //  And now if we are looking at a >, then we are done. It is not
888        //  required to have an internal or external subset, though why you
889        //  would not escapes me.
890        if (fReaderMgr.skippedChar(chCloseAngle)) {
891
892                //  If we have a doc type handler and advanced callbacks are enabled,
893                //  call the doctype event.
894                if (fDocTypeHandler)
895                        fDocTypeHandler->doctypeDecl(*rootDecl, 0, 0, false);
896                return;
897        }
898
899        // either internal/external subset
900        if (fValScheme == Val_Auto && !fValidate)
901                fValidate = true;
902
903        bool    hasIntSubset = false;
904        bool    hasExtSubset = false;
905        XMLCh*  sysId = 0;
906        XMLCh*  pubId = 0;
907
908        DTDScanner dtdScanner
909        (
910                (DTDGrammar*) fGrammar
911                , fDocTypeHandler
912                , fGrammarPoolMemoryManager
913                , fMemoryManager
914        );
915        dtdScanner.setScannerInfo(this, &fReaderMgr, &fBufMgr);
916
917        //  If the next character is '[' then we have no external subset cause
918        //  there is no system id, just the opening character of the internal
919        //  subset. Else, has to be an id.
920        //
921        // Just look at the next char, don't eat it.
922        if (fReaderMgr.peekNextChar() == chOpenSquare)
923        {
924                hasIntSubset = true;
925        }
926        else
927        {
928                // Indicate we have an external subset
929                hasExtSubset = true;
930                fHasNoDTD = false;
931
932                // Get buffers for the ids
933                XMLBufBid bbPubId(&fBufMgr);
934                XMLBufBid bbSysId(&fBufMgr);
935
936                // Get the external subset id
937                if (!dtdScanner.scanId(bbPubId.getBuffer(), bbSysId.getBuffer(), DTDScanner::IDType_External))
938                {
939                        fReaderMgr.skipPastChar(chCloseAngle);
940                        return;
941                }
942
943                // Get copies of the ids we got
944                pubId = XMLString::replicate(bbPubId.getRawBuffer(), fMemoryManager);
945                sysId = XMLString::replicate(bbSysId.getRawBuffer(), fMemoryManager);
946
947                // Skip spaces and check again for the opening of an internal subset
948                fReaderMgr.skipPastSpaces();
949
950                // Just look at the next char, don't eat it.
951                if (fReaderMgr.peekNextChar() == chOpenSquare) {
952                        hasIntSubset = true;
953                }
954        }
955
956        // Insure that the ids get cleaned up, if they got allocated
957        ArrayJanitor<XMLCh> janSysId(sysId, fMemoryManager);
958        ArrayJanitor<XMLCh> janPubId(pubId, fMemoryManager);
959
960        //  If we have a doc type handler and advanced callbacks are enabled,
961        //  call the doctype event.
962        if (fDocTypeHandler)
963                fDocTypeHandler->doctypeDecl(*rootDecl, pubId, sysId, hasIntSubset, hasExtSubset);
964
965        //  Ok, if we had an internal subset, we are just past the [ character
966        //  and need to parse that first.
967        if (hasIntSubset)
968        {
969                // Eat the opening square bracket
970                fReaderMgr.getNextChar();
971
972                checkInternalDTD(hasExtSubset, sysId, pubId);
973
974                //  And try to scan the internal subset. If we fail, try to recover
975                //  by skipping forward tot he close angle and returning.
976                if (!dtdScanner.scanInternalSubset())
977                {
978                        fReaderMgr.skipPastChar(chCloseAngle);
979                        return;
980                }
981
982                //  Do a sanity check that some expanded PE did not propogate out of
983                //  the doctype. This could happen if it was terminated early by bad
984                //  syntax.
985                if (fReaderMgr.getReaderDepth() > 1)
986                {
987                        emitError(XMLErrs::PEPropogated);
988
989                        // Ask the reader manager to pop back down to the main level
990                        fReaderMgr.cleanStackBackTo(1);
991                }
992
993                fReaderMgr.skipPastSpaces();
994        }
995
996        // And that should leave us at the closing > of the DOCTYPE line
997        if (!fReaderMgr.skippedChar(chCloseAngle))
998        {
999                //  Do a special check for the common scenario of an extra ] char at
1000                //  the end. This is easy to recover from.
1001                if (fReaderMgr.skippedChar(chCloseSquare)
1002                &&  fReaderMgr.skippedChar(chCloseAngle))
1003                {
1004                        emitError(XMLErrs::ExtraCloseSquare);
1005                }
1006                 else
1007                {
1008                        emitError(XMLErrs::UnterminatedDOCTYPE);
1009                        fReaderMgr.skipPastChar(chCloseAngle);
1010                }
1011        }
1012
1013        //  If we had an external subset, then we need to deal with that one
1014        //  next. If we are reusing the validator, then don't scan it.
1015        if (hasExtSubset) {
1016
1017                InputSource* srcUsed=0;
1018                Janitor<InputSource> janSrc(srcUsed);
1019                // If we had an internal subset and we're using the cached grammar, it
1020                // means that the ignoreCachedDTD is set, so we ignore the cached
1021                // grammar
1022                if (fUseCachedGrammar && !hasIntSubset)
1023                {
1024                        srcUsed = resolveSystemId(sysId, pubId);
1025                        if (srcUsed) {
1026                                janSrc.reset(srcUsed);
1027                                Grammar* grammar = fGrammarResolver->getGrammar(srcUsed->getSystemId());
1028
1029                                if (grammar && grammar->getGrammarType() == Grammar::DTDGrammarType) {
1030
1031                                        fDTDGrammar = (DTDGrammar*) grammar;
1032                                        fGrammar = fDTDGrammar;
1033                                        fValidator->setGrammar(fGrammar);
1034                                        // If we don't report at least the external subset boundaries,
1035                                        // an advanced document handler cannot know when the DTD end,
1036                                        // since we've already sent a doctype decl that indicates there's
1037                                        // there's an external subset.
1038                                        if (fDocTypeHandler)
1039                                        {
1040                                                fDocTypeHandler->startExtSubset();
1041                                                fDocTypeHandler->endExtSubset();
1042                                        }
1043
1044                                        return;
1045                                }
1046                        }
1047                }
1048
1049                if (fLoadExternalDTD || fValidate)
1050                {
1051                        // And now create a reader to read this entity
1052                        XMLReader* reader;
1053                        if(srcUsed) {
1054                                reader = fReaderMgr.createReader
1055                                                (
1056                                                        *srcUsed
1057                                                        , false
1058                                                        , XMLReader::RefFrom_NonLiteral
1059                                                        , XMLReader::Type_General
1060                                                        , XMLReader::Source_External
1061                                                        , fCalculateSrcOfs
1062                                                        , fLowWaterMark
1063                                                );
1064                        }
1065                        else {
1066                                reader = fReaderMgr.createReader
1067                                                (
1068                                                        sysId
1069                                                        , pubId
1070                                                        , false
1071                                                        , XMLReader::RefFrom_NonLiteral
1072                                                        , XMLReader::Type_General
1073                                                        , XMLReader::Source_External
1074                                                        , srcUsed
1075                                                        , fCalculateSrcOfs
1076                                                        , fLowWaterMark
1077                                                        , fDisableDefaultEntityResolution
1078                                                );
1079                                janSrc.reset(srcUsed);
1080                        }
1081                        //  If it failed then throw an exception
1082                        if (!reader)
1083                                ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Gen_CouldNotOpenDTD, srcUsed ? srcUsed->getSystemId() : sysId, fMemoryManager);
1084
1085                        if (fToCacheGrammar) {
1086
1087                                unsigned int stringId = fGrammarResolver->getStringPool()->addOrFind(srcUsed->getSystemId());
1088                                const XMLCh* sysIdStr = fGrammarResolver->getStringPool()->getValueForId(stringId);
1089
1090                                fGrammarResolver->orphanGrammar(XMLUni::fgDTDEntityString);
1091                                ((XMLDTDDescription*) (fGrammar->getGrammarDescription()))->setSystemId(sysIdStr);
1092                                fGrammarResolver->putGrammar(fGrammar);
1093                        }
1094
1095                        //  In order to make the processing work consistently, we have to
1096                        //  make this look like an external entity. So create an entity
1097                        //  decl and fill it in and push it with the reader, as happens
1098                        //  with an external entity. Put a janitor on it to insure it gets
1099                        //  cleaned up. The reader manager does not adopt them.
1100                        const XMLCh gDTDStr[] = { chLatin_D, chLatin_T, chLatin_D , chNull };
1101                        DTDEntityDecl* declDTD = new (fMemoryManager) DTDEntityDecl(gDTDStr, false, fMemoryManager);
1102                        declDTD->setSystemId(sysId);
1103                        declDTD->setIsExternal(true);
1104                        Janitor<DTDEntityDecl> janDecl(declDTD);
1105
1106                        // Mark this one as a throw at end
1107                        reader->setThrowAtEnd(true);
1108
1109                        // And push it onto the stack, with its pseudo name
1110                        fReaderMgr.pushReader(reader, declDTD);
1111
1112                        // Tell it its not in an include section
1113                        dtdScanner.scanExtSubsetDecl(false, true);
1114                }
1115        }
1116#endif
1117}
1118
1119bool DGXMLScanner::scanStartTag(bool& gotData)
1120{
1121#ifdef DGXML_SCANNER_DEPRECATED
1122        DEPRECATED_FEATURE_IN_ICXML;
1123#else
1124        //  Assume we will still have data until proven otherwise. It will only
1125        //  ever be false if this is the root and its empty.
1126        gotData = true;
1127
1128        //  Get the QName. In this case, we are not doing namespaces, so we just
1129        //  use it as is and don't have to break it into parts.
1130
1131        bool validName = fReaderMgr.getName(fQNameBuf);
1132        if (!validName)
1133        {
1134                if (fQNameBuf.isEmpty())
1135                        emitError(XMLErrs::ExpectedElementName);
1136                else
1137                        emitError(XMLErrs::InvalidElementName, fQNameBuf.getRawBuffer());
1138                fReaderMgr.skipToChar(chOpenAngle);
1139                return false;
1140        }
1141
1142        // Assume it won't be an empty tag
1143        bool isEmpty = false;
1144
1145        // See if its the root element
1146        const bool isRoot = fElemStack.isEmpty();
1147
1148        //  Lets try to look up the element in the validator's element decl pool
1149        //  We can pass bogus values for the URI id and the base name. We know that
1150        //  this can only be called if we are doing a DTD style validator and that
1151        //  he will only look at the QName.
1152        //
1153        //  We *do not* tell him to fault in a decl if he does not find one - NG.
1154        bool wasAdded = false;
1155        const XMLCh* qnameRawBuf = fQNameBuf.getRawBuffer();
1156
1157        XMLElementDecl* elemDecl = fGrammar->getElemDecl
1158        (
1159                #ifdef TEST_NAMESPACE_RESOLVER
1160                XMLNamespaceResolver::fEmptyUriId
1161                #else
1162                fEmptyNamespaceId
1163                #endif
1164                , 0
1165                , qnameRawBuf
1166                , Grammar::TOP_LEVEL_SCOPE
1167        );
1168        // look in the undeclared pool:
1169        if(!elemDecl)
1170        {
1171                elemDecl = fDTDElemNonDeclPool->getByKey(qnameRawBuf);
1172        }
1173        if(!elemDecl)
1174        {
1175                wasAdded = true;
1176                elemDecl = new (fMemoryManager) DTDElementDecl
1177                (
1178                        qnameRawBuf
1179                        #ifdef TEST_NAMESPACE_RESOLVER
1180                        , XMLNamespaceResolver::fEmptyUriId
1181                        #else
1182                        , fEmptyNamespaceId
1183                        #endif
1184                        , DTDElementDecl::Any
1185                        , fMemoryManager
1186                );
1187                elemDecl->setId(fDTDElemNonDeclPool->put((DTDElementDecl*)elemDecl));
1188        }
1189
1190        if (fValidate) {
1191
1192                if (wasAdded)
1193                {
1194                        // This is to tell the reuse Validator that this element was
1195                        // faulted-in, was not an element in the validator pool originally
1196                        elemDecl->setCreateReason(XMLElementDecl::JustFaultIn);
1197
1198                        fValidator->emitError
1199                        (
1200                                XMLValid::ElementNotDefined
1201                                , qnameRawBuf
1202                        );
1203                }
1204                // If its not marked declared, then emit an error
1205                else if (!elemDecl->isDeclared())
1206                {
1207                        fValidator->emitError
1208                        (
1209                                XMLValid::ElementNotDefined
1210                                , qnameRawBuf
1211                        );
1212                }
1213
1214
1215                fValidator->validateElement(elemDecl);
1216        }
1217
1218        // Expand the element stack and add the new element
1219        fElemStack.addLevel(elemDecl, fReaderMgr.getCurrentReaderNum());
1220
1221        //  If this is the first element and we are validating, check the root
1222        //  element.
1223        if (isRoot)
1224        {
1225                fRootGrammar = fGrammar;
1226
1227                if (fValidate)
1228                {
1229                        //  If a DocType exists, then check if it matches the root name there.
1230                        if (fRootElemName && !XMLString::equals(qnameRawBuf, fRootElemName))
1231                                fValidator->emitError(XMLValid::RootElemNotLikeDocType);
1232                }
1233        }
1234        else if (fValidate)
1235        {
1236                //  If the element stack is not empty, then add this element as a
1237                //  child of the previous top element. If its empty, this is the root
1238                //  elem and is not the child of anything.
1239                fElemStack.addChild(elemDecl->getElementName(), true);
1240        }
1241
1242        // Skip any whitespace after the name
1243        fReaderMgr.skipPastSpaces();
1244
1245        //  We loop until we either see a /> or >, handling attribute/value
1246        //  pairs until we get there.
1247        XMLSize_t    attCount = 0;
1248        XMLSize_t    curAttListSize = fAttrList.size();
1249        wasAdded = false;
1250
1251        fElemCount++;
1252
1253        while (true)
1254        {
1255                // And get the next non-space character
1256                XMLCh nextCh = fReaderMgr.peekNextChar();
1257
1258                //  If the next character is not a slash or closed angle bracket,
1259                //  then it must be whitespace, since whitespace is required
1260                //  between the end of the last attribute and the name of the next
1261                //  one.
1262                if (attCount)
1263                {
1264                        if ((nextCh != chForwardSlash) && (nextCh != chCloseAngle))
1265                        {
1266                                if (fReaderMgr.getCurrentReader()->isWhitespace(nextCh))
1267                                {
1268                                        // Ok, skip by them and peek another char
1269                                        fReaderMgr.skipPastSpaces();
1270                                        nextCh = fReaderMgr.peekNextChar();
1271                                }
1272                                 else
1273                                {
1274                                        // Emit the error but keep on going
1275                                        emitError(XMLErrs::ExpectedWhitespace);
1276                                }
1277                        }
1278                }
1279
1280                //  Ok, here we first check for any of the special case characters.
1281                //  If its not one, then we do the normal case processing, which
1282                //  assumes that we've hit an attribute value, Otherwise, we do all
1283                //  the special case checks.
1284                if (!fReaderMgr.getCurrentReader()->isSpecialStartTagChar(nextCh))
1285                {
1286                        //  Assume its going to be an attribute, so get a name from
1287                        //  the input.
1288
1289                        validName = fReaderMgr.getName(fAttNameBuf);
1290                        if (!validName)
1291                        {
1292                                if (fAttNameBuf.isEmpty())
1293                                        emitError(XMLErrs::ExpectedAttrName);
1294                                else
1295                                        emitError(XMLErrs::InvalidAttrName, fAttNameBuf.getRawBuffer());
1296                                fReaderMgr.skipPastChar(chCloseAngle);
1297                                return false;
1298                        }
1299
1300                        // And next must be an equal sign
1301                        if (!scanEq())
1302                        {
1303                                static const XMLCh tmpList[] =
1304                                {
1305                                        chSingleQuote, chDoubleQuote, chCloseAngle
1306                                        , chOpenAngle, chForwardSlash, chNull
1307                                };
1308
1309                                emitError(XMLErrs::ExpectedEqSign);
1310
1311                                //  Try to sync back up by skipping forward until we either
1312                                //  hit something meaningful.
1313                                const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
1314
1315                                if ((chFound == chCloseAngle) || (chFound == chForwardSlash))
1316                                {
1317                                        // Jump back to top for normal processing of these
1318                                        continue;
1319                                }
1320                                else if ((chFound == chSingleQuote)
1321                                          ||  (chFound == chDoubleQuote)
1322                                          ||  fReaderMgr.getCurrentReader()->isWhitespace(chFound))
1323                                {
1324                                        // Just fall through assuming that the value is to follow
1325                                }
1326                                else if (chFound == chOpenAngle)
1327                                {
1328                                        // Assume a malformed tag and that new one is starting
1329                                        emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
1330                                        return false;
1331                                }
1332                                else
1333                                {
1334                                        // Something went really wrong
1335                                        return false;
1336                                }
1337                        }
1338
1339                        //  See if this attribute is declared for this element. If we are
1340                        //  not validating of course it will not be at first, but we will
1341                        //  fault it into the pool (to avoid lots of redundant errors.)
1342                        XMLCh * namePtr = fAttNameBuf.getRawBuffer();
1343                        XMLAttDef* attDef = ((DTDElementDecl *)elemDecl)->getAttDef(namePtr);
1344
1345                        //  Skip any whitespace before the value and then scan the att
1346                        //  value. This will come back normalized with entity refs and
1347                        //  char refs expanded.
1348                        fReaderMgr.skipPastSpaces();
1349                        if (!scanAttValue(attDef, namePtr, fAttValueBuf))
1350                        {
1351                                static const XMLCh tmpList[] =
1352                                {
1353                                        chCloseAngle, chOpenAngle, chForwardSlash, chNull
1354                                };
1355
1356                                emitError(XMLErrs::ExpectedAttrValue);
1357
1358                                //  It failed, so lets try to get synced back up. We skip
1359                                //  forward until we find some whitespace or one of the
1360                                //  chars in our list.
1361                                const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
1362
1363                                if ((chFound == chCloseAngle)
1364                                ||  (chFound == chForwardSlash)
1365                                ||  fReaderMgr.getCurrentReader()->isWhitespace(chFound))
1366                                {
1367                                        //  Just fall through and process this attribute, though
1368                                        //  the value will be "".
1369                                }
1370                                else if (chFound == chOpenAngle)
1371                                {
1372                                        // Assume a malformed tag and that new one is starting
1373                                        emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
1374                                        return false;
1375                                }
1376                                else
1377                                {
1378                                        // Something went really wrong
1379                                        return false;
1380                                }
1381                        }
1382
1383                        //  Add this attribute to the attribute list that we use to
1384                        //  pass them to the handler. We reuse its existing elements
1385                        //  but expand it as required.
1386                        // Note that we want to this first since this will
1387                        // make a copy of the namePtr; we can then make use of
1388                        // that copy in the hashtable lookup that checks
1389                        // for duplicates.  This will mean we may have to update
1390                        // the type of the XMLAttr later.
1391                        XMLAttr* curAtt;
1392                        const XMLCh* attrValue = fAttValueBuf.getRawBuffer();
1393
1394                        if (attCount >= curAttListSize) {
1395                                curAtt = new (fMemoryManager) XMLAttr(fMemoryManager);
1396                                fAttrList.addElement(curAtt);
1397                        }
1398                        else {
1399                                curAtt = fAttrList.elementAt(attCount);
1400                        }
1401
1402                        curAtt->setSpecified(true);
1403
1404                        // NO NAMESPACE CODE
1405                        {
1406                                curAtt->set(
1407                                        0, namePtr, XMLUni::fgZeroLenString, XMLUni::fgZeroLenString
1408                                        , (attDef)?attDef->getType():XMLAttDef::CData
1409                                );
1410
1411                                // now need to prepare for duplicate detection
1412                                if (attDef) {
1413                                        unsigned int *curCountPtr = fAttDefRegistry->get(attDef);
1414                                        if (!curCountPtr) {
1415                                                curCountPtr = getNewUIntPtr();
1416                                                *curCountPtr = fElemCount;
1417                                                fAttDefRegistry->put(attDef, curCountPtr);
1418                                        }
1419                                        else if (*curCountPtr < fElemCount) {
1420                                                *curCountPtr = fElemCount;
1421                                        }
1422                                        else {
1423                                                emitError(
1424                                                        XMLErrs::AttrAlreadyUsedInSTag
1425                                                        , attDef->getFullName(), elemDecl->getFullName()
1426                                                );
1427                                        }
1428                                }
1429                                else
1430                                {
1431                                        // reset namePtr so it refers to newly-allocated memory
1432                                        namePtr = (XMLCh *)curAtt->getQName();
1433                                        if (!fUndeclaredAttrRegistry->putIfNotPresent(namePtr, 0))
1434                                        {
1435                                                emitError(
1436                                                        XMLErrs::AttrAlreadyUsedInSTag
1437                                                        , namePtr, elemDecl->getFullName()
1438                                                );
1439                                        }
1440                                }
1441                        }
1442
1443                        if (fValidate)
1444                        {
1445                                if (attDef) {
1446                                        // Let the validator pass judgement on the attribute value
1447                                        fValidator->validateAttrValue(
1448                                                attDef, fAttValueBuf.getRawBuffer(), false, elemDecl
1449                                        );
1450                                }
1451                                else
1452                                {
1453                                        fValidator->emitError
1454                                        (
1455                                                XMLValid::AttNotDefinedForElement
1456                                                , fAttNameBuf.getRawBuffer(), qnameRawBuf
1457                                        );
1458                                }
1459                        }
1460
1461                        // must set the newly-minted value on the XMLAttr:
1462                        curAtt->setValue(attrValue);
1463                        attCount++;
1464
1465                        // And jump back to the top of the loop
1466                        continue;
1467                }
1468
1469                //  It was some special case character so do all of the checks and
1470                //  deal with it.
1471                if (!nextCh)
1472                        ThrowXMLwithMemMgr(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF, fMemoryManager);
1473
1474                if (nextCh == chForwardSlash)
1475                {
1476                        fReaderMgr.getNextChar();
1477                        isEmpty = true;
1478                        if (!fReaderMgr.skippedChar(chCloseAngle))
1479                                emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
1480                        break;
1481                }
1482                else if (nextCh == chCloseAngle)
1483                {
1484                        fReaderMgr.getNextChar();
1485                        break;
1486                }
1487                else if (nextCh == chOpenAngle)
1488                {
1489                        //  Check for this one specially, since its going to be common
1490                        //  and it is kind of auto-recovering since we've already hit the
1491                        //  next open bracket, which is what we would have seeked to (and
1492                        //  skipped this whole tag.)
1493                        emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
1494                        break;
1495                }
1496                else if ((nextCh == chSingleQuote) || (nextCh == chDoubleQuote))
1497                {
1498                        //  Check for this one specially, which is probably a missing
1499                        //  attribute name, e.g. ="value". Just issue expected name
1500                        //  error and eat the quoted string, then jump back to the
1501                        //  top again.
1502                        emitError(XMLErrs::ExpectedAttrName);
1503                        fReaderMgr.getNextChar();
1504                        fReaderMgr.skipQuotedString(nextCh);
1505                        fReaderMgr.skipPastSpaces();
1506                        continue;
1507                }
1508        }
1509
1510        if(attCount)
1511        {
1512                // clean up after ourselves:
1513                // clear the map used to detect duplicate attributes
1514                fUndeclaredAttrRegistry->removeAll();
1515        }
1516
1517        //  Now lets get the fAttrList filled in. This involves faulting in any
1518        //  defaulted and fixed attributes and normalizing the values of any that
1519        //  we got explicitly.
1520        //
1521        //  We update the attCount value with the total number of attributes, but
1522        //  it goes in with the number of values we got during the raw scan of
1523        //  explictly provided attrs above.
1524        attCount = buildAttList(attCount, elemDecl, fAttrList);
1525
1526        //  If we have a document handler, then tell it about this start tag. We
1527        //  don't have any URI id to send along, so send fEmptyNamespaceId. We also do not send
1528        //  any prefix since its just one big name if we are not doing namespaces.
1529        unsigned int uriId =
1530        #ifdef TEST_NAMESPACE_RESOLVER
1531        XMLNamespaceResolver::fEmptyUriId;
1532        #else
1533        fEmptyNamespaceId;
1534        #endif
1535        if (fDocHandler)
1536        {
1537                fDocHandler->startElement
1538                (
1539                        *elemDecl
1540                        , uriId
1541                        , 0
1542                        , fAttrList
1543                        , attCount
1544                        , isEmpty
1545                        , isRoot
1546                );
1547        }
1548
1549        //  If empty, validate content right now if we are validating and then
1550        //  pop the element stack top. Else, we have to update the current stack
1551        //  top's namespace mapping elements.
1552        if (isEmpty)
1553        {
1554                // If validating, then insure that its legal to have no content
1555                if (fValidate)
1556                {
1557                        XMLSize_t failure;
1558                        bool res = fValidator->checkContent(elemDecl, 0, 0, &failure);
1559                        if (!res)
1560                        {
1561                                fValidator->emitError
1562                                (
1563                                        XMLValid::ElementNotValidForContent
1564                                        , qnameRawBuf
1565                                        , elemDecl->getFormattedContentModel()
1566                                );
1567                        }
1568                }
1569
1570                // Pop the element stack back off since it'll never be used now
1571                fElemStack.popTop();
1572
1573                // If the elem stack is empty, then it was an empty root
1574                if (isRoot)
1575                        gotData = false;
1576        }
1577
1578        return true;
1579#endif
1580}
1581
1582
1583bool DGXMLScanner::scanStartTagNS(bool& gotData)
1584{
1585#ifdef DGXML_SCANNER_DEPRECATED
1586        DEPRECATED_FEATURE_IN_ICXML;
1587#else
1588        //  Assume we will still have data until proven otherwise. It will only
1589        //  ever be false if this is the root and its empty.
1590        gotData = true;
1591
1592        //  Get the QName. In this case, we are not doing namespaces, so we just
1593        //  use it as is and don't have to break it into parts.
1594
1595        int  colonPosition;
1596        bool validName = fReaderMgr.getQName(fQNameBuf, &colonPosition);
1597        if (!validName)
1598        {
1599                if (fQNameBuf.isEmpty())
1600                        emitError(XMLErrs::ExpectedElementName);
1601                else
1602                        emitError(XMLErrs::InvalidElementName, fQNameBuf.getRawBuffer());
1603                fReaderMgr.skipToChar(chOpenAngle);
1604                return false;
1605        }
1606
1607        // Assume it won't be an empty tag
1608        bool isEmpty = false;
1609
1610        // See if its the root element
1611        const bool isRoot = fElemStack.isEmpty();
1612
1613        //  Lets try to look up the element in the validator's element decl pool
1614        //  We can pass bogus values for the URI id and the base name. We know that
1615        //  this can only be called if we are doing a DTD style validator and that
1616        //  he will only look at the QName.
1617        //
1618        //  We *do not* tell him to fault in a decl if he does not find one - NG.
1619        bool wasAdded = false;
1620        const XMLCh* qnameRawBuf = fQNameBuf.getRawBuffer();
1621
1622        XMLElementDecl* elemDecl = fGrammar->getElemDecl
1623        (
1624                #ifdef TEST_NAMESPACE_RESOLVER
1625                XMLNamespaceResolver::fEmptyUriId
1626                #else
1627                fEmptyNamespaceId
1628                #endif
1629                , 0
1630                , qnameRawBuf
1631                , Grammar::TOP_LEVEL_SCOPE
1632        );
1633        // look in the undeclared pool:
1634        if(!elemDecl)
1635        {
1636                elemDecl = fDTDElemNonDeclPool->getByKey(qnameRawBuf);
1637        }
1638        if(!elemDecl)
1639        {
1640                wasAdded = true;
1641                elemDecl = new (fMemoryManager) DTDElementDecl
1642                (
1643                        qnameRawBuf
1644                        #ifdef TEST_NAMESPACE_RESOLVER
1645                        , XMLNamespaceResolver::fEmptyUriId
1646                        #else
1647                        , fEmptyNamespaceId
1648                        #endif
1649                        , DTDElementDecl::Any
1650                        , fMemoryManager
1651                );
1652                elemDecl->setId(fDTDElemNonDeclPool->put((DTDElementDecl*)elemDecl));
1653        }
1654
1655        if (fValidate) {
1656
1657                if (wasAdded)
1658                {
1659                        // This is to tell the reuse Validator that this element was
1660                        // faulted-in, was not an element in the validator pool originally
1661                        elemDecl->setCreateReason(XMLElementDecl::JustFaultIn);
1662
1663                        fValidator->emitError
1664                        (
1665                                XMLValid::ElementNotDefined
1666                                , qnameRawBuf
1667                        );
1668                }
1669                // If its not marked declared, then emit an error
1670                else if (!elemDecl->isDeclared())
1671                {
1672                        fValidator->emitError
1673                        (
1674                                XMLValid::ElementNotDefined
1675                                , qnameRawBuf
1676                        );
1677                }
1678
1679
1680                fValidator->validateElement(elemDecl);
1681        }
1682
1683        // Expand the element stack and add the new element
1684        fElemStack.addLevel(elemDecl, fReaderMgr.getCurrentReaderNum());
1685
1686        //  If this is the first element and we are validating, check the root
1687        //  element.
1688        if (isRoot)
1689        {
1690                fRootGrammar = fGrammar;
1691
1692                if (fValidate)
1693                {
1694                        //  If a DocType exists, then check if it matches the root name there.
1695                        if (fRootElemName && !XMLString::equals(qnameRawBuf, fRootElemName))
1696                                fValidator->emitError(XMLValid::RootElemNotLikeDocType);
1697                }
1698        }
1699        else if (fValidate)
1700        {
1701                //  If the element stack is not empty, then add this element as a
1702                //  child of the previous top element. If its empty, this is the root
1703                //  elem and is not the child of anything.
1704                fElemStack.addChild(elemDecl->getElementName(), true);
1705        }
1706
1707        // Skip any whitespace after the name
1708        fReaderMgr.skipPastSpaces();
1709
1710        //  We loop until we either see a /> or >, handling attribute/value
1711        //  pairs until we get there.
1712        XMLSize_t    attCount = 0;
1713        XMLSize_t    curAttListSize = fAttrList.size();
1714        wasAdded = false;
1715
1716        fElemCount++;
1717
1718        while (true)
1719        {
1720                // And get the next non-space character
1721                XMLCh nextCh = fReaderMgr.peekNextChar();
1722
1723                //  If the next character is not a slash or closed angle bracket,
1724                //  then it must be whitespace, since whitespace is required
1725                //  between the end of the last attribute and the name of the next
1726                //  one.
1727                if (attCount)
1728                {
1729                        if ((nextCh != chForwardSlash) && (nextCh != chCloseAngle))
1730                        {
1731                                if (fReaderMgr.getCurrentReader()->isWhitespace(nextCh))
1732                                {
1733                                        // Ok, skip by them and peek another char
1734                                        fReaderMgr.skipPastSpaces();
1735                                        nextCh = fReaderMgr.peekNextChar();
1736                                }
1737                                 else
1738                                {
1739                                        // Emit the error but keep on going
1740                                        emitError(XMLErrs::ExpectedWhitespace);
1741                                }
1742                        }
1743                }
1744
1745                //  Ok, here we first check for any of the special case characters.
1746                //  If its not one, then we do the normal case processing, which
1747                //  assumes that we've hit an attribute value, Otherwise, we do all
1748                //  the special case checks.
1749                if (!fReaderMgr.getCurrentReader()->isSpecialStartTagChar(nextCh))
1750                {
1751                        //  Assume its going to be an attribute, so get a name from
1752                        //  the input.
1753
1754                        validName = fReaderMgr.getQName(fAttNameBuf, &colonPosition);
1755                        if (!validName)
1756                        {
1757                                if (fAttNameBuf.isEmpty())
1758                                        emitError(XMLErrs::ExpectedAttrName);
1759                                else
1760                                        emitError(XMLErrs::InvalidAttrName, fAttNameBuf.getRawBuffer());
1761                                fReaderMgr.skipPastChar(chCloseAngle);
1762                                return false;
1763                        }
1764
1765                        // And next must be an equal sign
1766                        if (!scanEq())
1767                        {
1768                                static const XMLCh tmpList[] =
1769                                {
1770                                        chSingleQuote, chDoubleQuote, chCloseAngle
1771                                        , chOpenAngle, chForwardSlash, chNull
1772                                };
1773
1774                                emitError(XMLErrs::ExpectedEqSign);
1775
1776                                //  Try to sync back up by skipping forward until we either
1777                                //  hit something meaningful.
1778                                const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
1779
1780                                if ((chFound == chCloseAngle) || (chFound == chForwardSlash))
1781                                {
1782                                        // Jump back to top for normal processing of these
1783                                        continue;
1784                                }
1785                                else if ((chFound == chSingleQuote)
1786                                          ||  (chFound == chDoubleQuote)
1787                                          ||  fReaderMgr.getCurrentReader()->isWhitespace(chFound))
1788                                {
1789                                        // Just fall through assuming that the value is to follow
1790                                }
1791                                else if (chFound == chOpenAngle)
1792                                {
1793                                        // Assume a malformed tag and that new one is starting
1794                                        emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
1795                                        return false;
1796                                }
1797                                else
1798                                {
1799                                        // Something went really wrong
1800                                        return false;
1801                                }
1802                        }
1803
1804                        //  See if this attribute is declared for this element. If we are
1805                        //  not validating of course it will not be at first, but we will
1806                        //  fault it into the pool (to avoid lots of redundant errors.)
1807                        XMLCh * namePtr = fAttNameBuf.getRawBuffer();
1808                        XMLAttDef* attDef = ((DTDElementDecl *)elemDecl)->getAttDef(namePtr);
1809
1810                        //  Skip any whitespace before the value and then scan the att
1811                        //  value. This will come back normalized with entity refs and
1812                        //  char refs expanded.
1813                        fReaderMgr.skipPastSpaces();
1814                        if (!scanAttValue(attDef, namePtr, fAttValueBuf))
1815                        {
1816                                static const XMLCh tmpList[] =
1817                                {
1818                                        chCloseAngle, chOpenAngle, chForwardSlash, chNull
1819                                };
1820
1821                                emitError(XMLErrs::ExpectedAttrValue);
1822
1823                                //  It failed, so lets try to get synced back up. We skip
1824                                //  forward until we find some whitespace or one of the
1825                                //  chars in our list.
1826                                const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
1827
1828                                if ((chFound == chCloseAngle)
1829                                ||  (chFound == chForwardSlash)
1830                                ||  fReaderMgr.getCurrentReader()->isWhitespace(chFound))
1831                                {
1832                                        //  Just fall through and process this attribute, though
1833                                        //  the value will be "".
1834                                }
1835                                else if (chFound == chOpenAngle)
1836                                {
1837                                        // Assume a malformed tag and that new one is starting
1838                                        emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
1839                                        return false;
1840                                }
1841                                else
1842                                {
1843                                        // Something went really wrong
1844                                        return false;
1845                                }
1846                        }
1847
1848                        //  Add this attribute to the attribute list that we use to
1849                        //  pass them to the handler. We reuse its existing elements
1850                        //  but expand it as required.
1851                        // Note that we want to this first since this will
1852                        // make a copy of the namePtr; we can then make use of
1853                        // that copy in the hashtable lookup that checks
1854                        // for duplicates.  This will mean we may have to update
1855                        // the type of the XMLAttr later.
1856                        XMLAttr* curAtt;
1857                        const XMLCh* attrValue = fAttValueBuf.getRawBuffer();
1858
1859                        if (attCount >= curAttListSize)
1860                        {
1861                                curAtt = new (fMemoryManager) XMLAttr(fMemoryManager);
1862                                fAttrList.addElement(curAtt);
1863                        }
1864                        else
1865                        {
1866                                curAtt = fAttrList.elementAt(attCount);
1867                        }
1868
1869                        curAtt->setSpecified(true);
1870                        // DO NAMESPACES
1871                        {
1872                                curAtt->set
1873                                (
1874                                        #ifdef TEST_NAMESPACE_RESOLVER
1875                                        XMLNamespaceResolver::fEmptyUriId
1876                                        #else
1877                                        fEmptyNamespaceId
1878                                        #endif
1879                                        , namePtr
1880                                        , XMLUni::fgZeroLenString
1881                                        , (attDef)? attDef->getType() : XMLAttDef::CData
1882                                );
1883
1884                                // each attribute has the prefix:suffix="value"
1885                                const XMLCh* attPrefix = curAtt->getPrefix();
1886                                const XMLCh* attLocalName = curAtt->getName();
1887
1888                                if (attPrefix && *attPrefix)
1889                                {
1890                                        if (XMLString::equals(attPrefix, XMLUni::fgXMLString))
1891                                        {
1892                                                #ifdef TEST_NAMESPACE_RESOLVER
1893                                                curAtt->setURIId(XMLNamespaceResolver::fXMLUriId);
1894                                                #else
1895                                                curAtt->setURIId(fXMLNamespaceId);
1896                                                #endif
1897                                        }
1898                                        else if (XMLString::equals(attPrefix, XMLUni::fgXMLNSString))
1899                                        {
1900                                                #ifdef TEST_NAMESPACE_RESOLVER
1901                                                curAtt->setURIId(XMLNamespaceResolver::fXMLNSUriId);
1902                                                #else
1903                                                curAtt->setURIId(fXMLNSNamespaceId);
1904                                                updateNSMap(attPrefix, attLocalName, attrValue);
1905                                                #endif
1906                                        }
1907                                        else
1908                                        {
1909                                                fAttrNSList->addElement(curAtt);
1910                                        }
1911                                }
1912                                else if (XMLString::equals(XMLUni::fgXMLNSString, attLocalName))
1913                                {
1914                                        updateNSMap(attPrefix, XMLUni::fgZeroLenString, attrValue);
1915                                }
1916
1917                                // NOTE: duplicate attribute check will be done, when we map
1918                                //       namespaces to all attributes
1919                                if (attDef) {
1920                                        unsigned int *curCountPtr = fAttDefRegistry->get(attDef);
1921                                        if (!curCountPtr) {
1922                                                curCountPtr = getNewUIntPtr();
1923                                                *curCountPtr = fElemCount;
1924                                                fAttDefRegistry->put(attDef, curCountPtr);
1925                                   }
1926                                        else if (*curCountPtr < fElemCount) {
1927                                                *curCountPtr = fElemCount;
1928                                        }
1929                                }
1930                        }
1931
1932                        if (fValidate)
1933                        {
1934                                if (attDef) {
1935                                        // Let the validator pass judgement on the attribute value
1936                                        fValidator->validateAttrValue(
1937                                                attDef, fAttValueBuf.getRawBuffer(), false, elemDecl
1938                                        );
1939                                }
1940                                else
1941                                {
1942                                        fValidator->emitError
1943                                        (
1944                                                XMLValid::AttNotDefinedForElement
1945                                                , fAttNameBuf.getRawBuffer(), qnameRawBuf
1946                                        );
1947                                }
1948                        }
1949
1950                        // must set the newly-minted value on the XMLAttr:
1951                        curAtt->setValue(attrValue);
1952                        attCount++;
1953
1954                        // And jump back to the top of the loop
1955                        continue;
1956                }
1957
1958                //  It was some special case character so do all of the checks and
1959                //  deal with it.
1960                if (!nextCh)
1961                        ThrowXMLwithMemMgr(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF, fMemoryManager);
1962
1963                if (nextCh == chForwardSlash)
1964                {
1965                        fReaderMgr.getNextChar();
1966                        isEmpty = true;
1967                        if (!fReaderMgr.skippedChar(chCloseAngle))
1968                                emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
1969                        break;
1970                }
1971                else if (nextCh == chCloseAngle)
1972                {
1973                        fReaderMgr.getNextChar();
1974                        break;
1975                }
1976                else if (nextCh == chOpenAngle)
1977                {
1978                        //  Check for this one specially, since its going to be common
1979                        //  and it is kind of auto-recovering since we've already hit the
1980                        //  next open bracket, which is what we would have seeked to (and
1981                        //  skipped this whole tag.)
1982                        emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
1983                        break;
1984                }
1985                else if ((nextCh == chSingleQuote) || (nextCh == chDoubleQuote))
1986                {
1987                        //  Check for this one specially, which is probably a missing
1988                        //  attribute name, e.g. ="value". Just issue expected name
1989                        //  error and eat the quoted string, then jump back to the
1990                        //  top again.
1991                        emitError(XMLErrs::ExpectedAttrName);
1992                        fReaderMgr.getNextChar();
1993                        fReaderMgr.skipQuotedString(nextCh);
1994                        fReaderMgr.skipPastSpaces();
1995                        continue;
1996                }
1997        }
1998
1999        //  Make an initial pass through the list and find any xmlns attributes.
2000        if (attCount)
2001        {
2002                scanAttrListforNameSpaces(&fAttrList, attCount, elemDecl);
2003        }
2004
2005        if(attCount)
2006        {
2007                // clean up after ourselves:
2008                // clear the map used to detect duplicate attributes
2009                fUndeclaredAttrRegistry->removeAll();
2010        }
2011
2012        //  Now lets get the fAttrList filled in. This involves faulting in any
2013        //  defaulted and fixed attributes and normalizing the values of any that
2014        //  we got explicitly.
2015        //
2016        //  We update the attCount value with the total number of attributes, but
2017        //  it goes in with the number of values we got during the raw scan of
2018        //  explictly provided attrs above.
2019        attCount = buildAttList(attCount, elemDecl, fAttrList);
2020
2021        //  If we have a document handler, then tell it about this start tag. We
2022        //  don't have any URI id to send along, so send fEmptyNamespaceId. We also do not send
2023        //  any prefix since its just one big name if we are not doing namespaces.
2024        if (fDocHandler)
2025        {
2026                unsigned int uriId = resolvePrefix
2027                        (
2028                                elemDecl->getElementName()->getPrefix()
2029                                , ElemStack::Mode_Element
2030                        );
2031
2032                fDocHandler->startElement
2033                (
2034                        *elemDecl
2035                        , uriId
2036                        , elemDecl->getElementName()->getPrefix()
2037                        , fAttrList
2038                        , attCount
2039                        , isEmpty
2040                        , isRoot
2041                );
2042        }
2043
2044        //  If empty, validate content right now if we are validating and then
2045        //  pop the element stack top. Else, we have to update the current stack
2046        //  top's namespace mapping elements.
2047        if (isEmpty)
2048        {
2049                // If validating, then insure that its legal to have no content
2050                if (fValidate)
2051                {
2052                        XMLSize_t failure;
2053                        bool res = fValidator->checkContent(elemDecl, 0, 0, &failure);
2054                        if (!res)
2055                        {
2056                                fValidator->emitError
2057                                (
2058                                        XMLValid::ElementNotValidForContent
2059                                        , qnameRawBuf
2060                                        , elemDecl->getFormattedContentModel()
2061                                );
2062                        }
2063                }
2064
2065                // Pop the element stack back off since it'll never be used now
2066                fElemStack.popTop();
2067
2068                // If the elem stack is empty, then it was an empty root
2069                if (isRoot)
2070                        gotData = false;
2071        }
2072
2073        return true;
2074#endif
2075}
2076
2077// ---------------------------------------------------------------------------
2078//  DGXMLScanner: Grammar preparsing
2079// ---------------------------------------------------------------------------
2080Grammar* DGXMLScanner::loadGrammar(const   InputSource& src
2081                                                                   , const short        grammarType
2082                                                                   , const bool         toCache)
2083{
2084#ifdef DGXML_SCANNER_DEPRECATED
2085        DEPRECATED_FEATURE_IN_ICXML;
2086#else
2087        Grammar* loadedGrammar = 0;
2088
2089        ReaderMgrResetType  resetReaderMgr(&fReaderMgr, &ReaderMgr::reset);
2090
2091        try
2092        {
2093                fGrammarResolver->cacheGrammarFromParse(false);
2094                fGrammarResolver->useCachedGrammarInParse(false);
2095                fRootGrammar = 0;
2096
2097                if (fValScheme == Val_Auto) {
2098                        fValidate = true;
2099                }
2100
2101                // Reset some status flags
2102                fInException = false;
2103                fStandalone = false;
2104                fErrorCount = 0;
2105                fHasNoDTD = true;
2106
2107                if (grammarType == Grammar::DTDGrammarType) {
2108                        loadedGrammar = loadDTDGrammar(src, toCache);
2109                }
2110        }
2111        //  NOTE:
2112        //
2113        //  In all of the error processing below, the emitError() call MUST come
2114        //  before the flush of the reader mgr, or it will fail because it tries
2115        //  to find out the position in the XML source of the error.
2116        catch(const XMLErrs::Codes)
2117        {
2118                // This is a 'first failure' exception, so fall through
2119        }
2120        catch(const XMLValid::Codes)
2121        {
2122                // This is a 'first fatal error' type exit, so fall through
2123        }
2124        catch(const XMLException& excToCatch)
2125        {
2126                //  Emit the error and catch any user exception thrown from here. Make
2127                //  sure in all cases we flush the reader manager.
2128                fInException = true;
2129                try
2130                {
2131                        if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
2132                                emitError
2133                                (
2134                                        XMLErrs::XMLException_Warning
2135                                        , excToCatch.getCode()
2136                                        , excToCatch.getMessage()
2137                                );
2138                        else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
2139                                emitError
2140                                (
2141                                        XMLErrs::XMLException_Fatal
2142                                        , excToCatch.getCode()
2143                                        , excToCatch.getMessage()
2144                                );
2145                        else
2146                                emitError
2147                                (
2148                                        XMLErrs::XMLException_Error
2149                                        , excToCatch.getCode()
2150                                        , excToCatch.getMessage()
2151                                );
2152                }
2153                catch(const OutOfMemoryException&)
2154                {
2155                        // This is a special case for out-of-memory
2156                        // conditions, because resetting the ReaderMgr
2157                        // can be problematic.
2158                        resetReaderMgr.release();
2159
2160                        throw;
2161                }
2162        }
2163        catch(const OutOfMemoryException&)
2164        {
2165                // This is a special case for out-of-memory
2166                // conditions, because resetting the ReaderMgr
2167                // can be problematic.
2168                resetReaderMgr.release();
2169
2170                throw;
2171        }
2172
2173        return loadedGrammar;
2174#endif
2175}
2176
2177Grammar* DGXMLScanner::loadDTDGrammar(const InputSource& src,
2178                                                                          const bool toCache)
2179{
2180#ifdef DGXML_SCANNER_DEPRECATED
2181        DEPRECATED_FEATURE_IN_ICXML;
2182#else
2183        // Reset the validators
2184        fDTDValidator->reset();
2185        if (fValidatorFromUser)
2186                fValidator->reset();
2187
2188        fDTDGrammar = new (fGrammarPoolMemoryManager) DTDGrammar(fGrammarPoolMemoryManager);
2189        fGrammarResolver->putGrammar(fDTDGrammar);
2190        fGrammar = fDTDGrammar;
2191        fValidator->setGrammar(fGrammar);
2192
2193        //  And for all installed handlers, send reset events. This gives them
2194        //  a chance to flush any cached data.
2195        if (fDocHandler)
2196                fDocHandler->resetDocument();
2197        if (fEntityHandler)
2198                fEntityHandler->resetEntities();
2199        if (fErrorReporter)
2200                fErrorReporter->resetErrors();
2201
2202        // Clear out the id reference list
2203        resetValidationContext();
2204
2205        if (toCache) {
2206
2207                unsigned int sysId = fGrammarResolver->getStringPool()->addOrFind(src.getSystemId());
2208                const XMLCh* sysIdStr = fGrammarResolver->getStringPool()->getValueForId(sysId);
2209
2210                fGrammarResolver->orphanGrammar(XMLUni::fgDTDEntityString);
2211                ((XMLDTDDescription*) (fGrammar->getGrammarDescription()))->setSystemId(sysIdStr);
2212                fGrammarResolver->putGrammar(fGrammar);
2213        }
2214
2215        //  Handle the creation of the XML reader object for this input source.
2216        //  This will provide us with transcoding and basic lexing services.
2217        XMLReader* newReader = fReaderMgr.createReader
2218        (
2219                src
2220                , false
2221                , XMLReader::RefFrom_NonLiteral
2222                , XMLReader::Type_General
2223                , XMLReader::Source_External
2224                , fCalculateSrcOfs
2225                , fLowWaterMark
2226        );
2227        if (!newReader) {
2228                if (src.getIssueFatalErrorIfNotFound())
2229                        ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource, src.getSystemId(), fMemoryManager);
2230                else
2231                        ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource_Warning, src.getSystemId(), fMemoryManager);
2232        }
2233
2234        //  In order to make the processing work consistently, we have to
2235        //  make this look like an external entity. So create an entity
2236        //  decl and fill it in and push it with the reader, as happens
2237        //  with an external entity. Put a janitor on it to insure it gets
2238        //  cleaned up. The reader manager does not adopt them.
2239        const XMLCh gDTDStr[] = { chLatin_D, chLatin_T, chLatin_D , chNull };
2240        DTDEntityDecl* declDTD = new (fMemoryManager) DTDEntityDecl(gDTDStr, false, fMemoryManager);
2241        declDTD->setSystemId(src.getSystemId());
2242        declDTD->setIsExternal(true);
2243        Janitor<DTDEntityDecl> janDecl(declDTD);
2244
2245        // Mark this one as a throw at end
2246        newReader->setThrowAtEnd(true);
2247
2248        // And push it onto the stack, with its pseudo name
2249        fReaderMgr.pushReader(newReader, declDTD);
2250
2251        //  If we have a doc type handler and advanced callbacks are enabled,
2252        //  call the doctype event.
2253        if (fDocTypeHandler) {
2254
2255                // Create a dummy root
2256                DTDElementDecl* rootDecl = new (fGrammarPoolMemoryManager) DTDElementDecl
2257                (
2258                        gDTDStr
2259                        #ifdef TEST_NAMESPACE_RESOLVER
2260                        , XMLNamespaceResolver::fEmptyUriId
2261                        #else
2262                        , fEmptyNamespaceId
2263                        #endif
2264                        , DTDElementDecl::Any
2265                        , fGrammarPoolMemoryManager
2266                );
2267                rootDecl->setCreateReason(DTDElementDecl::AsRootElem);
2268                rootDecl->setExternalElemDeclaration(true);
2269                Janitor<DTDElementDecl> janSrc(rootDecl);
2270
2271                fDocTypeHandler->doctypeDecl(*rootDecl, src.getPublicId(), src.getSystemId(), false, true);
2272        }
2273
2274        // Create DTDScanner
2275        DTDScanner dtdScanner
2276        (
2277                (DTDGrammar*)fGrammar
2278                , fDocTypeHandler
2279                , fGrammarPoolMemoryManager
2280                , fMemoryManager
2281        );
2282        dtdScanner.setScannerInfo(this, &fReaderMgr, &fBufMgr);
2283
2284        // Tell it its not in an include section
2285        dtdScanner.scanExtSubsetDecl(false, true);
2286
2287        if (fValidate) {
2288                //  validate the DTD scan so far
2289                fValidator->preContentValidation(false, true);
2290        }
2291
2292        if (toCache)
2293                fGrammarResolver->cacheGrammars();
2294
2295        return fDTDGrammar;
2296#endif
2297}
2298
2299
2300// ---------------------------------------------------------------------------
2301//  DGXMLScanner: Private helper methods
2302// ---------------------------------------------------------------------------
2303//  This method handles the common initialization, to avoid having to do
2304//  it redundantly in multiple constructors.
2305void DGXMLScanner::commonInit()
2306{
2307#ifdef DGXML_SCANNER_DEPRECATED
2308        DEPRECATED_FEATURE_IN_ICXML;
2309#else
2310        //  And we need one for the raw attribute scan. This just stores key/
2311        //  value string pairs (prior to any processing.)
2312        fAttrNSList = new (fMemoryManager) ValueVectorOf<XMLAttr*>(8, fMemoryManager);
2313
2314        //  Create the Validator and init them
2315        fDTDValidator = new (fMemoryManager) DTDValidator();
2316        initValidator(fDTDValidator);
2317        fDTDElemNonDeclPool = new (fMemoryManager) NameIdPool<DTDElementDecl>(29, 128, fMemoryManager);
2318        fAttDefRegistry = new (fMemoryManager) RefHashTableOf<unsigned int, PtrHasher>
2319        (
2320                131, false, fMemoryManager
2321        );
2322        fUndeclaredAttrRegistry = new (fMemoryManager) Hash2KeysSetOf<StringHasher>(7, fMemoryManager);
2323
2324        if (fValidator)
2325        {
2326                if (!fValidator->handlesDTD())
2327                   ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Gen_NoDTDValidator, fMemoryManager);
2328        }
2329        else
2330        {
2331                fValidator = fDTDValidator;
2332        }
2333#endif
2334}
2335
2336void DGXMLScanner::cleanUp()
2337{
2338        delete fAttrNSList;
2339        delete fDTDValidator;
2340        delete fDTDElemNonDeclPool;
2341        delete fAttDefRegistry;
2342        delete fUndeclaredAttrRegistry;
2343}
2344
2345
2346//  This method is called from scanStartTagNS() to build up the list of
2347//  XMLAttr objects that will be passed out in the start tag callout. We
2348//  get the key/value pairs from the raw scan of explicitly provided attrs,
2349//  which have not been normalized. And we get the element declaration from
2350//  which we will get any defaulted or fixed attribute defs and add those
2351//  in as well.
2352XMLSize_t
2353DGXMLScanner::buildAttList(const XMLSize_t              attCount
2354                                                  ,       XMLElementDecl*       elemDecl
2355                                                  ,       RefVectorOf<XMLAttr>& toFill)
2356{
2357#ifdef DGXML_SCANNER_DEPRECATED
2358        DEPRECATED_FEATURE_IN_ICXML;
2359#else
2360        //  Ask the element to clear the 'provided' flag on all of the att defs
2361        //  that it owns, and to return us a boolean indicating whether it has
2362        //  any defs.
2363        const bool hasDefs = elemDecl->hasAttDefs();
2364
2365        //  If there are no expliclitily provided attributes and there are no
2366        //  defined attributes for the element, the we don't have anything to do.
2367        //  So just return zero in this case.
2368        if (!hasDefs && !attCount)
2369                return 0;
2370
2371        // Keep up with how many attrs we end up with total
2372        XMLSize_t retCount = attCount;
2373
2374        //  And get the current size of the output vector. This lets us use
2375        //  existing elements until we fill it, then start adding new ones.
2376        const XMLSize_t curAttListSize = toFill.size();
2377
2378        //  Ok, so lets get an enumerator for the attributes of this element
2379        //  and run through them for well formedness and validity checks. But
2380        //  make sure that we had any attributes before we do it, since the list
2381        //  would have have gotten faulted in anyway.
2382        if (hasDefs)
2383        {
2384                XMLAttDefList& attDefList = elemDecl->getAttDefList();
2385                for(XMLSize_t i=0; i<attDefList.getAttDefCount(); i++)
2386                {
2387                        // Get the current att def, for convenience and its def type
2388                        XMLAttDef& curDef = attDefList.getAttDef(i);
2389
2390                        unsigned int *attCountPtr = fAttDefRegistry->get(&curDef);
2391                        if (!attCountPtr || *attCountPtr < fElemCount)
2392                        { // did not occur
2393                                const XMLAttDef::DefAttTypes defType = curDef.getDefaultType();
2394
2395                                if (fValidate)
2396                                {
2397                                        // If we are validating and its required, then an error
2398                                        if (defType == XMLAttDef::Required)
2399                                        {
2400                                                fValidator->emitError
2401                                                (
2402                                                        XMLValid::RequiredAttrNotProvided
2403                                                        , curDef.getFullName()
2404                                                );
2405                                        }
2406                                        else if ((defType == XMLAttDef::Default) ||
2407                                                                           (defType == XMLAttDef::Fixed)  )
2408                                        {
2409                                                if (fStandalone && curDef.isExternal())
2410                                                {
2411                                                        // XML 1.0 Section 2.9
2412                                                        // Document is standalone, so attributes must not be defaulted.
2413                                                        fValidator->emitError(XMLValid::NoDefAttForStandalone, curDef.getFullName(), elemDecl->getFullName());
2414                                                }
2415                                        }
2416                                }
2417
2418                                // Fault in the value if needed, and bump the att count
2419                                if ((defType == XMLAttDef::Default)
2420                                ||  (defType == XMLAttDef::Fixed))
2421                                {
2422                                        // Let the validator pass judgement on the attribute value
2423                                        if (fValidate)
2424                                        {
2425                                                fValidator->validateAttrValue
2426                                                (
2427                                                        &curDef
2428                                                        , curDef.getValue()
2429                                                        , false
2430                                                        , elemDecl
2431                                                );
2432                                        }
2433
2434                                        XMLAttr* curAtt;
2435                                        if (retCount >= curAttListSize)
2436                                        {
2437                                                if (fDoNamespaces)
2438                                                {
2439                                                        curAtt = new (fMemoryManager) XMLAttr
2440                                                        (
2441                                                                #ifdef TEST_NAMESPACE_RESOLVER
2442                                                                XMLNamespaceResolver::fEmptyUriId
2443                                                                #else
2444                                                                fEmptyNamespaceId
2445                                                                #endif
2446                                                                , curDef.getFullName()
2447                                                                , curDef.getValue()
2448                                                                , curDef.getType()
2449                                                                , false
2450                                                                , fMemoryManager
2451                                                        );
2452                                                }
2453                                                else
2454                                                {
2455                                                        curAtt = new (fMemoryManager) XMLAttr
2456                                                        (
2457                                                                0
2458                                                                , curDef.getFullName()
2459                                                                , XMLUni::fgZeroLenString
2460                                                                , curDef.getValue()
2461                                                                , curDef.getType()
2462                                                                , false
2463                                                                , fMemoryManager
2464                                                        );
2465                                                }
2466
2467                                                fAttrList.addElement(curAtt);
2468                                        }
2469                                        else
2470                                        {
2471                                                curAtt = fAttrList.elementAt(retCount);
2472                                                if (fDoNamespaces)
2473                                                {
2474                                                        curAtt->set
2475                                                        (
2476                                                                #ifdef TEST_NAMESPACE_RESOLVER
2477                                                                XMLNamespaceResolver::fEmptyUriId
2478                                                                #else
2479                                                                fEmptyNamespaceId
2480                                                                #endif
2481                                                                , curDef.getFullName()
2482                                                                , curDef.getValue()
2483                                                                , curDef.getType()
2484                                                        );
2485                                                }
2486                                                else
2487                                                {
2488                                                        curAtt->set
2489                                                        (
2490                                                                0
2491                                                                , curDef.getFullName()
2492                                                                , XMLUni::fgZeroLenString
2493                                                                , curDef.getValue()
2494                                                                , curDef.getType()
2495                                                        );
2496                                                }
2497                                                curAtt->setSpecified(false);
2498                                        }
2499
2500                                        if (fDoNamespaces)
2501                                        {
2502                                                //  Map the new attribute's prefix to a URI id and store
2503                                                //  that in the attribute object.
2504                                                const XMLCh* attPrefix = curAtt->getPrefix();
2505                                                if (attPrefix && *attPrefix) {
2506                                                        curAtt->setURIId
2507                                                        (
2508                                                                resolvePrefix(attPrefix, ElemStack::Mode_Attribute)
2509                                                        );
2510                                                }
2511                                        }
2512
2513                                        retCount++;
2514                                }
2515                        }
2516                }
2517        }
2518
2519        return retCount;
2520#endif
2521}
2522
2523
2524//  This method will reset the scanner data structures, and related plugged
2525//  in stuff, for a new scan session. We get the input source for the primary
2526//  XML entity, create the reader for it, and push it on the stack so that
2527//  upon successful return from here we are ready to go.
2528void DGXMLScanner::scanReset(const InputSource& src)
2529{
2530#ifdef DGXML_SCANNER_DEPRECATED
2531        DEPRECATED_FEATURE_IN_ICXML;
2532#else
2533        //  This call implicitly tells us that we are going to reuse the scanner
2534        //  if it was previously used. So tell the validator to reset itself.
2535        //
2536        //  But, if the fUseCacheGrammar flag is set, then don't reset it.
2537        //
2538        //  NOTE:   The ReaderMgr is flushed on the way out, because that is
2539        //          required to insure that files are closed.
2540        fGrammarResolver->cacheGrammarFromParse(fToCacheGrammar);
2541        fGrammarResolver->useCachedGrammarInParse(fUseCachedGrammar);
2542
2543        fDTDGrammar = new (fGrammarPoolMemoryManager) DTDGrammar(fGrammarPoolMemoryManager);
2544        fGrammarResolver->putGrammar(fDTDGrammar);
2545        fGrammar = fDTDGrammar;
2546        fRootGrammar = 0;
2547        fValidator->setGrammar(fGrammar);
2548
2549        // Reset validation
2550        fValidate = (fValScheme == Val_Always) ? true : false;
2551
2552        //  And for all installed handlers, send reset events. This gives them
2553        //  a chance to flush any cached data.
2554        if (fDocHandler)
2555                fDocHandler->resetDocument();
2556        if (fEntityHandler)
2557                fEntityHandler->resetEntities();
2558        if (fErrorReporter)
2559                fErrorReporter->resetErrors();
2560
2561        // Clear out the id reference list
2562        resetValidationContext();
2563
2564        // Reset the Root Element Name
2565        fRootElemName = 0;
2566
2567#ifndef TEST_NAMESPACE_RESOLVER
2568        //  Reset the element stack, and give it the latest ids for the special
2569        //  URIs it has to know about.
2570        fElemStack.reset
2571        (
2572                fEmptyNamespaceId
2573                , fUnknownNamespaceId
2574                , fXMLNamespaceId
2575                , fXMLNSNamespaceId
2576        );
2577#endif
2578
2579        // Reset some status flags
2580        fInException = false;
2581        fStandalone = false;
2582        fErrorCount = 0;
2583        fHasNoDTD = true;
2584
2585        // Reset the validators
2586        fDTDValidator->reset();
2587        fDTDValidator->setErrorReporter(fErrorReporter);
2588        if (fValidatorFromUser)
2589                fValidator->reset();
2590
2591        //  Handle the creation of the XML reader object for this input source.
2592        //  This will provide us with transcoding and basic lexing services.
2593        XMLReader* newReader = fReaderMgr.createReader
2594        (
2595                src
2596                , true
2597                , XMLReader::RefFrom_NonLiteral
2598                , XMLReader::Type_General
2599                , XMLReader::Source_External
2600                , fCalculateSrcOfs
2601                , fLowWaterMark
2602        );
2603
2604        if (!newReader)
2605        {
2606                if (src.getIssueFatalErrorIfNotFound())
2607                        ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource, src.getSystemId(), fMemoryManager);
2608                else
2609                        ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource_Warning, src.getSystemId(), fMemoryManager);
2610        }
2611
2612        // Push this read onto the reader manager
2613        fReaderMgr.pushReader(newReader, 0);
2614
2615        // and reset security-related things if necessary:
2616        if(fSecurityManager != 0)
2617        {
2618                fEntityExpansionLimit = fSecurityManager->getEntityExpansionLimit();
2619                fEntityExpansionCount = 0;
2620        }
2621        fUndeclaredAttrRegistry->removeAll();
2622        fAttrNSList->removeAllElements();
2623#endif
2624}
2625
2626
2627//  This method is called between markup in content. It scans for character
2628//  data that is sent to the document handler. It watches for any markup
2629//  characters that would indicate that the character data has ended. It also
2630//  handles expansion of general and character entities.
2631//
2632//  sendData() is a local static helper for this method which handles some
2633//  code that must be done in three different places here.
2634void DGXMLScanner::sendCharData(XMLBuffer& toSend)
2635{
2636#ifdef DGXML_SCANNER_DEPRECATED
2637        DEPRECATED_FEATURE_IN_ICXML;
2638#else
2639        // If no data in the buffer, then nothing to do
2640        if (toSend.isEmpty())
2641                return;
2642
2643        //  We do different things according to whether we are validating or
2644        //  not. If not, its always just characters; else, it depends on the
2645        //  current element's content model.
2646        if (fValidate)
2647        {
2648                // Get the raw data we need for the callback
2649                const XMLCh* const rawBuf = toSend.getRawBuffer();
2650                const XMLSize_t len = toSend.getLen();
2651
2652                // And see if the current element is a 'Children' style content model
2653                const ElemStack::StackElem* topElem = fElemStack.topElement();
2654
2655                // Get the character data opts for the current element
2656                XMLElementDecl::CharDataOpts charOpts = topElem->fThisElement->getCharDataOpts();
2657
2658                if (charOpts == XMLElementDecl::NoCharData)
2659                {
2660                        // They definitely cannot handle any type of char data
2661                        fValidator->emitError(XMLValid::NoCharDataInCM);
2662                }
2663                else if (fReaderMgr.getCurrentReader()->isAllSpaces(rawBuf, len))
2664                {
2665                        //  Its all spaces. So, if they can take spaces, then send it
2666                        //  as ignorable whitespace. If they can handle any char data
2667                        //  send it as characters.
2668                        if (charOpts == XMLElementDecl::SpacesOk) {
2669                                if (fDocHandler)
2670                                        fDocHandler->ignorableWhitespace(rawBuf, len, false);
2671                        }
2672                        else if (charOpts == XMLElementDecl::AllCharData)
2673                        {
2674                                if (fDocHandler)
2675                                        fDocHandler->docCharacters(rawBuf, len, false);
2676                        }
2677                }
2678                else
2679                {
2680                        //  If they can take any char data, then send it. Otherwise, they
2681                        //  can only handle whitespace and can't handle this stuff so
2682                        //  issue an error.
2683                        if (charOpts == XMLElementDecl::AllCharData)
2684                        {
2685                                if (fDocHandler)
2686                                        fDocHandler->docCharacters(rawBuf, len, false);
2687                        }
2688                        else
2689                        {
2690                                fValidator->emitError(XMLValid::NoCharDataInCM);
2691                        }
2692                }
2693        }
2694        else
2695        {
2696                // Always assume its just char data if not validating
2697                if (fDocHandler)
2698                        fDocHandler->docCharacters(toSend.getRawBuffer(), toSend.getLen(), false);
2699        }
2700
2701        // Reset buffer
2702        toSend.reset();
2703#endif
2704}
2705
2706
2707
2708//  This method is called with a key/value string pair that represents an
2709//  xmlns="yyy" or xmlns:xxx="yyy" attribute. This method will update the
2710//  current top of the element stack based on this data. We know that when
2711//  we get here, that it is one of these forms, so we don't bother confirming
2712//  it.
2713//
2714//  But we have to ensure
2715//      1. xxx is not xmlns
2716//      2. if xxx is xml, then yyy must match XMLUni::fgXMLURIName, and vice versa
2717//      3. yyy is not XMLUni::fgXMLNSURIName
2718//      4. if xxx is not null, then yyy cannot be an empty string.
2719void DGXMLScanner::updateNSMap(const    XMLCh* const attrPrefix
2720                                                           , const  XMLCh* const attrLocalName
2721                                                           , const  XMLCh* const attrValue)
2722{
2723        DEPRECATED_FEATURE_IN_ICXML;
2724}
2725
2726void DGXMLScanner::scanAttrListforNameSpaces(RefVectorOf<XMLAttr>* theAttrList, XMLSize_t attCount,
2727                                                                                                XMLElementDecl*       elemDecl)
2728{
2729        DEPRECATED_FEATURE_IN_ICXML;
2730}
2731
2732InputSource* DGXMLScanner::resolveSystemId(const XMLCh* const sysId
2733                                                                                  ,const XMLCh* const pubId)
2734{
2735#ifdef DGXML_SCANNER_DEPRECATED
2736        DEPRECATED_FEATURE_IN_ICXML;
2737#else
2738        //Normalize sysId
2739        XMLBufBid nnSys(&fBufMgr);
2740        XMLBuffer& normalizedSysId = nnSys.getBuffer();
2741        XMLString::removeChar(sysId, 0xFFFF, normalizedSysId);
2742        const XMLCh* normalizedURI = normalizedSysId.getRawBuffer();
2743
2744        // Create a buffer for expanding the normalized system id
2745        XMLBufBid bbSys(&fBufMgr);
2746        XMLBuffer& expSysId = bbSys.getBuffer();
2747
2748        //  Allow the entity handler to expand the system id if they choose
2749        //  to do so.
2750        InputSource* srcToFill = 0;
2751        if (fEntityHandler)
2752        {
2753                if (!fEntityHandler->expandSystemId(normalizedURI, expSysId))
2754                        expSysId.set(normalizedURI);
2755
2756                ReaderMgr::LastExtEntityInfo lastInfo;
2757                fReaderMgr.getLastExtEntityInfo(lastInfo);
2758                XMLResourceIdentifier resourceIdentifier(XMLResourceIdentifier::ExternalEntity,
2759                                                        expSysId.getRawBuffer(), 0, pubId, lastInfo.systemId,
2760                                                        &fReaderMgr);
2761                srcToFill = fEntityHandler->resolveEntity(&resourceIdentifier);
2762        }
2763        else
2764        {
2765                expSysId.set(normalizedURI);
2766        }
2767
2768        //  If they didn't create a source via the entity handler, then we
2769        //  have to create one on our own.
2770        if (!srcToFill)
2771        {
2772                if (fDisableDefaultEntityResolution)
2773                        return srcToFill;
2774
2775                ReaderMgr::LastExtEntityInfo lastInfo;
2776                fReaderMgr.getLastExtEntityInfo(lastInfo);
2777
2778                XMLURL urlTmp(fMemoryManager);
2779                if ((!urlTmp.setURL(lastInfo.systemId, expSysId.getRawBuffer(), urlTmp)) ||
2780                        (urlTmp.isRelative()))
2781                {
2782                        if (!fStandardUriConformant)
2783                        {
2784                                XMLBufBid  ddSys(&fBufMgr);
2785                                XMLBuffer& resolvedSysId = ddSys.getBuffer();
2786                                XMLUri::normalizeURI(expSysId.getRawBuffer(), resolvedSysId);
2787
2788                                srcToFill = new (fMemoryManager) LocalFileInputSource
2789                                (
2790                                        lastInfo.systemId
2791                                        , resolvedSysId.getRawBuffer()
2792                                        , fMemoryManager
2793                                );
2794                        }
2795                        else
2796                                ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);
2797                }
2798                else
2799                {
2800                        if (fStandardUriConformant && urlTmp.hasInvalidChar())
2801                                ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);
2802                        srcToFill = new (fMemoryManager) URLInputSource(urlTmp, fMemoryManager);
2803                }
2804        }
2805
2806        return srcToFill;
2807#endif
2808}
2809
2810// ---------------------------------------------------------------------------
2811//  DGXMLScanner: Private parsing methods
2812// ---------------------------------------------------------------------------
2813bool DGXMLScanner::scanAttValue(  const   XMLAttDef* const    attDef
2814                                                                  , const XMLCh *const attrName
2815                                                                  ,       XMLBuffer&          toFill)
2816{
2817#ifdef DGXML_SCANNER_DEPRECATED
2818        DEPRECATED_FEATURE_IN_ICXML;
2819#else
2820
2821        enum States
2822        {
2823                InWhitespace
2824                , InContent
2825        };
2826
2827        // Get the type and name
2828        const XMLAttDef::AttTypes type = (attDef)
2829                                                ?attDef->getType()
2830                                                :XMLAttDef::CData;
2831
2832        // Reset the target buffer
2833        toFill.reset();
2834
2835        // Get the next char which must be a single or double quote
2836        XMLCh quoteCh;
2837        if (!fReaderMgr.skipIfQuote(quoteCh))
2838                return false;
2839
2840        //  We have to get the current reader because we have to ignore closing
2841        //  quotes until we hit the same reader again.
2842        const XMLSize_t curReader = fReaderMgr.getCurrentReaderNum();
2843
2844        // Get attribute def - to check to see if it's declared externally or not
2845        bool  isAttExternal = (attDef)
2846                                                ?attDef->isExternal()
2847                                                :false;
2848
2849        //  Loop until we get the attribute value. Note that we use a double
2850        //  loop here to avoid the setup/teardown overhead of the exception
2851        //  handler on every round.
2852        XMLCh   nextCh;
2853        XMLCh   secondCh = 0;
2854        States  curState = InContent;
2855        bool    firstNonWS = false;
2856        bool    gotLeadingSurrogate = false;
2857        bool    escaped;
2858        while (true)
2859        {
2860        try
2861        {
2862                while(true)
2863                {
2864                        nextCh = fReaderMgr.getNextChar();
2865
2866                        if (!nextCh)
2867                                ThrowXMLwithMemMgr(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF, fMemoryManager);
2868
2869                        // Check for our ending quote in the same entity
2870                        if (nextCh == quoteCh)
2871                        {
2872                                if (curReader == fReaderMgr.getCurrentReaderNum())
2873                                        return true;
2874
2875                                // Watch for spillover into a previous entity
2876                                if (curReader > fReaderMgr.getCurrentReaderNum())
2877                                {
2878                                        emitError(XMLErrs::PartialMarkupInEntity);
2879                                        return false;
2880                                }
2881                        }
2882
2883                        //  Check for an entity ref now, before we let it affect our
2884                        //  whitespace normalization logic below. We ignore the empty flag
2885                        //  in this one.
2886                        escaped = false;
2887                        if (nextCh == chAmpersand)
2888                        {
2889                                if (scanEntityRef(true, nextCh, secondCh, escaped) != EntityExp_Returned)
2890                                {
2891                                        gotLeadingSurrogate = false;
2892                                        continue;
2893                                }
2894                        }
2895                        else if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
2896                        {
2897                                // Deal with surrogate pairs
2898                                //  Its a leading surrogate. If we already got one, then
2899                                //  issue an error, else set leading flag to make sure that
2900                                //  we look for a trailing next time.
2901                                if (gotLeadingSurrogate)
2902                                        emitError(XMLErrs::Expected2ndSurrogateChar);
2903                                else
2904                                        gotLeadingSurrogate = true;
2905                        }
2906                        else
2907                        {
2908                                //  If its a trailing surrogate, make sure that we are
2909                                //  prepared for that. Else, its just a regular char so make
2910                                //  sure that we were not expected a trailing surrogate.
2911                                if ((nextCh >= 0xDC00) && (nextCh <= 0xDFFF))
2912                                {
2913                                        // Its trailing, so make sure we were expecting it
2914                                        if (!gotLeadingSurrogate)
2915                                                emitError(XMLErrs::Unexpected2ndSurrogateChar);
2916                                }
2917                                else
2918                                {
2919                                        //  Its just a char, so make sure we were not expecting a
2920                                        //  trailing surrogate.
2921                                        if (gotLeadingSurrogate)
2922                                                emitError(XMLErrs::Expected2ndSurrogateChar);
2923
2924                                        // Its got to at least be a valid XML character
2925                                        if (!fReaderMgr.getCurrentReader()->isXMLChar(nextCh))
2926                                        {
2927                                                XMLCh tmpBuf[9];
2928                                                XMLString::binToText
2929                                                (
2930                                                        nextCh
2931                                                        , tmpBuf
2932                                                        , 8
2933                                                        , 16
2934                                                        , fMemoryManager
2935                                                );
2936                                                emitError(XMLErrs::InvalidCharacterInAttrValue, attrName, tmpBuf);
2937                                        }
2938                                }
2939                                gotLeadingSurrogate = false;
2940                        }
2941
2942                        //  If its not escaped, then make sure its not a < character, which
2943                        //  is not allowed in attribute values.
2944                        if (!escaped && (nextCh == chOpenAngle))
2945                                emitError(XMLErrs::BracketInAttrValue, attrName);
2946
2947                        //  If the attribute is a CDATA type we do simple replacement of
2948                        //  tabs and new lines with spaces, if the character is not escaped
2949                        //  by way of a char ref.
2950                        //
2951                        //  Otherwise, we do the standard non-CDATA normalization of
2952                        //  compressing whitespace to single spaces and getting rid of leading
2953                        //  and trailing whitespace.
2954                        if (type == XMLAttDef::CData)
2955                        {
2956                                if (!escaped)
2957                                {
2958                                        if ((nextCh == 0x09) || (nextCh == 0x0A) || (nextCh == 0x0D))
2959                                        {
2960                                                // Check Validity Constraint for Standalone document declaration
2961                                                // XML 1.0, Section 2.9
2962                                                if (fStandalone && fValidate && isAttExternal)
2963                                                {
2964                                                         // Can't have a standalone document declaration of "yes" if  attribute
2965                                                         // values are subject to normalisation
2966                                                         fValidator->emitError(XMLValid::NoAttNormForStandalone, attrName);
2967                                                }
2968                                                nextCh = chSpace;
2969                                        }
2970                                }
2971                        }
2972                        else
2973                        {
2974                                if (curState == InWhitespace)
2975                                {
2976                                        if ((escaped && nextCh != chSpace) || !fReaderMgr.getCurrentReader()->isWhitespace(nextCh))
2977                                        {
2978                                                if (firstNonWS)
2979                                                        toFill.append(chSpace);
2980                                                curState = InContent;
2981                                                firstNonWS = true;
2982                                        }
2983                                        else
2984                                        {
2985                                                continue;
2986                                        }
2987                                }
2988                                else if (curState == InContent)
2989                                {
2990                                        if ((nextCh == chSpace) ||
2991                                                (fReaderMgr.getCurrentReader()->isWhitespace(nextCh) && !escaped))
2992                                        {
2993                                                curState = InWhitespace;
2994
2995                                                // Check Validity Constraint for Standalone document declaration
2996                                                // XML 1.0, Section 2.9
2997                                                if (fStandalone && fValidate && isAttExternal)
2998                                                {
2999                                                        if (!firstNonWS || (nextCh != chSpace) || (fReaderMgr.lookingAtSpace()))
3000                                                        {
3001                                                                 // Can't have a standalone document declaration of "yes" if  attribute
3002                                                                 // values are subject to normalisation
3003                                                                 fValidator->emitError(XMLValid::NoAttNormForStandalone, attrName);
3004                                                        }
3005                                                }
3006                                                continue;
3007                                        }
3008                                        firstNonWS = true;
3009                                }
3010                        }
3011
3012                        // Else add it to the buffer
3013                        toFill.append(nextCh);
3014
3015                        if (secondCh)
3016                        {
3017                                toFill.append(secondCh);
3018                                secondCh=0;
3019                        }
3020                }
3021        }
3022        catch(const EndOfEntityException&)
3023        {
3024                // Just eat it and continue.
3025                gotLeadingSurrogate = false;
3026                escaped = false;
3027        }
3028        }
3029        return true;
3030#endif
3031}
3032
3033
3034//  This method scans a CDATA section. It collects the character into one
3035//  of the temp buffers and calls the document handler, if any, with the
3036//  characters. It assumes that the <![CDATA string has been scanned before
3037//  this call.
3038void DGXMLScanner::scanCDSection()
3039{
3040#ifdef DGXML_SCANNER_DEPRECATED
3041        DEPRECATED_FEATURE_IN_ICXML;
3042#else
3043        static const XMLCh CDataClose[] =
3044        {
3045                        chCloseSquare, chCloseAngle, chNull
3046        };
3047
3048        //  The next character should be the opening square bracket. If not
3049        //  issue an error, but then try to recover by skipping any whitespace
3050        //  and checking again.
3051        if (!fReaderMgr.skippedChar(chOpenSquare))
3052        {
3053                emitError(XMLErrs::ExpectedOpenSquareBracket);
3054                fReaderMgr.skipPastSpaces();
3055
3056                // If we still don't find it, then give up, else keep going
3057                if (!fReaderMgr.skippedChar(chOpenSquare))
3058                        return;
3059        }
3060
3061        // Get a buffer for this
3062        XMLBufBid bbCData(&fBufMgr);
3063
3064        //  We just scan forward until we hit the end of CDATA section sequence.
3065        //  CDATA is effectively a big escape mechanism so we don't treat markup
3066        //  characters specially here.
3067        bool            emittedError = false;
3068        bool     gotLeadingSurrogate = false;
3069
3070        // Get the character data opts for the current element
3071        const ElemStack::StackElem* topElem = fElemStack.topElement();
3072        XMLElementDecl::CharDataOpts charOpts =  topElem->fThisElement->getCharDataOpts();
3073
3074        while (true)
3075        {
3076                const XMLCh nextCh = fReaderMgr.getNextChar();
3077
3078                // Watch for unexpected end of file
3079                if (!nextCh)
3080                {
3081                        emitError(XMLErrs::UnterminatedCDATASection);
3082                        ThrowXMLwithMemMgr(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF, fMemoryManager);
3083                }
3084
3085                if (fValidate && fStandalone && (fReaderMgr.getCurrentReader()->isWhitespace(nextCh)))
3086                {
3087                        // This document is standalone; this ignorable CDATA whitespace is forbidden.
3088                        // XML 1.0, Section 2.9
3089                        // And see if the current element is a 'Children' style content model
3090                        if (topElem->fThisElement->isExternal()) {
3091
3092                                if (charOpts == XMLElementDecl::SpacesOk) // Element Content
3093                                {
3094                                        // Error - standalone should have a value of "no" as whitespace detected in an
3095                                        // element type with element content whose element declaration was external
3096                                        fValidator->emitError(XMLValid::NoWSForStandalone);
3097                                }
3098                        }
3099                }
3100
3101                //  If this is a close square bracket it could be our closing
3102                //  sequence.
3103                if (nextCh == chCloseSquare && fReaderMgr.skippedString(CDataClose))
3104                {
3105                        //  make sure we were not expecting a trailing surrogate.
3106                        if (gotLeadingSurrogate)
3107                                emitError(XMLErrs::Expected2ndSurrogateChar);
3108
3109                        if (fValidate) {
3110
3111                                if (charOpts != XMLElementDecl::AllCharData)
3112                                {
3113                                        // They definitely cannot handle any type of char data
3114                                        fValidator->emitError(XMLValid::NoCharDataInCM);
3115                                }
3116                        }
3117
3118                        // If we have a doc handler, call it
3119                        if (fDocHandler)
3120                        {
3121                                fDocHandler->docCharacters
3122                                        (
3123                                        bbCData.getRawBuffer()
3124                                        , bbCData.getLen()
3125                                        , true
3126                                        );
3127                        }
3128
3129                        // And we are done
3130                        break;
3131                }
3132
3133                //  Make sure its a valid character. But if we've emitted an error
3134                //  already, don't bother with the overhead since we've already told
3135                //  them about it.
3136                if (!emittedError)
3137                {
3138                        // Deal with surrogate pairs
3139                        if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
3140                        {
3141                                //  Its a leading surrogate. If we already got one, then
3142                                //  issue an error, else set leading flag to make sure that
3143                                //  we look for a trailing next time.
3144                                if (gotLeadingSurrogate)
3145                                        emitError(XMLErrs::Expected2ndSurrogateChar);
3146                                else
3147                                        gotLeadingSurrogate = true;
3148                        }
3149                        else
3150                        {
3151                                //  If its a trailing surrogate, make sure that we are
3152                                //  prepared for that. Else, its just a regular char so make
3153                                //  sure that we were not expected a trailing surrogate.
3154                                if ((nextCh >= 0xDC00) && (nextCh <= 0xDFFF))
3155                                {
3156                                        // Its trailing, so make sure we were expecting it
3157                                        if (!gotLeadingSurrogate)
3158                                                emitError(XMLErrs::Unexpected2ndSurrogateChar);
3159                                }
3160                                else
3161                                {
3162                                        //  Its just a char, so make sure we were not expecting a
3163                                        //  trailing surrogate.
3164                                        if (gotLeadingSurrogate)
3165                                                emitError(XMLErrs::Expected2ndSurrogateChar);
3166
3167                                        // Its got to at least be a valid XML character
3168                                        else if (!fReaderMgr.getCurrentReader()->isXMLChar(nextCh))
3169                                        {
3170                                                XMLCh tmpBuf[9];
3171                                                XMLString::binToText
3172                                                (
3173                                                        nextCh
3174                                                        , tmpBuf
3175                                                        , 8
3176                                                        , 16
3177                                                        , fMemoryManager
3178                                                );
3179                                                emitError(XMLErrs::InvalidCharacter, tmpBuf);
3180                                                emittedError = true;
3181                                        }
3182                                }
3183                                gotLeadingSurrogate = false;
3184                        }
3185                }
3186
3187                // Add it to the buffer
3188                bbCData.append(nextCh);
3189        }
3190#endif
3191}
3192
3193
3194void DGXMLScanner::scanCharData(XMLBuffer& toUse)
3195{
3196#ifdef DGXML_SCANNER_DEPRECATED
3197        DEPRECATED_FEATURE_IN_ICXML;
3198#else
3199        //  We have to watch for the stupid ]]> sequence, which is illegal in
3200        //  character data. So this is a little state machine that handles that.
3201        enum States
3202        {
3203                State_Waiting
3204                , State_GotOne
3205                , State_GotTwo
3206        };
3207
3208        // Reset the buffer before we start
3209        toUse.reset();
3210
3211        // Turn on the 'throw at end' flag of the reader manager
3212        ThrowEOEJanitor jan(&fReaderMgr, true);
3213
3214        //  In order to be more efficient we have to use kind of a deeply nested
3215        //  set of blocks here. The outer block puts on a try and catches end of
3216        //  entity exceptions. The inner loop is the per-character loop. If we
3217        //  put the try inside the inner loop, it would work but would require
3218        //  the exception handling code setup/teardown code to be invoked for
3219        //  each character.
3220        XMLCh   nextCh;
3221        XMLCh   secondCh = 0;
3222        States  curState = State_Waiting;
3223        bool    escaped = false;
3224        bool    gotLeadingSurrogate = false;
3225        bool    notDone = true;
3226        while (notDone)
3227        {
3228                try
3229                {
3230                        while (true)
3231                        {
3232                                //  Eat through as many plain content characters as possible without
3233                                //  needing special handling.  Moving most content characters here,
3234                                //  in this one call, rather than running the overall loop once
3235                                //  per content character, is a speed optimization.
3236                                if (curState == State_Waiting  &&  !gotLeadingSurrogate)
3237                                {
3238                                         fReaderMgr.movePlainContentChars(toUse);
3239                                }
3240
3241                                // Try to get another char from the source
3242                                //   The code from here on down covers all contengencies,
3243                                if (!fReaderMgr.getNextCharIfNot(chOpenAngle, nextCh))
3244                                {
3245                                        // If we were waiting for a trailing surrogate, its an error
3246                                        if (gotLeadingSurrogate)
3247                                                emitError(XMLErrs::Expected2ndSurrogateChar);
3248
3249                                        notDone = false;
3250                                        break;
3251                                }
3252
3253                                //  Watch for a reference. Note that the escapement mechanism
3254                                //  is ignored in this content.
3255                                escaped = false;
3256                                if (nextCh == chAmpersand)
3257                                {
3258                                        sendCharData(toUse);
3259
3260                                        // Turn off the throwing at the end of entity during this
3261                                        ThrowEOEJanitor jan(&fReaderMgr, false);
3262
3263                                        if (scanEntityRef(false, nextCh, secondCh, escaped) != EntityExp_Returned)
3264                                        {
3265                                                gotLeadingSurrogate = false;
3266                                                continue;
3267                                        }
3268#if 0
3269                                        else
3270                                        {
3271                                                if (escaped && !fElemStack.isEmpty())
3272                                                        fElemStack.setReferenceEscaped();
3273                                        }
3274#endif
3275                                }
3276                                else if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
3277                                {
3278                                        // Deal with surrogate pairs
3279                                        //  Its a leading surrogate. If we already got one, then
3280                                        //  issue an error, else set leading flag to make sure that
3281                                        //  we look for a trailing next time.
3282                                        if (gotLeadingSurrogate)
3283                                                emitError(XMLErrs::Expected2ndSurrogateChar);
3284                                        else
3285                                                gotLeadingSurrogate = true;
3286                                }
3287                                else
3288                                {
3289                                        //  If its a trailing surrogate, make sure that we are
3290                                        //  prepared for that. Else, its just a regular char so make
3291                                        //  sure that we were not expected a trailing surrogate.
3292                                        if ((nextCh >= 0xDC00) && (nextCh <= 0xDFFF))
3293                                        {
3294                                                // Its trailing, so make sure we were expecting it
3295                                                if (!gotLeadingSurrogate)
3296                                                        emitError(XMLErrs::Unexpected2ndSurrogateChar);
3297                                        }
3298                                        else
3299                                        {
3300                                                //  Its just a char, so make sure we were not expecting a
3301                                                //  trailing surrogate.
3302                                                if (gotLeadingSurrogate)
3303                                                        emitError(XMLErrs::Expected2ndSurrogateChar);
3304
3305                                                // Make sure the returned char is a valid XML char
3306                                                if (!fReaderMgr.getCurrentReader()->isXMLChar(nextCh))
3307                                                {
3308                                                        XMLCh tmpBuf[9];
3309                                                        XMLString::binToText
3310                                                        (
3311                                                                nextCh
3312                                                                , tmpBuf
3313                                                                , 8
3314                                                                , 16
3315                                                                , fMemoryManager
3316                                                        );
3317                                                        emitError(XMLErrs::InvalidCharacter, tmpBuf);
3318                                                }
3319                                        }
3320                                        gotLeadingSurrogate = false;
3321                                }
3322
3323                                 // Keep the state machine up to date
3324                                if (!escaped)
3325                                {
3326                                        if (nextCh == chCloseSquare)
3327                                        {
3328                                                if (curState == State_Waiting)
3329                                                        curState = State_GotOne;
3330                                                else if (curState == State_GotOne)
3331                                                        curState = State_GotTwo;
3332                                        }
3333                                        else if (nextCh == chCloseAngle)
3334                                        {
3335                                                if (curState == State_GotTwo)
3336                                                        emitError(XMLErrs::BadSequenceInCharData);
3337                                                curState = State_Waiting;
3338                                        }
3339                                        else
3340                                        {
3341                                                curState = State_Waiting;
3342                                        }
3343                                }
3344                                else
3345                                {
3346                                        curState = State_Waiting;
3347                                }
3348
3349                                // Add this char to the buffer
3350                                toUse.append(nextCh);
3351
3352                                if (secondCh)
3353                                {
3354                                        toUse.append(secondCh);
3355                                        secondCh=0;
3356                                }
3357                        }
3358                }
3359                catch(const EndOfEntityException& toCatch)
3360                {
3361                        //  Some entity ended, so we have to send any accumulated
3362                        //  chars and send an end of entity event.
3363                        sendCharData(toUse);
3364                        gotLeadingSurrogate = false;
3365
3366                        if (fDocHandler)
3367                                fDocHandler->endEntityReference(toCatch.getEntity());
3368                }
3369        }
3370
3371        // Check the validity constraints as per XML 1.0 Section 2.9
3372        if (fValidate && fStandalone)
3373        {
3374                // See if the text contains whitespace
3375                // Get the raw data we need for the callback
3376                const XMLCh* rawBuf = toUse.getRawBuffer();
3377                const XMLSize_t len = toUse.getLen();
3378                const bool isSpaces = fReaderMgr.getCurrentReader()->containsWhiteSpace(rawBuf, len);
3379
3380                if (isSpaces)
3381                {
3382                        // And see if the current element is a 'Children' style content model
3383                        const ElemStack::StackElem* topElem = fElemStack.topElement();
3384
3385                        if (topElem->fThisElement->isExternal()) {
3386
3387                                // Get the character data opts for the current element
3388                                XMLElementDecl::CharDataOpts charOpts =  topElem->fThisElement->getCharDataOpts();
3389
3390                                if (charOpts == XMLElementDecl::SpacesOk)  // => Element Content
3391                                {
3392                                        // Error - standalone should have a value of "no" as whitespace detected in an
3393                                        // element type with element content whose element declaration was external
3394                                        //
3395                                        fValidator->emitError(XMLValid::NoWSForStandalone);
3396                                }
3397                        }
3398                }
3399        }
3400        // Send any char data that we accumulated into the buffer
3401        sendCharData(toUse);
3402#endif
3403}
3404
3405
3406//  This method will scan a general/character entity ref. It will either
3407//  expand a char ref and return it directly, or push a reader for a general
3408//  entity.
3409//
3410//  The return value indicates whether the char parameters hold the value
3411//  or whether the value was pushed as a reader, or that it failed.
3412//
3413//  The escaped flag tells the caller whether the returned parameter resulted
3414//  from a character reference, which escapes the character in some cases. It
3415//  only makes any difference if the return value indicates the value was
3416//  returned directly.
3417DGXMLScanner::EntityExpRes
3418DGXMLScanner::scanEntityRef(  const   bool    inAttVal
3419                                                        ,       XMLCh&  firstCh
3420                                                        ,       XMLCh&  secondCh
3421                                                        ,       bool&   escaped)
3422{
3423#ifdef DGXML_SCANNER_DEPRECATED
3424        DEPRECATED_FEATURE_IN_ICXML;
3425#else
3426        // Assume no escape
3427        secondCh = 0;
3428        escaped = false;
3429
3430        // We have to insure that its all in one entity
3431        const XMLSize_t curReader = fReaderMgr.getCurrentReaderNum();
3432
3433        //  If the next char is a pound, then its a character reference and we
3434        //  need to expand it always.
3435        if (fReaderMgr.skippedChar(chPound))
3436        {
3437                //  Its a character reference, so scan it and get back the numeric
3438                //  value it represents.
3439                if (!scanCharRef(firstCh, secondCh))
3440                        return EntityExp_Failed;
3441
3442                escaped = true;
3443
3444                if (curReader != fReaderMgr.getCurrentReaderNum())
3445                        emitError(XMLErrs::PartialMarkupInEntity);
3446
3447                return EntityExp_Returned;
3448        }
3449
3450        // Expand it since its a normal entity ref
3451        XMLBufBid bbName(&fBufMgr);
3452
3453        int  colonPosition;
3454        bool validName = fDoNamespaces ? fReaderMgr.getQName(bbName.getBuffer(), &colonPosition) :
3455                                                                         fReaderMgr.getName(bbName.getBuffer());
3456        if (!validName)
3457        {
3458                if (bbName.isEmpty())
3459                        emitError(XMLErrs::ExpectedEntityRefName);
3460                else
3461                        emitError(XMLErrs::InvalidEntityRefName, bbName.getRawBuffer());
3462                return EntityExp_Failed;
3463        }
3464
3465        //  Next char must be a semi-colon. But if its not, just emit
3466        //  an error and try to continue.
3467        if (!fReaderMgr.skippedChar(chSemiColon))
3468                emitError(XMLErrs::UnterminatedEntityRef, bbName.getRawBuffer());
3469
3470        // Make sure we ended up on the same entity reader as the & char
3471        if (curReader != fReaderMgr.getCurrentReaderNum())
3472                emitError(XMLErrs::PartialMarkupInEntity);
3473
3474        // Look up the name in the general entity pool
3475        XMLEntityDecl* decl = fDTDGrammar->getEntityDecl(bbName.getRawBuffer());
3476
3477        // If it does not exist, then obviously an error
3478        if (!decl)
3479        {
3480                // XML 1.0 Section 4.1
3481                // Well-formedness Constraint for entity not found:
3482                //   In a document without any DTD, a document with only an internal DTD subset which contains no parameter entity references,
3483                //      or a document with "standalone='yes'", for an entity reference that does not occur within the external subset
3484                //      or a parameter entity
3485                //
3486                // Else it's Validity Constraint
3487                if (fStandalone || fHasNoDTD)
3488                        emitError(XMLErrs::EntityNotFound, bbName.getRawBuffer());
3489                else {
3490                        if (fValidate)
3491                                fValidator->emitError(XMLValid::VC_EntityNotFound, bbName.getRawBuffer());
3492                }
3493
3494                return EntityExp_Failed;
3495        }
3496
3497        // XML 1.0 Section 4.1
3498        //  If we are a standalone document, then it has to have been declared
3499        //  in the internal subset.
3500        if (fStandalone && !decl->getDeclaredInIntSubset())
3501                emitError(XMLErrs::IllegalRefInStandalone, bbName.getRawBuffer());
3502
3503        if (decl->isExternal())
3504        {
3505                // If its unparsed, then its not valid here
3506                if (decl->isUnparsed())
3507                {
3508                        emitError(XMLErrs::NoUnparsedEntityRefs, bbName.getRawBuffer());
3509                        return EntityExp_Failed;
3510                }
3511
3512                // If we are in an attribute value, then not valid but keep going
3513                if (inAttVal)
3514                        emitError(XMLErrs::NoExtRefsInAttValue);
3515
3516                // And now create a reader to read this entity
3517                InputSource* srcUsed;
3518                XMLReader* reader = fReaderMgr.createReader
3519                (
3520                        decl->getBaseURI()
3521                        , decl->getSystemId()
3522                        , decl->getPublicId()
3523                        , false
3524                        , XMLReader::RefFrom_NonLiteral
3525                        , XMLReader::Type_General
3526                        , XMLReader::Source_External
3527                        , srcUsed
3528                        , fCalculateSrcOfs
3529                        , fLowWaterMark
3530                        , fDisableDefaultEntityResolution
3531                );
3532
3533                // Put a janitor on the source so it gets cleaned up on exit
3534                Janitor<InputSource> janSrc(srcUsed);
3535
3536                //  If the creation failed, and its not because the source was empty,
3537                //  then emit an error and return.
3538                if (!reader)
3539                        ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Gen_CouldNotOpenExtEntity, srcUsed ? srcUsed->getSystemId() : decl->getSystemId(), fMemoryManager);
3540
3541                //  Push the reader. If its a recursive expansion, then emit an error
3542                //  and return an failure.
3543                if (!fReaderMgr.pushReader(reader, decl))
3544                {
3545                        emitError(XMLErrs::RecursiveEntity, decl->getName());
3546                        return EntityExp_Failed;
3547                }
3548
3549                // here's where we need to check if there's a SecurityManager,
3550                // how many entity references we've had
3551                if(fSecurityManager != 0 && ++fEntityExpansionCount > fEntityExpansionLimit) {
3552                        XMLCh expLimStr[32];
3553                        XMLString::sizeToText(fEntityExpansionLimit, expLimStr, 31, 10, fMemoryManager);
3554                        emitError
3555                        (
3556                                XMLErrs::EntityExpansionLimitExceeded
3557                                , expLimStr
3558                        );
3559                        // there seems nothing better to do than reset the entity expansion counter
3560                        fEntityExpansionCount = 0;
3561                }
3562
3563                //  Do a start entity reference event.
3564                //
3565                //  <TBD> For now, we supress them in att values. Later, when
3566                //  the stuff is in place to correctly allow DOM to handle them
3567                //  we'll turn this back on.
3568                if (fDocHandler && !inAttVal)
3569                        fDocHandler->startEntityReference(*decl);
3570
3571                // If it starts with the XML string, then parse a text decl
3572                if (checkXMLDecl(true))
3573                        scanXMLDecl(Decl_Text);
3574        }
3575        else
3576        {
3577                //  If its one of the special char references, then we can return
3578                //  it as a character, and its considered escaped.
3579                if (decl->getIsSpecialChar())
3580                {
3581                        firstCh = decl->getValue()[0];
3582                        escaped = true;
3583                        return EntityExp_Returned;
3584                }
3585
3586                //  Create a reader over a memory stream over the entity value
3587                //  We force it to assume UTF-16 by passing in an encoding
3588                //  string. This way it won't both trying to predecode the
3589                //  first line, looking for an XML/TextDecl.
3590                XMLReader* valueReader = fReaderMgr.createIntEntReader
3591                (
3592                        decl->getName()
3593                        , XMLReader::RefFrom_NonLiteral
3594                        , XMLReader::Type_General
3595                        , decl->getValue()
3596                        , decl->getValueLen()
3597                        , false
3598                );
3599
3600                //  Try to push the entity reader onto the reader manager stack,
3601                //  where it will become the subsequent input. If it fails, that
3602                //  means the entity is recursive, so issue an error. The reader
3603                //  will have just been discarded, but we just keep going.
3604                if (!fReaderMgr.pushReader(valueReader, decl))
3605                        emitError(XMLErrs::RecursiveEntity, decl->getName());
3606
3607                // here's where we need to check if there's a SecurityManager,
3608                // how many entity references we've had
3609                if(fSecurityManager != 0 && ++fEntityExpansionCount > fEntityExpansionLimit) {
3610                        XMLCh expLimStr[32];
3611                        XMLString::sizeToText(fEntityExpansionLimit, expLimStr, 31, 10, fMemoryManager);
3612                        emitError
3613                        (
3614                                XMLErrs::EntityExpansionLimitExceeded
3615                                , expLimStr
3616                        );
3617                }
3618
3619                //  Do a start entity reference event.
3620                //
3621                //  <TBD> For now, we supress them in att values. Later, when
3622                //  the stuff is in place to correctly allow DOM to handle them
3623                //  we'll turn this back on.
3624                if (fDocHandler && !inAttVal)
3625                        fDocHandler->startEntityReference(*decl);
3626
3627                // If it starts with the XML string, then it's an error
3628                if (checkXMLDecl(true)) {
3629                        emitError(XMLErrs::TextDeclNotLegalHere);
3630                        fReaderMgr.skipPastChar(chCloseAngle);
3631                }
3632        }
3633        return EntityExp_Pushed;
3634#endif
3635}
3636
3637
3638XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.