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