source: icXML/icXML-devel/src/icxercesc/internal/WFXMLScanner.cpp @ 2720

Last change on this file since 2720 was 2720, checked in by cameron, 7 years ago

Initial check-in of icXML 0.8 source files

File size: 18.1 KB
RevLine 
[2720]1/*
2 * Unless required by applicable law or agreed to in writing, software
3 * distributed under the License is distributed on an "AS IS" BASIS,
4 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5 * See the License for the specific language governing permissions and
6 * limitations under the License.
7 */
8
9/*
10  * $Id: WFXMLScanner.cpp 833045 2009-11-05 13:21:27Z borisk $
11 */
12
13// ---------------------------------------------------------------------------
14//  Includes
15// ---------------------------------------------------------------------------
16#include <xercesc/internal/WFXMLScanner.hpp>
17#include <xercesc/util/Janitor.hpp>
18#include <xercesc/util/RuntimeException.hpp>
19#include <xercesc/util/UnexpectedEOFException.hpp>
20#include <xercesc/sax/InputSource.hpp>
21#include <xercesc/framework/XMLDocumentHandler.hpp>
22#include <xercesc/framework/XMLEntityHandler.hpp>
23#include <xercesc/framework/XMLPScanToken.hpp>
24#include <xercesc/framework/XMLValidityCodes.hpp>
25#include <xercesc/internal/EndOfEntityException.hpp>
26#include <xercesc/util/OutOfMemoryException.hpp>
27#include <iostream>
28
29#define USE_PARABIX_READER
30
31XERCES_CPP_NAMESPACE_BEGIN
32
33// ---------------------------------------------------------------------------
34//  WFXMLScanner: Constructors and Destructor
35// ---------------------------------------------------------------------------
36
37
38typedef JanitorMemFunCall<WFXMLScanner> CleanupType;
39typedef JanitorMemFunCall<ReaderMgr>    ReaderMgrResetType;
40
41
42WFXMLScanner::WFXMLScanner( XMLValidator* const  valToAdopt
43                                                  , GrammarResolver* const grammarResolver
44                                                  , MemoryManager* const manager) :
45
46        XMLScanner(valToAdopt, grammarResolver, manager)
47        , fProgressiveParser(0)
48{
49        CleanupType cleanup(this, &WFXMLScanner::cleanUp);
50
51        try
52        {
53                commonInit();
54        }
55        catch(const OutOfMemoryException&)
56        {
57                // Don't cleanup when out of memory, since executing the
58                // code can cause problems.
59                cleanup.release();
60
61                throw;
62        }
63
64        cleanup.release();
65}
66
67WFXMLScanner::WFXMLScanner( XMLDocumentHandler* const docHandler
68                                                  , DocTypeHandler* const     docTypeHandler
69                                                  , XMLEntityHandler* const   entityHandler
70                                                  , XMLErrorReporter* const   errHandler
71                                                  , XMLValidator* const       valToAdopt
72                                                  , GrammarResolver* const    grammarResolver
73                                                  , MemoryManager* const      manager) :
74
75        XMLScanner(docHandler, docTypeHandler, entityHandler, errHandler, valToAdopt, grammarResolver, manager)
76        , fProgressiveParser(0)
77{
78        CleanupType cleanup(this, &WFXMLScanner::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
96WFXMLScanner::~WFXMLScanner()
97{
98        cleanUp();
99}
100
101// ---------------------------------------------------------------------------
102//  XMLScanner: Getter methods
103// ---------------------------------------------------------------------------
104NameIdPool<DTDEntityDecl>* WFXMLScanner::getEntityDeclPool()
105{
106        return 0;
107}
108
109const NameIdPool<DTDEntityDecl>* WFXMLScanner::getEntityDeclPool() const
110{
111        return 0;
112}
113
114// ---------------------------------------------------------------------------
115//  WFXMLScanner: Main entry point to scan a document
116// ---------------------------------------------------------------------------
117void WFXMLScanner::scanDocument(const InputSource& src)
118{
119        //  Bump up the sequence id for this parser instance. This will invalidate
120        //  any previous progressive scan tokens.
121        fSequenceId++;
122
123        ReaderMgrResetType  resetReaderMgr(&fReaderMgr, &ReaderMgr::reset);
124
125        try
126        {
127                //  Reset the scanner and its plugged in stuff for a new run. This
128                //  resets all the data structures, creates the initial reader and
129                //  pushes it on the stack, and sets up the base document path.
130                scanReset(src);
131
132                // If we have a document handler, then call the start document
133                if (fDocHandler)
134                        fDocHandler->startDocument();
135
136                //  If we got to the end of input, then its not a valid XML file.
137                //  Else, go on to scan the content.
138                if (fReaderMgr.atEOF())
139                {
140                        emitError(XMLErrs::EmptyMainEntity);
141                }
142                else
143                {
144                        // Scan content, and tell it its not an external entity
145                        if (fReaderMgr.getCurrentReader()->scanDocument<WFXMLScanner>(this))
146                        {
147
148                        }
149                }
150
151                // If we have a document handler, then call the end document
152                if (fDocHandler)
153                        fDocHandler->endDocument();
154
155        }
156        //  NOTE:
157        //
158        //  In all of the error processing below, the emitError() call MUST come
159        //  before the flush of the reader mgr, or it will fail because it tries
160        //  to find out the position in the XML source of the error.
161        catch(const XMLErrs::Codes)
162        {
163                // This is a 'first failure' exception, so fall through
164        }
165        catch(const XMLValid::Codes)
166        {
167                // This is a 'first fatal error' type exit, so fall through
168        }
169        catch(const XMLException& excToCatch)
170        {
171                //  Emit the error and catch any user exception thrown from here. Make
172                //  sure in all cases we flush the reader manager.
173                fInException = true;
174                try
175                {
176                        if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
177                                emitError
178                                (
179                                        XMLErrs::XMLException_Warning
180                                        , excToCatch.getCode()
181                                        , excToCatch.getMessage()
182                                );
183                        else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
184                                emitError
185                                (
186                                        XMLErrs::XMLException_Fatal
187                                        , excToCatch.getCode()
188                                        , excToCatch.getMessage()
189                                );
190                        else
191                                emitError
192                                (
193                                        XMLErrs::XMLException_Error
194                                        , excToCatch.getCode()
195                                        , excToCatch.getMessage()
196                                );
197                }
198                catch(const OutOfMemoryException&)
199                {
200                        // This is a special case for out-of-memory
201                        // conditions, because resetting the ReaderMgr
202                        // can be problematic.
203                        resetReaderMgr.release();
204                        throw;
205                }
206        }
207        catch(const OutOfMemoryException&)
208        {
209                // This is a special case for out-of-memory
210                // conditions, because resetting the ReaderMgr
211                // can be problematic.
212                resetReaderMgr.release();
213                throw;
214        }
215}
216
217void WFXMLScanner::scanFirst()
218{
219        fProgressiveParser = fReaderMgr.getCurrentReader()->scanFirst<WFXMLScanner>(this);
220}
221
222bool WFXMLScanner::scanNext(XMLPScanToken& token)
223{
224        // Make sure this token is still legal
225        if (!isLegalToken(token))
226                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Scan_BadPScanToken, fMemoryManager);
227
228        try
229        {
230                const bool gotData =
231                        fReaderMgr.getCurrentReader()->scanNext<WFXMLScanner>(*fProgressiveParser);
232
233                if (!gotData)
234                {
235                        if (fDocHandler)
236                                fDocHandler->endDocument();
237                }
238
239                return gotData;
240        }
241        catch(const XMLErrs::Codes)
242        {
243
244        }
245        catch(const XMLValid::Codes)
246        {
247
248        }
249        catch(const XMLException & excToCatch)
250        {
251                //  Emit the error and catch any user exception thrown from here. Make
252                //  sure in all cases we flush the reader manager.
253                fInException = true;
254                try
255                {
256                        if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
257                                emitError
258                                (
259                                        XMLErrs::XMLException_Warning
260                                        , excToCatch.getCode()
261                                        , excToCatch.getMessage()
262                                );
263                        else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
264                                emitError
265                                (
266                                        XMLErrs::XMLException_Fatal
267                                        , excToCatch.getCode()
268                                        , excToCatch.getMessage()
269                                );
270                        else
271                                emitError
272                                (
273                                        XMLErrs::XMLException_Error
274                                        , excToCatch.getCode()
275                                        , excToCatch.getMessage()
276                                );
277                }
278                catch(const OutOfMemoryException&)
279                {
280                        throw;
281                }
282        }
283        catch(const OutOfMemoryException&)
284        {
285                throw;
286        }
287
288        fReaderMgr.reset();
289
290        return false;
291}
292
293// ---------------------------------------------------------------------------
294//  WFXMLScanner: Private helper methods.
295// ---------------------------------------------------------------------------
296
297//  This method handles the common initialization, to avoid having to do
298//  it redundantly in multiple constructors.
299void WFXMLScanner::commonInit()
300{
301
302}
303
304void WFXMLScanner::cleanUp()
305{
306        delete fProgressiveParser;
307}
308
309//  This method will reset the scanner data structures, and related plugged
310//  in stuff, for a new scan session. We get the input source for the primary
311//  XML entity, create the reader for it, and push it on the stack so that
312//  upon successful return from here we are ready to go.
313void WFXMLScanner::scanReset(const InputSource& src)
314{
315        //  For all installed handlers, send reset events. This gives them
316        //  a chance to flush any cached data.
317        if (fDocHandler)
318                fDocHandler->resetDocument();
319        if (fEntityHandler)
320                fEntityHandler->resetEntities();
321        if (fErrorReporter)
322                fErrorReporter->resetErrors();
323
324        // Reset some status flags
325        fInException = false;
326        fStandalone = false;
327        fErrorCount = 0;
328        fHasNoDTD = true;
329
330        //  Handle the creation of the XML reader object for this input source.
331        //  This will provide us with transcoding and basic lexing services.
332        XMLReader* newReader = fReaderMgr.createReader
333        (
334                src
335                , true
336                , XMLReader::RefFrom_NonLiteral
337                , XMLReader::Type_General
338                , XMLReader::Source_External
339                , fCalculateSrcOfs
340                , fLowWaterMark
341        );
342
343        if (!newReader)
344        {
345                if (src.getIssueFatalErrorIfNotFound())
346                        ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource, src.getSystemId(), fMemoryManager);
347                else
348                        ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource_Warning, src.getSystemId(), fMemoryManager);
349        }
350
351        // Push this read onto the reader manager
352        fReaderMgr.pushReader(newReader, 0);
353
354        // and reset security-related things if necessary:
355        if(fSecurityManager != 0)
356        {
357                fEntityExpansionLimit = fSecurityManager->getEntityExpansionLimit();
358                fEntityExpansionCount = 0;
359        }
360}
361
362// ---------------------------------------------------------------------------
363//  WFXMLScanner: Private scanning methods
364// ---------------------------------------------------------------------------
365
366void WFXMLScanner::handleContent
367(
368        const XMLCh       * content
369        , const XMLSize_t   length
370)
371{
372        // If no data in the buffer, then nothing to do
373        assert (length > 0);
374
375        // Always assume it's just char data if not validating
376        if (fDocHandler)
377        {
378                fDocHandler->docCharacters(content, length, false);
379        }
380}
381
382// ---------------------------------------------------------------------------
383
384void WFXMLScanner::handleEndTag
385(
386        XMLElementDecl * const                  element
387        , const unsigned int                    uriId
388        , const XMLSize_t                               readerNum
389        , const bool                                    isRoot
390        , XMLElementDecl **                             children
391        , const XMLSize_t                               childCount
392)
393{
394        const ElemStack::StackElem * topElem = fElemStack.popTop();
395
396        // Make sure we are back on the same reader as where we started
397        if (topElem->fReaderNum != readerNum)
398        {
399                emitError(XMLErrs::PartialTagMarkupError);
400        }
401
402        // If we have a doc handler, tell it about the end tag
403        if (fDocHandler)
404        {
405                fDocHandler->endElement
406                (
407                        * element
408                        , uriId
409                        , isRoot
410                        , element->getElementName()->getPrefix()
411                );
412        }
413}
414
415// --------------------------------------------------------------------------------------------------------
416// HANDLE START / EMPTY TAG FUNCTIONS
417// --------------------------------------------------------------------------------------------------------
418
419XMLElementDecl * WFXMLScanner::handleStartTag
420(
421          const XMLSymbol * const               element
422        , const XMLAttributeList &              attributeList
423        , XMLSize_t                                             attributeCount
424        , const bool                                    isRoot
425        , const bool                                    isEmpty
426        , const XMLSize_t                               readerNum
427)
428{
429        //  Lets try to look up the element
430        XMLElementDecl * elemDecl = element->getElemDecl();
431
432        if (unlikely(!elemDecl))
433        {
434                #ifdef __GNUC__
435                #warning "WFXMLScanner::beginStartTag: memory leak! create an internal list within the WFXMLScanner to store the elemDecls? I would prefer to construct a global pool of QNames such that we can always determine whether a document element and a schema element are equivalent by checking the pointers. This would require an extensive modification to how uriIds are stored within QNames."
436                #endif
437
438                elemDecl = new (fGrammarPoolMemoryManager) DTDElementDecl
439                (
440                        element->getQName(), DTDElementDecl::Any, fGrammarPoolMemoryManager
441                );
442                element->setElemDecl(elemDecl);
443        }
444
445        fElemStack.addLevel(elemDecl, readerNum);
446
447        for (XMLSize_t index = 0; index < attributeCount; index++)
448        {
449                const XMLSymbol * attr = attributeList[index].getAttribute();
450                const XMLCh * attVal = attributeList[index].getValue();
451
452                const XMLCh * attName = attr->getName();
453
454                //  Add this attribute to the attribute list that we use to
455                //  pass them to the handler. We reuse its existing elements
456                //  but expand it as required.
457                XMLAttr * curAtt;
458                if (index >= this->fAttrList.size())
459                {
460                        curAtt = new (fMemoryManager) XMLAttr
461                         (
462                                 0
463                                 , attName
464                                 , XMLUni::fgZeroLenString
465                                 , attVal
466                                 , XMLAttDef::CData
467                                 , true
468                                 , fMemoryManager
469                         );
470
471                        this->fAttrList.addElement(curAtt);
472                }
473                else
474                {
475                        curAtt = this->fAttrList.elementAt(index);
476                        curAtt->set
477                        (
478                                0
479                                , attName
480                                , XMLUni::fgZeroLenString
481                                , attVal
482                        );
483                        curAtt->setSpecified(true);
484                }
485        }
486
487        // Expand the element stack and add the new element
488        // fReaderMgr.getCurrentReaderNum() -> or fCurReader->getReaderNum() -> passing "this" in from the XMLReader
489        if (unlikely(isEmpty))
490        {
491                fElemStack.popTop();
492        }
493
494        //  If we have a document handler, then tell it about this start tag. We
495        //  don't have any URI id to send along, so send fEmptyNamespaceId. We also do not send
496        //  any prefix since its just one big name if we are not doing namespaces.
497        if (fDocHandler)
498        {
499                fDocHandler->startElement
500                (
501                        *elemDecl
502                        , element->getQName()->getURI()
503                        , 0
504                        , fAttrList
505                        , attributeCount
506                        , isEmpty
507                        , isRoot
508                );
509        }
510
511        return elemDecl;
512}
513
514// ---------------------------------------------------------------------------
515//  WFXMLScanner: Grammar preparsing
516// ---------------------------------------------------------------------------
517Grammar* WFXMLScanner::loadGrammar( const InputSource&
518                                                                  , const short
519                                                                  , const bool)
520{
521        // REVISIT: emit a warning or throw an exception
522        return 0;
523}
524
525InputSource* WFXMLScanner::resolveSystemId(const XMLCh* const /*sysId*/
526                                                                                  ,const XMLCh* const /*pubId*/)
527{
528        return 0;
529}
530
531
532// ---------------------------------------------------------------------------
533//  WFXMLScanner: ICXML Deprecated Functions
534// ---------------------------------------------------------------------------
535
536void WFXMLScanner::sendCharData(XMLBuffer &)
537{
538        DEPRECATED_FEATURE_IN_ICXML;
539}
540
541bool WFXMLScanner::scanContent()
542{
543        DEPRECATED_FEATURE_IN_ICXML;
544}
545
546void WFXMLScanner::scanEndTag(bool&)
547{
548        DEPRECATED_FEATURE_IN_ICXML;
549}
550
551bool WFXMLScanner::scanStartTag(bool&)
552{
553        DEPRECATED_FEATURE_IN_ICXML;
554}
555
556bool WFXMLScanner::scanStartTagNS(bool&)
557{
558        DEPRECATED_FEATURE_IN_ICXML;
559}
560
561bool WFXMLScanner::scanAttValue(const XMLCh* const, XMLBuffer&)
562{
563        DEPRECATED_FEATURE_IN_ICXML;
564}
565
566void WFXMLScanner::scanCDSection()
567{
568        DEPRECATED_FEATURE_IN_ICXML;
569}
570
571void WFXMLScanner::scanCharData(XMLBuffer &)
572{
573        DEPRECATED_FEATURE_IN_ICXML;
574}
575
576//  This method will scan a general/character entity ref. It will either
577//  expand a char ref and return it directly, or push a reader for a general
578//  entity.
579//
580//  The return value indicates whether the char parameters hold the value
581//  or whether the value was pushed as a reader, or that it failed.
582//
583//  The escaped flag tells the caller whether the returned parameter resulted
584//  from a character reference, which escapes the character in some cases. It
585//  only makes any difference if the return value indicates the value was
586//  returned directly.
587XMLScanner::EntityExpRes
588WFXMLScanner::scanEntityRef(const bool
589                                                        ,     XMLCh&  firstCh
590                                                        ,     XMLCh&  secondCh
591                                                        ,     bool&   escaped)
592{
593#if 1
594        DEPRECATED_FEATURE_IN_ICXML;
595#else
596        // Assume no escape
597        secondCh = 0;
598        escaped = false;
599
600        // We have to insure that its all in one entity
601        const XMLSize_t curReader = fReaderMgr.getCurrentReaderNum();
602
603        //  If the next char is a pound, then its a character reference and we
604        //  need to expand it always.
605        if (fReaderMgr.skippedChar(chPound))
606        {
607                //  Its a character reference, so scan it and get back the numeric
608                //  value it represents.
609                if (!scanCharRef(firstCh, secondCh))
610                        return EntityExp_Failed;
611
612                escaped = true;
613
614                if (curReader != fReaderMgr.getCurrentReaderNum())
615                        emitError(XMLErrs::PartialMarkupInEntity);
616
617                return EntityExp_Returned;
618        }
619
620        // Expand it since its a normal entity ref
621        XMLBufBid bbName(&fBufMgr);
622        if (!fReaderMgr.getName(bbName.getBuffer()))
623        {
624                emitError(XMLErrs::ExpectedEntityRefName);
625                return EntityExp_Failed;
626        }
627
628        //  Next char must be a semi-colon. But if its not, just emit
629        //  an error and try to continue.
630        if (!fReaderMgr.skippedChar(chSemiColon))
631                emitError(XMLErrs::UnterminatedEntityRef, bbName.getRawBuffer());
632
633        // Make sure we ended up on the same entity reader as the & char
634        if (curReader != fReaderMgr.getCurrentReaderNum())
635                emitError(XMLErrs::PartialMarkupInEntity);
636
637        // Look up the name in the general entity pool
638        // If it does not exist, then obviously an error
639        if (!fEntityTable->containsKey(bbName.getRawBuffer()))
640        {
641                // XML 1.0 Section 4.1
642                // Well-formedness Constraint for entity not found:
643                //   In a document without any DTD, a document with only an internal DTD subset which contains no parameter entity references,
644                //      or a document with "standalone='yes'", for an entity reference that does not occur within the external subset
645                //      or a parameter entity
646                if (fStandalone || fHasNoDTD)
647                        emitError(XMLErrs::EntityNotFound, bbName.getRawBuffer());
648
649                return EntityExp_Failed;
650        }
651
652        // here's where we need to check if there's a SecurityManager,
653        // how many entity references we've had
654        if(fSecurityManager != 0 && ++fEntityExpansionCount > fEntityExpansionLimit)
655        {
656                XMLCh expLimStr[32];
657                XMLString::sizeToText(fEntityExpansionLimit, expLimStr, 31, 10, fMemoryManager);
658                emitError
659                (
660                        XMLErrs::EntityExpansionLimitExceeded
661                        , expLimStr
662                );
663                // there seems nothing better to be done than to reset the entity expansion counter
664                fEntityExpansionCount = 0;
665        }
666
667        firstCh = fEntityTable->get(bbName.getRawBuffer());
668        escaped = true;
669        return EntityExp_Returned;
670#endif
671}
672
673void WFXMLScanner::scanDocTypeDecl()
674{
675#ifdef EXCLUDE_TRADITIONAL_XERCES_FUNCTIONS_AND_VARIABLES
676        DEPRECATED_FEATURE_IN_ICXML;
677#else
678        // Just skips over it
679        // REVISIT: Should we issue a warning
680        static const XMLCh doctypeIE[] =
681        {
682                chOpenSquare, chCloseAngle, chNull
683        };
684        XMLCh nextCh = fReaderMgr.skipUntilIn(doctypeIE);
685
686        if (nextCh == chOpenSquare)
687                fReaderMgr.skipPastChar(chCloseSquare);
688
689        fReaderMgr.skipPastChar(chCloseAngle);
690#endif
691}
692
693XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.