1 // Copyright (c) 1994 James Clark, 2000 Matthias Clasen
2 // See the file COPYING for copying permission.
3 
4 #ifdef __GNUG__
5 #pragma implementation
6 #endif
7 #include "splib.h"
8 #include "ParserState.h"
9 #include "InternalInputSource.h"
10 #include "MessageArg.h"
11 #include "macros.h"
12 #include "SgmlParser.h"
13 #include "IListIter.h"
14 #include "ParserMessages.h"
15 #include "Undo.h"
16 #include "Trie.h"
17 
18 #ifdef SP_NAMESPACE
19 namespace SP_NAMESPACE {
20 #endif
21 
22 const Location ParserState::nullLocation_;
23 sig_atomic_t ParserState::dummyCancel_ = 0;
24 
25 static const size_t eventSizes[] = {
26 #define EVENT(c, f) sizeof(c),
27 #include "events.h"
28 #undef EVENT
29 };
30 
31 static const size_t internalSizes[] = {
32   sizeof(InternalInputSource),
33   sizeof(OpenElement),
34   sizeof(UndoStartTag),
35   sizeof(UndoEndTag),
36   sizeof(UndoTransition)
37 };
38 
39 static
maxSize(const size_t * v,size_t n,size_t max=0)40 size_t maxSize(const size_t *v, size_t n, size_t max = 0)
41 {
42   for (size_t i = 0; i < n; i++) {
43     if (v[i] > max)
44       max = v[i];
45   }
46   return max;
47 }
48 
ParserState(const Ptr<EntityManager> & em,const ParserOptions & opt,unsigned subdocLevel,Phase finalPhase)49 ParserState::ParserState(const Ptr<EntityManager> &em,
50 			 const ParserOptions &opt,
51 			 unsigned subdocLevel,
52 			 Phase finalPhase)
53 : entityManager_(em),
54   options_(opt),
55   inInstance_(0),
56   inStartTag_(0),
57   inEndTag_(0),
58   keepingMessages_(0),
59   eventAllocator_(maxSize(eventSizes, SIZEOF(eventSizes)), 50),
60   internalAllocator_(maxSize(internalSizes, SIZEOF(internalSizes), EntityOrigin::allocSize), 50),
61   handler_(&eventQueue_),
62   subdocLevel_(subdocLevel),
63   inputLevel_(0),
64   specialParseInputLevel_(0),
65   markedSectionLevel_(0),
66   markedSectionSpecialLevel_(0),
67   currentMode_(proMode),
68   hadLpd_(0),
69   resultAttributeSpecMode_(0),
70   pass2_(0),
71   activeLinkTypesSubsted_(0),
72   allowPass2_(0),
73   hadPass2Start_(0),
74   pcdataRecovering_(0),
75   currentMarkup_(0),
76   cancelPtr_(&dummyCancel_),
77   finalPhase_(finalPhase),
78   hadAfdrDecl_(0),
79   instantiatedDtds_(0)
80 {
81 }
82 
inheritActiveLinkTypes(const ParserState & parent)83 void ParserState::inheritActiveLinkTypes(const ParserState &parent)
84 {
85   activeLinkTypes_ = parent.activeLinkTypes_;
86   activeLinkTypesSubsted_ = parent.activeLinkTypesSubsted_;
87 }
88 
allDone()89 void ParserState::allDone()
90 {
91   phase_ = noPhase;
92 }
93 
setPass2Start()94 void ParserState::setPass2Start()
95 {
96   ASSERT(inputLevel_ == 1);
97   if (hadPass2Start_)
98     return;
99   hadPass2Start_ = 1;
100   if (!pass2() && sd().link() && activeLinkTypes_.size() > 0) {
101     allowPass2_ = 1;
102     pass1Handler_.init(handler_);
103     handler_ = &pass1Handler_;
104     const InputSourceOrigin *p
105       = currentLocation().origin()->asInputSourceOrigin();
106     pass2StartOffset_= p->startOffset(currentLocation().index());
107   }
108   else {
109     allowPass2_ = 0;
110     currentInput()->willNotRewind();
111   }
112 }
113 
allLinkTypesActivated()114 void ParserState::allLinkTypesActivated()
115 {
116   if (activeLinkTypes_.size() == 0 && inputLevel_ == 1)
117     currentInput()->willNotRewind();
118 }
119 
maybeStartPass2()120 Boolean ParserState::maybeStartPass2()
121 {
122   if (pass2_ || !allowPass2_)
123     return 0;
124   handler_ = pass1Handler_.origHandler();
125   if (!nActiveLink() || pass1Handler_.hadError()) {
126     while (!pass1Handler_.empty()) {
127       if (cancelled())
128 	return 0;
129       pass1Handler_.get()->handle(*handler_);
130     }
131     InputSource *top = 0;
132     for (IListIter<InputSource> iter(inputStack_);
133 	 !iter.done();
134 	 iter.next())
135       top = iter.cur();
136     if (top)
137       top->willNotRewind();
138     return 0;
139   }
140   pass1Handler_.clear();
141   while (inputLevel_ > 1) {
142     InputSource *p = inputStack_.get();
143     inputLevel_--;
144     delete p;
145   }
146   // Caller will call allDone() if inputLevel_ is 0.
147   if (inputLevel_ == 0)
148     return 0;
149   if (!inputStack_.head()->rewind(*this)) {
150     inputLevel_ = 0;
151     delete inputStack_.get();
152     return 0;
153   }
154   inputStack_.head()->willNotRewind();
155   for (; pass2StartOffset_ > 0; pass2StartOffset_--)
156     if (inputStack_.head()->get(messenger()) == InputSource::eE) {
157       message(ParserMessages::pass2Ee);
158       inputLevel_ = 0;
159       delete inputStack_.get();
160       return 0;
161     }
162   specialParseInputLevel_ = 0;
163   markedSectionLevel_ = 0;
164   markedSectionSpecialLevel_ = 0;
165   currentMode_ = proMode;
166   hadLpd_ = 0;
167   allowPass2_ = 0;
168   hadPass2Start_ = 0;
169   currentMarkup_ = 0;
170   inputLevel_ = 1;
171   inInstance_ = 0;
172   inStartTag_ = 0;
173   inEndTag_ = 0;
174   defDtd_.clear();
175   defLpd_.clear();
176   dtd_[0].swap(pass1Dtd_);
177   dtd_.clear();
178   dsEntity_.clear();
179   currentDtd_.clear();
180   currentDtdConst_.clear();
181   phase_ = noPhase;
182   pass2_ = 1;
183   lpd_.clear();
184   allLpd_.clear();
185   return 1;
186 }
187 
referenceDsEntity(const Location & loc)188 Boolean ParserState::referenceDsEntity(const Location &loc)
189 {
190   if (dsEntity_.isNull())
191     return 0;
192   Ptr<EntityOrigin> origin
193     = EntityOrigin::make(internalAllocator(), dsEntity_, loc);
194   dsEntity_->dsReference(*this, origin);
195   dsEntity_.clear();
196   return inputLevel() > 1;
197 }
198 
startDtd(const StringC & name)199 void ParserState::startDtd(const StringC &name)
200 {
201   defDtd_ = new Dtd(name, dtd_.size() == 0);
202   defLpd_.clear();
203   for (size_t i = 0; i < options().includes.size(); i++) {
204     StringC name = options().includes[i];
205     syntax().entitySubstTable()->subst(name);
206     Text text;
207     text.addChars(syntax().reservedName(Syntax::rINCLUDE), Location());
208     Entity *entity
209       = new InternalTextEntity(name,
210 			       Entity::parameterEntity,
211 			       Location(),
212 			       text,
213 			       InternalTextEntity::none);
214     entity->setUsed();
215     defDtd_->insertEntity(entity);
216   }
217   size_t nEntities = instanceSyntax_->nEntities();
218   for (size_t i = 0; i < nEntities; i++) {
219     Text text;
220     text.addChar(instanceSyntax_->entityChar(i), Location());
221     Entity *entity
222       = new PredefinedEntity(instanceSyntax_->entityName(i),
223 				Location(),
224 				text);
225     defDtd_->insertEntity(entity);
226   }
227   currentDtd_ = defDtd_;
228   currentDtdConst_ = defDtd_;
229   currentMode_ = dsMode;
230 }
231 
enterTag(Boolean start)232 void ParserState::enterTag(Boolean start)
233 {
234   (start ? inStartTag_ : inEndTag_) = 1;
235 }
236 
leaveTag()237 void ParserState::leaveTag()
238 {
239   inStartTag_ = 0;
240   inEndTag_ = 0;
241 }
242 
inTag(Boolean & start) const243 Boolean ParserState::inTag(Boolean &start) const
244 {
245   start = inStartTag_;
246   return inStartTag_ || inEndTag_;
247 }
248 
endDtd()249 void ParserState::endDtd()
250 {
251   dtd_.push_back(defDtd_);
252   defDtd_.clear();
253   currentDtd_.clear();
254   currentDtdConst_.clear();
255   currentMode_ = proMode;
256 }
257 
startLpd(Ptr<Lpd> & lpd)258 void ParserState::startLpd(Ptr<Lpd> &lpd)
259 {
260   defLpd_ = lpd;
261   defDtd_ = defLpd_->sourceDtd();
262   currentDtd_ = defLpd_->sourceDtd();
263   currentDtdConst_ = defLpd_->sourceDtd();
264   currentMode_ = dsMode;
265 }
266 
endLpd()267 void ParserState::endLpd()
268 {
269   hadLpd_ = 1;
270   if (defLpd_->active())
271     lpd_.push_back(defLpd_);
272   allLpd_.push_back(defLpd_);
273   defLpd_.clear();
274   currentDtd_.clear();
275   currentDtdConst_.clear();
276   currentMode_ = proMode;
277 }
278 
popInputStack()279 void ParserState::popInputStack()
280 {
281   ASSERT(inputLevel_ > 0);
282   InputSource *p = inputStack_.get();
283 
284   if (handler_ != 0 && inputLevel_ > 1) {
285     handler_->inputClosed(p);
286   }
287 
288   inputLevel_--;
289   delete p;
290   if (specialParseInputLevel_ > 0 && inputLevel_ == specialParseInputLevel_)
291     currentMode_ = specialParseMode_;
292   if (currentMode_ == dsiMode
293       && inputLevel_ == 1
294       && markedSectionLevel_ == 0)
295     currentMode_ = dsMode;
296   if (inputLevelElementIndex_.size())
297     inputLevelElementIndex_.resize(inputLevelElementIndex_.size() - 1);
298 }
299 
setSd(ConstPtr<Sd> sd)300 void ParserState::setSd(ConstPtr<Sd> sd)
301 {
302   sd_ = sd;
303   mayDefaultAttribute_ = (sd_->omittag() || sd_->attributeDefault());
304   validate_ = sd_->typeValid();
305   implydefElement_ = sd_->implydefElement();
306   implydefAttlist_ = sd_->implydefAttlist();
307 }
308 
setSyntax(ConstPtr<Syntax> syntax)309 void ParserState::setSyntax(ConstPtr<Syntax> syntax)
310 {
311   syntax_ = syntax;
312   prologSyntax_ = syntax;
313   instanceSyntax_ = syntax;
314 }
315 
setSyntaxes(ConstPtr<Syntax> prologSyntax,ConstPtr<Syntax> instanceSyntax)316 void ParserState::setSyntaxes(ConstPtr<Syntax> prologSyntax,
317 			      ConstPtr<Syntax> instanceSyntax)
318 {
319   syntax_ = prologSyntax;
320   prologSyntax_ = prologSyntax;
321   instanceSyntax_ = instanceSyntax;
322 }
323 
pushInput(InputSource * in)324 void ParserState::pushInput(InputSource *in)
325 {
326   if (!in)
327     return;
328 
329   if (handler_ != 0 && inputLevel_ > 0) {
330     handler_->inputOpened(in);
331   }
332 
333   if (!syntax_.isNull() && syntax_->multicode())
334     in->setMarkupScanTable(syntax_->markupScanTable());
335   inputStack_.insert(in);
336   inputLevel_++;
337   if (specialParseInputLevel_ > 0 && inputLevel_ > specialParseInputLevel_)
338     currentMode_ = rcconeMode;	// mode for rcdata in an entity
339   else if (currentMode_ == dsMode)
340     currentMode_ = dsiMode;
341   if (inInstance_ && sd().integrallyStored())
342     inputLevelElementIndex_.push_back(tagLevel() ? currentElement().index() : 0);
343 }
344 
startMarkedSection(const Location & loc)345 void ParserState::startMarkedSection(const Location &loc)
346 {
347   markedSectionLevel_++;
348   markedSectionStartLocation_.push_back(loc);
349   if (currentMode_ == dsMode)
350     currentMode_ = dsiMode;
351   if (markedSectionSpecialLevel_)
352     markedSectionSpecialLevel_++;
353 }
354 
startSpecialMarkedSection(Mode mode,const Location & loc)355 void ParserState::startSpecialMarkedSection(Mode mode, const Location &loc)
356 {
357   markedSectionLevel_++;
358   markedSectionStartLocation_.push_back(loc);
359   specialParseInputLevel_ = inputLevel_;
360   markedSectionSpecialLevel_ = 1;
361   specialParseMode_ = currentMode_ = mode;
362 }
363 
endMarkedSection()364 void ParserState::endMarkedSection()
365 {
366   ASSERT(markedSectionLevel_ > 0);
367   markedSectionLevel_--;
368   markedSectionStartLocation_.resize(markedSectionStartLocation_.size()
369 					- 1);
370   if (markedSectionSpecialLevel_ > 0) {
371     markedSectionSpecialLevel_--;
372     if (markedSectionSpecialLevel_ > 0)
373       return;			// remain in imsMode
374     specialParseInputLevel_ = 0;
375     if (inInstance_)
376       currentMode_ = contentMode();
377     else
378       currentMode_ = dsiMode;
379   }
380   if (currentMode_ == dsiMode
381       && inputLevel_ == 1
382       && markedSectionLevel_ == 0)
383     currentMode_ = dsMode;
384 }
385 
pushElement(OpenElement * e)386 void ParserState::pushElement(OpenElement *e)
387 {
388   ContentState::pushElement(e);
389   pcdataRecovering_ = 0;
390   // the start tag of this element may have been implied by data
391   // inside a cdata or rcdata marked section
392   if (markedSectionSpecialLevel_ == 0) {
393     currentMode_ = contentMode();
394     if (e->requiresSpecialParse()) {
395       specialParseMode_ = currentMode_;
396       specialParseInputLevel_ = inputLevel_;
397     }
398   }
399 }
400 
401 // PCDATA was encountered somewhere where it was not allowed.
402 // Change the current mode to improve recovery.
403 
pcdataRecover()404 void ParserState::pcdataRecover()
405 {
406   switch (currentMode_) {
407   case econMode:
408     currentMode_ = mconMode;
409     break;
410   case econnetMode:
411     currentMode_ = mconnetMode;
412     break;
413   default:
414     break;
415   }
416   pcdataRecovering_ = 1;
417 }
418 
popSaveElement()419 OpenElement *ParserState::popSaveElement()
420 {
421   OpenElement *e = ContentState::popSaveElement();
422   // the end tag of this element may have been implied by data
423   // inside a cdata or rcdata marked section
424   if (markedSectionSpecialLevel_ == 0) {
425     currentMode_ = contentMode();
426     specialParseInputLevel_ = 0;
427   }
428   pcdataRecovering_ = 0;
429   return e;
430 }
431 
popElement()432 void ParserState::popElement()
433 {
434   delete popSaveElement();
435 }
436 
entityIsOpen(const EntityDecl * entityDecl) const437 Boolean ParserState::entityIsOpen(const EntityDecl *entityDecl) const
438 {
439   for (IListIter<InputSource> iter(inputStack_); !iter.done(); iter.next())
440     if (iter.cur()->currentLocation().origin()->entityDecl() == entityDecl)
441       return 1;
442   return 0;
443 }
444 
startInstance()445 void ParserState::startInstance()
446 {
447   if (!instanceSyntax_.isNull())
448     syntax_ = instanceSyntax_;
449   currentMode_ = econMode;
450 
451   currentDtd_.clear();
452   for (size_t i = 0; i < dtd_.size(); i++) {
453     if (shouldActivateLink(dtd_[i]->name())) {
454       if (nActiveLink() > 0) {
455 	message(ParserMessages::activeDocLink);
456 	break;
457       }
458       else if (!currentDtd_.isNull()) {
459 	message(ParserMessages::sorryActiveDoctypes);
460 	break;
461       }
462       else
463 	currentDtd_ = dtd_[i];
464     }
465   }
466   if (currentDtd_.isNull())
467     currentDtd_ = dtd_[0];
468   currentDtdConst_ = currentDtd_;
469 
470   startContent(currentDtd());
471   inInstance_ = 1;
472   if (sd().rank())
473     currentRank_.assign(currentDtd().nRankStem(), StringC());
474   currentAttributes_.clear();
475   currentAttributes_.resize(currentDtd().nCurrentAttribute());
476   idTable_.clear();
477 }
478 
lookupCreateId(const StringC & name)479 Id *ParserState::lookupCreateId(const StringC &name)
480 {
481   Id *id = idTable_.lookup(name);
482   if (!id) {
483     id = new Id(name);
484     idTable_.insert(id);
485   }
486   return id;
487 }
488 
489 ConstPtr<Entity>
lookupEntity(Boolean isParameter,const StringC & name,const Location & useLocation,Boolean referenced)490 ParserState::lookupEntity(Boolean isParameter,
491 			  const StringC &name,
492 			  const Location &useLocation,
493 			  Boolean referenced)
494 {
495   Dtd *dtd;
496   if (resultAttributeSpecMode_)
497     dtd = defComplexLpd().resultDtd().pointer();
498   else
499     dtd = currentDtd_.pointer();
500   if (dtd) {
501     Ptr<Entity> entity(dtd->lookupEntity(isParameter, name));
502     // Did we find it in pass1Dtd?
503     // Did we look at the defaultEntity?
504     if (!inInstance_ && pass2() && dtd->isBase()
505 	&& !resultAttributeSpecMode_
506 	&& (entity.isNull() || !entity->declInActiveLpd())) {
507       ConstPtr<Entity> entity1
508 	= pass1Dtd_->lookupEntity(isParameter, name);
509       if (!entity1.isNull() && entity1->declInActiveLpd()
510 	  && !entity1->defaulted()) {
511 	if (referenced)
512 	  noteReferencedEntity(entity1, 1, 0);
513 	return entity1;
514       }
515       else if (!entity.isNull()) {
516 	if (referenced)
517 	  noteReferencedEntity(entity, 0, 0);
518 	entity->setUsed();
519 	return entity;
520       }
521     }
522     else if (!entity.isNull()) {
523       entity->setUsed();
524       eventHandler().entityDefaulted
525 	(new (eventAllocator())EntityDefaultedEvent
526 	 (entity, useLocation));
527       return entity;
528     }
529     if (!isParameter) {
530       ConstPtr<Entity> entity(dtd->defaultEntity());
531       Boolean note = 0;
532       Boolean usedPass1 = 0;
533       if (!inInstance_ && pass2() && dtd->isBase()
534 	  && !resultAttributeSpecMode_
535 	  && (entity.isNull() || !entity->declInActiveLpd())) {
536 	if (referenced)
537 	  note = 1;
538 	ConstPtr<Entity> entity1 = pass1Dtd_->defaultEntity();
539 	if (!entity1.isNull() && entity1->declInActiveLpd()) {
540 	  usedPass1 = 1;
541 	  entity = entity1;
542 	}
543       }
544       if (!entity.isNull()) {
545 	Boolean mustCopy = 1;
546 	if (inInstance_) {
547 	  ConstPtr<Entity> tem
548 	    = instanceDefaultedEntityTable_.lookupConst(name);
549 	  if (!tem.isNull()) {
550 	    entity = tem;
551 	    mustCopy = 0;
552 	  }
553 	}
554 	if (mustCopy) {
555 	  Ptr<Entity> p(entity->copy());
556 	  p->setName(name);
557 	  p->generateSystemId(*this);
558 	  p->setDefaulted();
559 	  entity = p;
560 	  if (inInstance_) {
561 	    instanceDefaultedEntityTable_.insert(p);
562 	    eventHandler().entityDefaulted(new (eventAllocator())
563 					   EntityDefaultedEvent(entity,
564 								useLocation));
565 	  }
566 	  else
567 	    dtd->insertEntity(p);
568 	}
569 	if (note)
570 	  noteReferencedEntity(entity, usedPass1, 1);
571       }
572       else
573 	entity = undefinedEntityTable_.lookupConst(name);
574       return entity;
575     }
576   }
577   return (Entity *)0;
578 }
579 
createUndefinedEntity(const StringC & name,const Location & loc)580 ConstPtr<Entity> ParserState::createUndefinedEntity(const StringC &name, const Location &loc)
581 {
582   ExternalId extid;
583   Ptr<Entity> entity(new ExternalTextEntity(name, EntityDecl::generalEntity,
584 					    loc, extid));
585   undefinedEntityTable_.insert(entity);
586   entity->generateSystemId(*this);
587   return entity;
588 }
589 
noteReferencedEntity(const ConstPtr<Entity> & entity,Boolean foundInPass1Dtd,Boolean lookedAtDefault)590 void ParserState::noteReferencedEntity(const ConstPtr<Entity> &entity,
591 				       Boolean foundInPass1Dtd,
592 				       Boolean lookedAtDefault)
593 {
594   LpdEntityRef ref;
595   ref.entity = entity;
596   ref.lookedAtDefault = lookedAtDefault;
597   ref.foundInPass1Dtd = foundInPass1Dtd;
598   LpdEntityRef *old = lpdEntityRefs_.lookup(ref);
599   if (!old)
600     lpdEntityRefs_.insert(new LpdEntityRef(ref));
601 }
602 
603 // Compare entity definitions.
604 // e1 is the original (will not be an external non-text entity).
605 // FIXME should look at generated sysids as well.
606 static
sameEntityDef(const Entity * e1,const Entity * e2)607 Boolean sameEntityDef(const Entity *e1, const Entity *e2)
608 {
609   if (e1->dataType() != e2->dataType())
610     return 0;
611   const InternalEntity *i1 = e1->asInternalEntity();
612   const InternalEntity *i2 = e2->asInternalEntity();
613   if (i1) {
614     if (!i2)
615       return 0;
616     if (i1->string() != i2->string())
617       return 0;
618     return 1;
619   }
620   else if (i2)
621     return 0;
622   const ExternalEntity *x1 = e1->asExternalEntity();
623   const ExternalEntity *x2 = e2->asExternalEntity();
624   const StringC *s1 = x1->externalId().systemIdString();
625   const StringC *s2 = x2->externalId().systemIdString();
626   if (s1) {
627     if (!s2)
628       return 0;
629     if (*s1 != *s2)
630       return 0;
631   }
632   else if (s2)
633     return 0;
634   s1 = x1->externalId().publicIdString();
635   s2 = x2->externalId().publicIdString();
636   if (s1) {
637     if (!s2)
638       return 0;
639     if (*s1 != *s2)
640       return 0;
641   }
642   else if (s2)
643     return 0;
644   return 1;
645 }
646 
checkEntityStability()647 void ParserState::checkEntityStability()
648 {
649   LpdEntityRefSetIter iter(lpdEntityRefs_);
650   LpdEntityRef *ref;
651   while ((ref = iter.next()) != 0) {
652     ConstPtr<Entity> entity
653       = dtd_[0]->lookupEntity(ref->entity->declType()
654 			      == Entity::parameterEntity,
655 			      ref->entity->name());
656     if (entity.isNull() && ref->lookedAtDefault)
657       entity = dtd_[0]->defaultEntity();
658     if (entity.isNull()
659 	? ref->foundInPass1Dtd
660 	: !sameEntityDef(ref->entity.pointer(), entity.pointer()))
661       message(((ref->entity->declType()
662 		== Entity::parameterEntity)
663 	       ? ParserMessages::unstableLpdParameterEntity
664 	       : ParserMessages::unstableLpdGeneralEntity),
665 	      StringMessageArg(ref->entity->name()));
666   }
667   {
668     // Ensure that the memory is released.
669     LpdEntityRefSet tem;
670     lpdEntityRefs_.swap(tem);
671   }
672 }
673 
appendCurrentRank(StringC & str,const RankStem * stem) const674 Boolean ParserState::appendCurrentRank(StringC &str, const RankStem *stem)
675      const
676 {
677   const StringC &suffix = currentRank_[stem->index()];
678   if (suffix.size() > 0) {
679     str += suffix;
680     return 1;
681   }
682   return 0;
683 }
684 
setCurrentRank(const RankStem * stem,const StringC & suffix)685 void ParserState::setCurrentRank(const RankStem *stem, const StringC &suffix)
686 {
687   currentRank_[stem->index()] = suffix;
688 }
689 
getCurrentToken(const SubstTable * subst,StringC & str) const690 void ParserState::getCurrentToken(const SubstTable *subst,
691 				  StringC &str) const
692 {
693   InputSource *in = currentInput();
694   const Char *p = in->currentTokenStart();
695   size_t count = in->currentTokenLength();
696   str.resize(count);
697   StringC::iterator s = str.begin();
698   for (; count > 0; --count)
699     *s++ = (*subst)[*p++];
700 }
701 
queueMessage(MessageEvent * event)702 void ParserState::queueMessage(MessageEvent *event)
703 {
704   if (cancelled()) {
705     delete event;
706     return;
707   }
708   if (keepingMessages_)
709     keptMessages_.append(event);
710   else
711     handler_->message(event);
712 }
713 
releaseKeptMessages()714 void ParserState::releaseKeptMessages()
715 {
716   keepingMessages_ = 0;
717   while (!keptMessages_.empty()) {
718     if (cancelled()) {
719       allDone();
720       return;
721     }
722     handler_->message(keptMessages_.get());
723   }
724 }
725 
discardKeptMessages()726 void ParserState::discardKeptMessages()
727 {
728   keepingMessages_ = 0;
729   keptMessages_.clear();
730 }
731 
initMessage(Message & msg)732 void ParserState::initMessage(Message &msg)
733 {
734   if (inInstance()) {
735     StringC rniPcdata = syntax().delimGeneral(Syntax::dRNI);
736     rniPcdata += syntax().reservedName(Syntax::rPCDATA);
737     getOpenElementInfo(msg.openElementInfo, rniPcdata);
738   }
739   msg.loc = currentLocation();
740 }
741 
dispatchMessage(Message & msg)742 void ParserState::dispatchMessage(Message &msg)
743 {
744   queueMessage(new MessageEvent(msg));
745 }
746 
dispatchMessage(const Message & msg)747 void ParserState::dispatchMessage(const Message &msg)
748 {
749   queueMessage(new MessageEvent(msg));
750 }
751 
752 AttributeList *
allocAttributeList(const ConstPtr<AttributeDefinitionList> & def,unsigned i)753 ParserState::allocAttributeList(const ConstPtr<AttributeDefinitionList> &def,
754 				unsigned i)
755 {
756   if (i < attributeLists_.size())
757     attributeLists_[i]->init(def);
758   else {
759     attributeLists_.resize(i + 1);
760     attributeLists_[i] = new AttributeList(def);
761   }
762   return attributeLists_[i].pointer();
763 }
764 
activateLinkType(const StringC & name)765 void ParserState::activateLinkType(const StringC &name)
766 {
767   if (!hadPass2Start_ && !pass2_)
768     activeLinkTypes_.push_back(name);
769   else
770     message(ParserMessages::linkActivateTooLate);
771 }
772 
shouldActivateLink(const StringC & name) const773 Boolean ParserState::shouldActivateLink(const StringC &name) const
774 {
775   if (!activeLinkTypesSubsted_) {
776     for (size_t i = 0; i < activeLinkTypes_.size(); i++)
777       syntax().generalSubstTable()->subst(
778 #ifndef HAVE_MUTABLE
779 	((ParserState *)this)->
780 #endif
781 	activeLinkTypes_[i]
782 	);
783 #ifndef HAVE_MUTABLE
784     ((ParserState *)this)->
785 #endif
786       activeLinkTypesSubsted_ = 1;
787   }
788   for (size_t i = 0; i < activeLinkTypes_.size(); i++)
789     if (name == activeLinkTypes_[i])
790       return 1;
791   return 0;
792 }
793 
lookupDtd(const StringC & name)794 Ptr<Dtd> ParserState::lookupDtd(const StringC &name)
795 {
796   for (size_t i = 0; i < dtd_.size(); i++)
797     if (dtd_[i]->name() == name)
798       return dtd_[i];
799   return Ptr<Dtd>();
800 }
801 
lookupLpd(const StringC & name) const802 ConstPtr<Lpd> ParserState::lookupLpd(const StringC &name) const
803 {
804   for (size_t i = 0; i < allLpd_.size(); i++)
805     if (allLpd_[i]->name() == name)
806       return allLpd_[i];
807   return ConstPtr<Lpd>();
808 }
809 
getAttributeNotation(const StringC & name,const Location &)810 ConstPtr<Notation> ParserState::getAttributeNotation(const StringC &name,
811 						     const Location &)
812 {
813   ConstPtr<Notation> notation;
814   if (haveCurrentDtd()) {
815     notation = currentDtd().lookupNotation(name);
816     if (notation.isNull() && sd().implydefNotation()) {
817       Ptr<Notation> nt = new Notation(name,
818 				      currentDtd().namePointer(),
819 				      currentDtd().isBase());
820       ExternalId id;
821       nt->setExternalId(id, Location());
822       nt->generateSystemId(*this);
823       nt->setAttributeDef(currentDtdNonConst().implicitNotationAttributeDef());
824       currentDtdNonConst().insertNotation(nt);
825       notation = currentDtd().lookupNotation(name);
826     }
827   }
828   else if (resultAttributeSpecMode_) {
829     const Dtd *resultDtd = defComplexLpd().resultDtd().pointer();
830     if (!resultDtd)
831       return 0;
832     notation = resultDtd->lookupNotation(name);
833   }
834   return notation;
835 }
836 
getAttributeEntity(const StringC & str,const Location & loc)837 ConstPtr<Entity> ParserState::getAttributeEntity(const StringC &str,
838 						 const Location &loc)
839 {
840   ConstPtr<Entity> entity = lookupEntity(0, str, loc, 0);
841   if (!entity.isNull()
842       && entity->defaulted()
843       && options().warnDefaultEntityReference) {
844     setNextLocation(loc);
845     message(ParserMessages::defaultEntityInAttribute,
846 	    StringMessageArg(str));
847   }
848   return entity;
849 }
850 
defineId(const StringC & str,const Location & loc,Location & prevLoc)851 Boolean ParserState::defineId(const StringC &str, const Location &loc,
852 			      Location &prevLoc)
853 {
854   if (!inInstance() || !validate())
855     return 1;
856   Id *id = lookupCreateId(str);
857   if (id->defined()) {
858     prevLoc = id->defLocation();
859     return 0;
860   }
861   id->define(loc);
862   return 1;
863 }
864 
noteIdref(const StringC & str,const Location & loc)865 void ParserState::noteIdref(const StringC &str, const Location &loc)
866 {
867   if (!inInstance() || !options().errorIdref || !validate())
868     return;
869   Id *id = lookupCreateId(str);
870   if (!id->defined())
871     id->addPendingRef(loc);
872 }
873 
noteCurrentAttribute(size_t i,AttributeValue * value)874 void ParserState::noteCurrentAttribute(size_t i, AttributeValue *value)
875 {
876   if (inInstance())
877     currentAttributes_[i] = value;
878 }
879 
getCurrentAttribute(size_t i) const880 ConstPtr<AttributeValue> ParserState::getCurrentAttribute(size_t i) const
881 {
882   if (!inInstance())
883     return ConstPtr<AttributeValue>();
884   return currentAttributes_[i];
885 }
886 
attributeSyntax() const887 const Syntax &ParserState::attributeSyntax() const
888 {
889   return syntax();
890 }
891 
instantiateDtd(Ptr<Dtd> & dtd)892 unsigned ParserState::instantiateDtd(Ptr<Dtd> &dtd)
893 {
894   if (!dtd->isInstantiated()) {
895     dtd->instantiate();
896     if (instantiatedDtds_ == sd().concur())
897       message(ParserMessages::concurrentInstances,
898               NumberMessageArg(sd().concur()));
899     instantiatedDtds_++;
900   }
901   return instantiatedDtds_;
902 }
903 
904 #ifdef SP_NAMESPACE
905 }
906 #endif
907