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

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

Initial check-in of icXML 0.8 source files

File size: 28.6 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: ReaderMgr.cpp 833045 2009-11-05 13:21:27Z borisk $
20 */
21
22// ---------------------------------------------------------------------------
23//  Includes
24// ---------------------------------------------------------------------------
25#include <xercesc/util/BinMemInputStream.hpp>
26#include <xercesc/util/Janitor.hpp>
27#include <xercesc/util/PlatformUtils.hpp>
28#include <xercesc/util/RuntimeException.hpp>
29#include <xercesc/util/UnexpectedEOFException.hpp>
30#include <xercesc/util/XMLURL.hpp>
31#include <xercesc/util/XMLUniDefs.hpp>
32#include <xercesc/util/XMLUni.hpp>
33#include <xercesc/util/XMLUri.hpp>
34#include <xercesc/sax/InputSource.hpp>
35#include <xercesc/framework/LocalFileInputSource.hpp>
36#include <xercesc/framework/URLInputSource.hpp>
37#include <xercesc/framework/XMLBuffer.hpp>
38#include <xercesc/framework/XMLDocumentHandler.hpp>
39#include <xercesc/framework/XMLEntityDecl.hpp>
40#include <xercesc/framework/XMLEntityHandler.hpp>
41#include <xercesc/internal/EndOfEntityException.hpp>
42#include <xercesc/internal/ReaderMgr.hpp>
43#include <xercesc/util/OutOfMemoryException.hpp>
44#include <xercesc/util/XMLResourceIdentifier.hpp>
45
46XERCES_CPP_NAMESPACE_BEGIN
47
48// ---------------------------------------------------------------------------
49//  ReaderMgr: Constructors and Destructor
50// ---------------------------------------------------------------------------
51ReaderMgr::ReaderMgr(MemoryManager* const manager) :
52
53        fCurEntity(0)
54        , fCurReader(0)
55        , fEntityHandler(0)
56        , fEntityStack(0)
57        , fNextReaderNum(1)
58        , fReaderStack(0)
59        , fThrowEOE(false)
60        , fXMLVersion(XMLReader::XMLV1_0)
61        , fStandardUriConformant(false)
62        , fMemoryManager(manager)
63{
64}
65
66ReaderMgr::~ReaderMgr()
67{
68        //
69        //  Clean up the reader and entity stacks. Note that we don't own the
70        //  entities, so we don't delete the current entity (and the entity stack
71        //  does not own its elements either, so deleting it will not delete the
72        //  entities it still references!)
73        //
74        delete fCurReader; fCurReader=0;
75        delete fReaderStack; fReaderStack=0;
76        delete fEntityStack; fEntityStack=0;
77}
78
79
80// ---------------------------------------------------------------------------
81//  ReaderMgr: Getter methods
82// ---------------------------------------------------------------------------
83bool ReaderMgr::isEmpty() const
84{
85        return fReaderStack->empty();
86}
87
88
89// ---------------------------------------------------------------------------
90//  ReaderMgr: Scanning APIs
91// ---------------------------------------------------------------------------
92XMLCh ReaderMgr::getNextChar()
93{
94        XMLCh chRet;
95        if (fCurReader->getNextChar(chRet))
96                return chRet;
97
98        //
99        //  Didn't get anything back so this reader is hosed. So lets move to
100        //  the next reader on the stack. If this fails, it will be because
101        //  its the end of the original file, and we just return zero.
102        //
103        //  If its the end of an entity and fThrowEOE is set, it will throw out
104        //  of here. Otherwise, it will take us down to the next reader and
105        //  we'll have more chars.
106        //
107        if (!popReader())
108                return XMLCh(0);
109
110        // Else try again and return the new character
111        fCurReader->getNextChar(chRet);
112        return chRet;
113}
114
115
116void ReaderMgr::getSpaces(XMLBuffer& toFill)
117{
118        // Reset the buffer before we start
119        toFill.reset();
120
121        //
122        //  Get all the spaces from the current reader. If it returns true,
123        //  it hit a non-space and we are done. Else we have to pop a reader
124        //  and keep going.
125        //
126        while (!fCurReader->getSpaces(toFill))
127        {
128                // We wore that one out, so lets pop a reader and try again
129                if (!popReader())
130                        break;
131        }
132}
133
134
135void ReaderMgr::getUpToCharOrWS(XMLBuffer& toFill, const XMLCh toCheck)
136{
137        // Reset the target buffer before we start
138        toFill.reset();
139
140        //
141        //  Ok, enter a loop where we ask the current reader to get chars until
142        //  it meets the criteria. It returns false if it came back due to eating
143        //  up all of its data. Else it returned because something matched, and
144        //  we are done.
145        //
146        while (!fCurReader->getUpToCharOrWS(toFill, toCheck))
147        {
148                // We ate that one up, lets try to pop another. If not, break out
149                if (!popReader())
150                        break;
151        }
152}
153
154
155XMLCh ReaderMgr::peekNextChar()
156{
157        XMLCh chRet;
158        if (fCurReader->peekNextChar(chRet))
159                return chRet;
160
161        //
162        //  Didn't get anything back so this reader is hosed. So lets move to
163        //  the next reader on the stack. If this fails, it will be because
164        //  its the end of the original file, and we just return zero.
165        //
166        if (!popReader())
167                return XMLCh(0);
168
169        // Else peek again and return the character
170        fCurReader->peekNextChar(chRet);
171        return chRet;
172}
173
174
175bool ReaderMgr::skippedChar(const XMLCh toCheck)
176{
177        while (true)
178        {
179                // If we get it, then just return true now
180                if (fCurReader->skippedChar(toCheck))
181                        return true;
182
183                //
184                //  Check to see if we hit end of input on this reader. If so, then
185                //  lets pop and try again. Else, we failed. If we cannot pop another
186                //  then we failed.
187                //
188                if (!fCurReader->getNoMoreFlag())
189                        break;
190
191                if (!popReader())
192                        break;
193        }
194        return false;
195}
196
197
198bool ReaderMgr::skippedSpace()
199{
200        while (true)
201        {
202                // If we get it, then just return true now
203                if (fCurReader->skippedSpace())
204                        return true;
205
206                //
207                //  Check to see if we hit end of input on this reader. If so, then
208                //  lets pop and try again. Else, we failed. If we cannot pop another
209                //  then we failed.
210                //
211                if (!fCurReader->getNoMoreFlag())
212                        break;
213
214                if (!popReader())
215                        break;
216        }
217        return false;
218}
219
220
221bool ReaderMgr::skipIfQuote(XMLCh& chGotten)
222{
223        while (true)
224        {
225                // If we get it, then just return true now
226                if (fCurReader->skipIfQuote(chGotten))
227                        return true;
228
229                //
230                //  Check to see if we hit end of input on this reader. If so, then
231                //  lets pop and try again. Else, we failed. If we cannot pop another
232                //  then we failed.
233                //
234                if (!fCurReader->getNoMoreFlag())
235                        break;
236
237                if (!popReader())
238                        break;
239        }
240        return false;
241}
242
243void ReaderMgr::skipPastSpaces(bool& skippedSomething, bool inDecl /* = false */)
244{
245        // we rely on the fact that fCurReader->skipSpaces will NOT reset the flag to false, but only
246        // set it to true if a space is found
247        skippedSomething = false;
248        //
249        //  Skip all the spaces in the current reader. If it returned because
250        //  it hit a non-space, break out. Else we have to pop another entity
251        //  and keep going.
252        //
253        while (!fCurReader->skipSpaces(skippedSomething, inDecl))
254        {
255                // Try to pop another entity. If we can't then we are done
256                if (!popReader())
257                        break;
258        }
259}
260
261void ReaderMgr::skipPastSpaces()
262{
263        // we are not using it, so we don't care to initialize it
264        bool tmpFlag;
265        //
266        //  Skip all the spaces in the current reader. If it returned because
267        //  it hit a non-space, break out. Else we have to pop another entity
268        //  and keep going.
269        //
270        while (!fCurReader->skipSpaces(tmpFlag, false))
271        {
272                // Try to pop another entity. If we can't then we are done
273                if (!popReader())
274                        break;
275        }
276}
277
278void ReaderMgr::skipQuotedString(const XMLCh quoteCh)
279{
280        XMLCh nextCh;
281        // If we get an end of file char, then return
282        while ((nextCh = getNextChar())!=0)
283        {
284                // If we get the quote char, then break out
285                if (nextCh == quoteCh)
286                        break;
287        }
288}
289
290
291XMLCh ReaderMgr::skipUntilIn(const XMLCh* const listToSkip)
292{
293        XMLCh nextCh;
294        // If we get an end of file char, then return
295        while ((nextCh = peekNextChar())!=0)
296        {
297                if (XMLString::indexOf(listToSkip, nextCh) != -1)
298                        break;
299
300                // Its one of ours so eat it
301                getNextChar();
302        }
303        return nextCh;
304}
305
306
307XMLCh ReaderMgr::skipUntilInOrWS(const XMLCh* const listToSkip)
308{
309        XMLCh nextCh;
310        // If we get an end of file char, then return
311        while ((nextCh = peekNextChar())!=0)
312        {
313                if (fCurReader->isWhitespace(nextCh))
314                        break;
315
316                if (XMLString::indexOf(listToSkip, nextCh) != -1)
317                        break;
318
319                // Its one of ours, so eat it
320                getNextChar();
321        }
322        return nextCh;
323}
324
325
326
327// ---------------------------------------------------------------------------
328//  ReaderMgr: Control methods
329// ---------------------------------------------------------------------------
330
331//
332//  If the reader stack is empty, then there is only the original main XML
333//  entity left. If its empty, then we have no more input.
334//
335bool ReaderMgr::atEOF() const
336{
337        return fReaderStack->empty() && fCurReader->getNoMoreFlag();
338}
339
340
341//
342//  This method is called in the case of errors to clean up the stack when
343//  entities have been incorrectly left on the stack due to syntax errors.
344//  It just cleans back the stack, and sends no entity events.
345//
346void ReaderMgr::cleanStackBackTo(const XMLSize_t readerNum)
347{
348        //
349        //  Just start popping readers until we find the one with the indicated
350        //  reader number.
351        //
352        while (true)
353        {
354                if (fCurReader->getReaderNum() == readerNum)
355                        break;
356
357                if (fReaderStack->empty())
358                        ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::RdrMgr_ReaderIdNotFound, fMemoryManager);
359
360                delete fCurReader;
361                fCurReader = fReaderStack->pop();
362                fCurEntity = fEntityStack->pop();
363        }
364}
365
366
367XMLReader* ReaderMgr::createReader( const   InputSource&        src
368                                                                        , const bool
369                                                                        , const XMLReader::RefFrom  refFrom
370                                                                        , const XMLReader::Types    type
371                                                                        , const XMLReader::Sources  source
372                                                                        , const bool                calcSrcOfs
373                                                                        ,       XMLSize_t           lowWaterMark)
374{
375
376        DEBUG_MESSAGE(" ***** ReaderMgr::createReader 1");
377
378        //
379        //  Ask the input source to create us an input stream. The particular
380        //  type of input source will know what kind to create.
381        //
382        BinInputStream* newStream = src.makeStream();
383        if (!newStream)
384                return 0;
385
386        Janitor<BinInputStream>   streamJanitor(newStream);
387
388        //
389        //  Create a new reader and return it. If the source has an encoding that
390        //  it wants to force, then we call the constructor that does that.
391        //  Otherwise, we just call the one that provides the provisional encoding
392        //  to be possibly updated later by the encoding="" setting.
393        //
394        XMLReader* retVal = 0;
395
396        // XMLReader ctor invokes refreshRawBuffer() which calls
397        // newStream->readBytes().
398        // This readBytes() may throw exception, which neither
399        // refresRawBuffer(), nor XMLReader ctor catches.
400        // We need to handle this exception to avoid leak on newStream.
401
402        try
403        {
404                if (src.getEncoding())
405                {
406                        retVal = new (fMemoryManager) XMLReader
407                        (
408                                src.getPublicId()
409                                , src.getSystemId()
410                                , newStream
411                                , src.getEncoding()
412                                , refFrom
413                                , type
414                                , source
415                                , false
416                                , calcSrcOfs
417                                , lowWaterMark
418                                , fXMLVersion
419                                , fMemoryManager
420                        );
421                }
422                else
423                {
424                        retVal = new (fMemoryManager) XMLReader
425                        (
426                                src.getPublicId()
427                                , src.getSystemId()
428                                , newStream
429                                , refFrom
430                                , type
431                                , source
432                                , false
433                                , calcSrcOfs
434                                , lowWaterMark
435                                , fXMLVersion
436                                , fMemoryManager
437                        );
438                }
439        }
440        catch(const OutOfMemoryException&)
441        {
442                streamJanitor.release();
443                throw;
444        }
445
446
447
448        streamJanitor.release();
449
450        // Set the next available reader number on this reader
451        retVal->setReaderNum(fNextReaderNum++);
452        return retVal;
453}
454
455
456XMLReader* ReaderMgr::createReader( const   XMLCh* const        sysId
457                                                                        , const XMLCh* const        pubId
458                                                                        , const bool                xmlDecl
459                                                                        , const XMLReader::RefFrom  refFrom
460                                                                        , const XMLReader::Types    type
461                                                                        , const XMLReader::Sources  source
462                                                                        ,       InputSource*&       srcToFill
463                                                                        , const bool                calcSrcOfs
464                                                                        ,       XMLSize_t           lowWaterMark
465                                                                        , const bool                disableDefaultEntityResolution)
466{
467
468        //Normalize sysId
469        XMLBuffer normalizedSysId(1023, fMemoryManager);
470        if(sysId)
471                XMLString::removeChar(sysId, 0xFFFF, normalizedSysId);
472        const XMLCh* normalizedURI = normalizedSysId.getRawBuffer();
473
474        // Create a buffer for expanding the system id
475        XMLBuffer expSysId(1023, fMemoryManager);
476
477        //
478        //  Allow the entity handler to expand the system id if they choose
479        //  to do so.
480        //
481        if (fEntityHandler)
482        {
483                if (!fEntityHandler->expandSystemId(normalizedURI, expSysId))
484                        expSysId.set(normalizedURI);
485        }
486         else
487        {
488                expSysId.set(normalizedURI);
489        }
490
491        // Call the entity resolver interface to get an input source
492        srcToFill = 0;
493        if (fEntityHandler)
494        {
495                LastExtEntityInfo lastInfo;
496                getLastExtEntityInfo(lastInfo);
497                XMLResourceIdentifier resourceIdentifier(XMLResourceIdentifier::ExternalEntity,
498                                                        expSysId.getRawBuffer(), XMLUni::fgZeroLenString, pubId, lastInfo.systemId,
499                                                        this);
500                srcToFill = fEntityHandler->resolveEntity(&resourceIdentifier);
501        }
502
503        //
504        //  If they didn't create a source via the entity resolver, then we
505        //  have to create one on our own.
506        //
507        if (!srcToFill)
508        {
509                if (disableDefaultEntityResolution)
510                        return 0;
511
512                LastExtEntityInfo lastInfo;
513                getLastExtEntityInfo(lastInfo);
514
515// Keep this #if 0 block as it was exposing a threading problem on AIX.
516// Got rid of the problem by changing XMLURL to not throw malformedurl
517// exceptions.
518#if 0
519                try
520                {
521                        XMLURL urlTmp(lastInfo.systemId, expSysId.getRawBuffer(), fMemoryManager);
522                        if (urlTmp.isRelative())
523                        {
524                                ThrowXMLwithMemMgr
525                                (
526                                        MalformedURLException
527                                        , XMLExcepts::URL_NoProtocolPresent
528                                        , fMemoryManager
529                                );
530                        }
531                        else {
532                                if (fStandardUriConformant && urlTmp.hasInvalidChar())
533                                        ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);
534                                srcToFill = new (fMemoryManager) URLInputSource(urlTmp, fMemoryManager);
535                        }
536                }
537
538                catch(const MalformedURLException& e)
539                {
540                        // Its not a URL, so lets assume its a local file name if non-standard uri is allowed
541                        if (!fStandardUriConformant)
542                                srcToFill = new (fMemoryManager) LocalFileInputSource
543                                (
544                                        lastInfo.systemId
545                                        , expSysId.getRawBuffer()
546                                        , fMemoryManager
547                                );
548                        else
549                                throw e;
550                }
551#else
552                XMLURL urlTmp(fMemoryManager);
553                if ((!urlTmp.setURL(lastInfo.systemId, expSysId.getRawBuffer(), urlTmp)) ||
554                        (urlTmp.isRelative()))
555                {
556                        if (!fStandardUriConformant)
557                        {
558                                XMLBuffer resolvedSysId(1023, fMemoryManager);
559                                XMLUri::normalizeURI(expSysId.getRawBuffer(), resolvedSysId);
560
561                                srcToFill = new (fMemoryManager) LocalFileInputSource
562                                (
563                                        lastInfo.systemId
564                                        , resolvedSysId.getRawBuffer()
565                                        , fMemoryManager
566                                );
567                        }
568                        else
569                                ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);
570                }
571                else
572                {
573                        if (fStandardUriConformant && urlTmp.hasInvalidChar())
574                                ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);
575                        srcToFill = new (fMemoryManager) URLInputSource(urlTmp, fMemoryManager);
576                }
577#endif
578        }
579
580        // Put a janitor on the input source
581        Janitor<InputSource> janSrc(srcToFill);
582
583        //
584        //  Now call the other version with the input source that we have, and
585        //  return the resulting reader.
586        //
587        XMLReader* retVal = createReader
588        (
589                *srcToFill
590                , xmlDecl
591                , refFrom
592                , type
593                , source
594                , calcSrcOfs
595                , lowWaterMark
596        );
597
598        // Either way, we can release the input source now
599        janSrc.orphan();
600
601        // If it failed for any reason, then return zero.
602        if (!retVal)
603                return 0;
604
605        // Give this reader the next available reader number and return it
606        retVal->setReaderNum(fNextReaderNum++);
607        return retVal;
608}
609
610
611XMLReader* ReaderMgr::createReader( const   XMLCh* const        baseURI
612                                                                        , const XMLCh* const        sysId
613                                                                        , const XMLCh* const        pubId
614                                                                        , const bool                xmlDecl
615                                                                        , const XMLReader::RefFrom  refFrom
616                                                                        , const XMLReader::Types    type
617                                                                        , const XMLReader::Sources  source
618                                                                        ,       InputSource*&       srcToFill
619                                                                        , const bool                calcSrcOfs
620                                                                        ,       XMLSize_t           lowWaterMark
621                                                                        , const bool                disableDefaultEntityResolution)
622{
623        //Normalize sysId
624        XMLBuffer normalizedSysId(1023, fMemoryManager);
625        XMLString::removeChar(sysId, 0xFFFF, normalizedSysId);
626        const XMLCh* normalizedURI = normalizedSysId.getRawBuffer();
627
628        // Create a buffer for expanding the system id
629        XMLBuffer expSysId(1023, fMemoryManager);
630
631        //
632        //  Allow the entity handler to expand the system id if they choose
633        //  to do so.
634        //
635        if (fEntityHandler)
636        {
637                if (!fEntityHandler->expandSystemId(normalizedURI, expSysId))
638                        expSysId.set(normalizedURI);
639        }
640         else
641        {
642                expSysId.set(normalizedURI);
643        }
644
645        // Call the entity resolver interface to get an input source
646        srcToFill = 0;
647        if (fEntityHandler)
648        {
649                XMLResourceIdentifier resourceIdentifier(XMLResourceIdentifier::ExternalEntity,
650                                                        expSysId.getRawBuffer(), XMLUni::fgZeroLenString, pubId, baseURI,
651                                                        this);
652                srcToFill = fEntityHandler->resolveEntity(&resourceIdentifier);
653        }
654
655        //
656        //  If they didn't create a source via the entity resolver, then we
657        //  have to create one on our own.
658        //
659        if (!srcToFill)
660        {
661                if (disableDefaultEntityResolution)
662                        return 0;
663
664                LastExtEntityInfo lastInfo;
665
666                const XMLCh* baseuri=baseURI;
667                if(!baseuri || !*baseuri)
668                {
669                        getLastExtEntityInfo(lastInfo);
670                        baseuri = lastInfo.systemId;
671                }
672
673                XMLURL urlTmp(fMemoryManager);
674                if ((!urlTmp.setURL(baseuri, expSysId.getRawBuffer(), urlTmp)) ||
675                        (urlTmp.isRelative()))
676                {
677                        if (!fStandardUriConformant)
678                        {
679                                XMLBuffer resolvedSysId(1023, fMemoryManager);
680                                XMLUri::normalizeURI(expSysId.getRawBuffer(), resolvedSysId);
681
682                                srcToFill = new (fMemoryManager) LocalFileInputSource
683                                (
684                                        baseuri
685                                        , resolvedSysId.getRawBuffer()
686                                        , fMemoryManager
687                                );
688                        }
689                        else
690                                ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);
691                }
692                else
693                {
694                        if (fStandardUriConformant && urlTmp.hasInvalidChar())
695                                ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);
696                        srcToFill = new (fMemoryManager) URLInputSource(urlTmp, fMemoryManager);
697                }
698        }
699
700        // Put a janitor on the input source
701        Janitor<InputSource> janSrc(srcToFill);
702
703        //
704        //  Now call the other version with the input source that we have, and
705        //  return the resulting reader.
706        //
707        XMLReader* retVal = createReader
708        (
709                *srcToFill
710                , xmlDecl
711                , refFrom
712                , type
713                , source
714                , calcSrcOfs
715                , lowWaterMark
716        );
717
718        // Either way, we can release the input source now
719        janSrc.orphan();
720
721        // If it failed for any reason, then return zero.
722        if (!retVal)
723                return 0;
724
725        // Give this reader the next available reader number and return it
726        retVal->setReaderNum(fNextReaderNum++);
727        return retVal;
728}
729
730
731XMLReader*
732ReaderMgr::createIntEntReader(  const   XMLCh* const        sysId
733                                                                , const XMLReader::RefFrom  refFrom
734                                                                , const XMLReader::Types    type
735                                                                , const XMLCh* const        dataBuf
736                                                                , const XMLSize_t           dataLen
737                                                                , const bool                copyBuf
738                                                                , const bool                calcSrcOfs
739                                                                ,       XMLSize_t           lowWaterMark)
740{
741        //
742        //  This one is easy, we just create an input stream for the data and
743        //  provide a few extra goodies.
744        //
745        //  NOTE: We use a special encoding string that will be recognized
746        //  as a 'do nothing' transcoder for the already internalized XMLCh
747        //  data that makes up an internal entity.
748        //
749        BinMemInputStream* newStream = new (fMemoryManager) BinMemInputStream
750                                                                   (
751                                                                         (const XMLByte*)dataBuf
752                                                                         , dataLen * sizeof(XMLCh)
753                                                                         , copyBuf ? BinMemInputStream::BufOpt_Copy
754                                                                                           : BinMemInputStream::BufOpt_Reference
755                                                                         , fMemoryManager
756                                                                   );
757        if (!newStream)
758                return 0;
759
760        XMLReader* retVal = new (fMemoryManager) XMLReader
761        (
762                sysId
763                , 0
764                , newStream
765                , XMLRecognizer::XERCES_XMLCH
766                , refFrom
767                , type
768                , XMLReader::Source_Internal
769                , false
770                , calcSrcOfs
771                , lowWaterMark
772                , fXMLVersion
773                , fMemoryManager
774        );
775
776        // If it failed for any reason, then return zero.
777        if (!retVal)
778        {
779                delete newStream;
780                return 0;
781        }
782
783        // Set the reader number to the next available number
784        retVal->setReaderNum(fNextReaderNum++);
785        return retVal;
786}
787
788
789const XMLCh* ReaderMgr::getCurrentEncodingStr() const
790{
791        const XMLEntityDecl*    theEntity;
792        const XMLReader*        theReader = getLastExtEntity(theEntity);
793
794        return theReader->getEncodingStr();
795}
796
797
798const XMLEntityDecl* ReaderMgr::getCurrentEntity() const
799{
800        return fCurEntity;
801}
802
803
804XMLEntityDecl* ReaderMgr::getCurrentEntity()
805{
806        return fCurEntity;
807}
808
809
810XMLSize_t ReaderMgr::getReaderDepth() const
811{
812        // If the stack doesn't exist, its obviously zero
813        if (!fEntityStack)
814                return 0;
815
816        //
817        //  The return is the stack size, plus one if there is a current
818        //  reader. So if there is no current reader and none on the stack,
819        //  its zero, else its some non-zero value.
820        //
821        XMLSize_t retVal = fEntityStack->size();
822        if (fCurReader)
823                retVal++;
824        return retVal;
825}
826
827void ReaderMgr::getLastExtEntityInfo(LastExtEntityInfo& lastInfo) const
828{
829        //
830        //  If the reader stack never got created or we've not managed to open any
831        //  main entity yet, then we can't give this information.
832        //
833        if (!fReaderStack || !fCurReader)
834        {
835                lastInfo.systemId = XMLUni::fgZeroLenString;
836                lastInfo.publicId = XMLUni::fgZeroLenString;
837                lastInfo.lineNumber = 0;
838                lastInfo.colNumber = 0;
839                return;
840        }
841
842        // We have at least one entity so get the data
843        const XMLEntityDecl*    theEntity;
844        const XMLReader*        theReader = getLastExtEntity(theEntity);
845
846        // Fill in the info structure with the reader we found
847        lastInfo.systemId = theReader->getSystemId();
848        lastInfo.publicId = theReader->getPublicId();
849        theReader->getCurrentLineColumn(lastInfo.lineNumber, lastInfo.colNumber);
850}
851
852
853bool ReaderMgr::isScanningPERefOutOfLiteral() const
854{
855        // If the current reader is not for an entity, then definitely not
856        if (!fCurEntity)
857                return false;
858
859        //
860        //  If this is a PE entity, and its not being expanded in a literal
861        //  then its true.
862        //
863        if ((fCurReader->getType() == XMLReader::Type_PE)
864        &&  (fCurReader->getRefFrom() == XMLReader::RefFrom_NonLiteral))
865        {
866                return true;
867        }
868        return false;
869}
870
871
872bool ReaderMgr::pushReader(XMLReader* const reader, XMLEntityDecl* const entity)
873{
874        DEBUG_MESSAGE(" ***** ReaderMgr::pushReader");
875        //
876        //  First, if an entity was passed, we have to confirm that this entity
877        //  is not already on the entity stack. If so, then this is a recursive
878        //  entity expansion, so we issue an error and refuse to put the reader
879        //  on the stack.
880        //
881        //  If there is no entity passed, then its not an entity being pushed, so
882        //  nothing to do. If there is no entity stack yet, then of coures it
883        //  cannot already be there.
884        //
885        if (entity && fEntityStack)
886        {
887                const XMLSize_t count = fEntityStack->size();
888                const XMLCh* const theName = entity->getName();
889                for (XMLSize_t index = 0; index < count; index++)
890                {
891                        const XMLEntityDecl* curDecl = fEntityStack->elementAt(index);
892                        if (curDecl)
893                        {
894                                if (XMLString::equals(theName, curDecl->getName()))
895                                {
896                                        // Oops, already there so delete reader and return
897                                        delete reader;
898                                        return false;
899                                }
900                        }
901                }
902        }
903
904        //
905        //  Fault in the reader stack. Give it an initial capacity of 16, and
906        //  tell it it does own its elements.
907        //
908        if (!fReaderStack)
909                fReaderStack = new (fMemoryManager) RefStackOf<XMLReader>(16, true, fMemoryManager);
910
911        // And the entity stack, which does not own its elements
912        if (!fEntityStack)
913                fEntityStack = new (fMemoryManager) RefStackOf<XMLEntityDecl>(16, false, fMemoryManager);
914
915        //
916        //  Push the current reader and entity onto their respective stacks.
917        //  Note that the the current entity can be null if the current reader
918        //  is not for an entity.
919        //
920        if (fCurReader)
921        {
922                fReaderStack->push(fCurReader);
923                fEntityStack->push(fCurEntity);
924        }
925
926        //
927        //  Make the passed reader and entity the current top of stack. The
928        //  passed entity can (and often is) null.
929        //
930        fCurReader = reader;
931        fCurEntity = entity;
932
933        return true;
934}
935
936
937void ReaderMgr::reset()
938{
939        DEBUG_MESSAGE(" ***** ReaderMgr::reset");
940
941        // Reset all of the flags
942        fThrowEOE = false;
943
944        // Delete the current reader and flush the reader stack
945        delete fCurReader;
946        fCurReader = 0;
947        if (fReaderStack)
948                fReaderStack->removeAllElements();
949
950        //
951        //  And do the same for the entity stack, but don't delete the current
952        //  entity (if any) since we don't own them.
953        //
954        fCurEntity = 0;
955        if (fEntityStack)
956                fEntityStack->removeAllElements();
957}
958
959
960// ---------------------------------------------------------------------------
961//  ReaderMgr: Implement the SAX Locator interface
962// ---------------------------------------------------------------------------
963const XMLCh* ReaderMgr::getPublicId() const
964{
965        if (!fReaderStack && !fCurReader)
966                return XMLUni::fgZeroLenString;
967
968        const XMLEntityDecl* theEntity;
969        return getLastExtEntity(theEntity)->getPublicId();
970}
971
972const XMLCh* ReaderMgr::getSystemId() const
973{
974        if (!fReaderStack && !fCurReader)
975                return XMLUni::fgZeroLenString;
976
977        const XMLEntityDecl* theEntity;
978        return getLastExtEntity(theEntity)->getSystemId();
979}
980
981XMLFileLoc ReaderMgr::getColumnNumber() const
982{
983        if (!fReaderStack && !fCurReader)
984                return 0;
985
986    //const XMLEntityDecl* theEntity;
987    return 1; // getLastExtEntity(theEntity)->getColumnNumber();
988}
989
990XMLFileLoc ReaderMgr::getLineNumber() const
991{
992        if (!fReaderStack && !fCurReader)
993                return 0;
994
995    //const XMLEntityDecl* theEntity;
996    return 2; // getLastExtEntity(theEntity)->getLineNumber();
997}
998
999
1000
1001// ---------------------------------------------------------------------------
1002//  ReaderMgr: Private helper methods
1003// ---------------------------------------------------------------------------
1004const XMLReader*
1005ReaderMgr::getLastExtEntity(const XMLEntityDecl*& itsEntity) const
1006{
1007        //
1008        //  Scan down the reader stack until we find a reader for an entity that
1009        //  is external. First check that there is anything in the stack at all,
1010        //  in which case the current reader is the main file and that's the one
1011        //  that we want.
1012        //
1013        const XMLReader* theReader = fCurReader;
1014
1015        //
1016        //  If there is a current entity and it is not an external entity, then
1017        //  search the stack; else, keep the reader that we've got since its
1018        //  either an external entity reader or the main file reader.
1019        //
1020        const XMLEntityDecl* curEntity = fCurEntity;
1021        if (curEntity && !curEntity->isExternal())
1022        {
1023                XMLSize_t index = fReaderStack->size();
1024                if (index)
1025                {
1026                        while (true)
1027                        {
1028                                // Move down to the previous element and get a pointer to it
1029                                index--;
1030                                curEntity = fEntityStack->elementAt(index);
1031
1032                                //
1033                                //  If its null or its an external entity, then this reader
1034                                //  is what we want, so break out with that one.
1035                                //
1036                                if (!curEntity)
1037                                {
1038                                        theReader = fReaderStack->elementAt(index);
1039                                        break;
1040                                }
1041                                 else if (curEntity->isExternal())
1042                                {
1043                                        theReader = fReaderStack->elementAt(index);
1044                                        break;
1045                                }
1046
1047                                // We hit the end, so leave the main file reader as the one
1048                                if (!index)
1049                                        break;
1050                        }
1051                }
1052        }
1053
1054        itsEntity = curEntity;
1055        return theReader;
1056}
1057
1058
1059bool ReaderMgr::popReader()
1060{
1061        //
1062        //  We didn't get any more, so try to pop off a reader. If the reader
1063        //  stack is empty, then we are at the end, so return false.
1064        //
1065        if (fReaderStack->empty())
1066        {
1067                return false;
1068        }
1069
1070        DEBUG_MESSAGE(" ***** ReaderMgr::popReader");
1071
1072        //
1073        //  Remember the current entity, before we pop off a new one. We might
1074        //  need this to throw the end of entity exception at the end.
1075        //
1076        XMLEntityDecl* prevEntity = fCurEntity;
1077        const bool prevReaderThrowAtEnd = fCurReader->getThrowAtEnd();
1078        const XMLSize_t readerNum = fCurReader->getReaderNum();
1079
1080        //
1081        //  Delete the current reader and pop a new reader and entity off
1082        //  the stacks.
1083        //
1084        delete fCurReader;
1085        fCurReader = fReaderStack->pop();
1086        fCurEntity = fEntityStack->pop();
1087
1088        //
1089        //  If there was a previous entity, and either the fThrowEOE flag is set
1090        //  or reader was marked as such, then throw an end of entity.
1091        //
1092        if (prevEntity && (fThrowEOE || prevReaderThrowAtEnd))
1093                throw EndOfEntityException(prevEntity, readerNum);
1094
1095        for (;;)
1096        {
1097                //
1098                //  They don't want us to throw, so lets just return with a new
1099                //  reader. Here we have to do a loop because we might have multiple
1100                //  readers on these stack that are empty (i.e. the last char in them
1101                //  was the ';' at the end of the entity ref that caused the next
1102                //  entity to be pushed.
1103                //
1104                //  So we loop until we find a non-empty reader, or hit the main
1105                //  file entity. If we find one with some chars available, then break
1106                //  out and take that one.
1107                //
1108                if (!fCurReader->fNoMore)
1109                        break;
1110
1111                //
1112                //  The current one is hosed. So, if the reader stack is empty we
1113                //  are dead meat and can give up now.
1114                //
1115                if (fReaderStack->empty())
1116                {
1117                        return false;
1118                }
1119                // Else pop again and try it one more time
1120                delete fCurReader;
1121                fCurReader = fReaderStack->pop();
1122                fCurEntity = fEntityStack->pop();
1123        }
1124        return true;
1125}
1126
1127XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.