1 /* 2 * The contents of this file are subject to the Mozilla Public 3 * License Version 1.1 (the "License"); you may not use this file 4 * except in compliance with the License. You may obtain a copy of 5 * the License at http://www.mozilla.org/MPL/ 6 * 7 * Software distributed under the License is distributed on an "AS 8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 9 * implied. See the License for the specific language governing 10 * rights and limitations under the License. 11 * 12 * The Original Code is the Sablotron XSLT Processor. 13 * 14 * The Initial Developer of the Original Code is Ginger Alliance Ltd. 15 * Portions created by Ginger Alliance are Copyright (C) 2000-2002 16 * Ginger Alliance Ltd. All Rights Reserved. 17 * 18 * Contributor(s): 19 * 20 * Alternatively, the contents of this file may be used under the 21 * terms of the GNU General Public License Version 2 or later (the 22 * "GPL"), in which case the provisions of the GPL are applicable 23 * instead of those above. If you wish to allow use of your 24 * version of this file only under the terms of the GPL and not to 25 * allow others to use your version of this file under the MPL, 26 * indicate your decision by deleting the provisions above and 27 * replace them with the notice and other provisions required by 28 * the GPL. If you do not delete the provisions above, a recipient 29 * may use your version of this file under either the MPL or the 30 * GPL. 31 */ 32 33 #ifndef TreeHIncl 34 #define TreeHIncl 35 36 // GP: clean 37 38 #include "base.h" 39 #include "verts.h" 40 #include "datastr.h" 41 #include "output.h" 42 43 #ifdef HAVE_CONFIG_H 44 #include <config.h> 45 #endif 46 47 class RootNode; 48 49 #define TREE_ARENA_SIZE 0x10000 50 #define TREE_DICT_LOGSIZE 10 51 52 //atts cache used for parsing 53 class AttsCache: public PList<Attribute*> 54 { 55 public: AttsCache()56 AttsCache(): keep(FALSE) {}; ~AttsCache()57 ~AttsCache() {if (!keep) freeall(FALSE);}; keepThem()58 void keepThem() { keep = TRUE; }; 59 Attribute* find(XSL_ATT what); 60 Attribute* find(const QName& attName); 61 int findNdx(const QName& attName); 62 private: 63 Bool keep; 64 }; 65 66 //_TH_ v 67 68 /**************************************** 69 T m p L i s t 70 ****************************************/ 71 72 class TmpList : public PList<Vertex *> 73 { 74 public: 75 TmpList(); 76 ~TmpList(); 77 void append(void *what); 78 void rm(int n); 79 void freeall(Bool a); 80 // void freeall(SablotSituation s); 81 // void dump(SablotSituation sit, int p=0); 82 void dump(int p=0); 83 int findNum(void *p) const; 84 void rmP(void *p); 85 }; 86 //_TH_ ^ 87 88 class StylesheetStructure; 89 90 // 91 // SubtreeInfo 92 // holds information about a document which is (1) xsl:included, 93 // (2) xsl:imported or (3) included as external entity to form a part of 94 // the tree. The SubtreeInfo records are linked to form a tree, each one 95 // holds the base URI, pointer to the associated StylesheetStructure 96 // (only exists for xsl:imports) and 'dependency type' which is 97 // (1), (2) or (3) above (with values XSL_INCLUDE, XSL_IMPORT and XSL_NONE, 98 // respectively). 99 // 100 101 class SubtreeInfo 102 { 103 public: SubtreeInfo(const Str & baseURI_,XSL_OP dependency_,StylesheetStructure * structure_,Bool inline_)104 SubtreeInfo(const Str& baseURI_, XSL_OP dependency_, 105 StylesheetStructure* structure_, Bool inline_) : 106 #ifdef SABLOT_DEBUGGER 107 nextBPIndex(-2), 108 #endif 109 baseURI(baseURI_), dependency(dependency_), inlineVal(inline_), 110 structure(structure_), parentSubtree(NULL), masterSubtree(NULL) {}; 111 ~SubtreeInfo(); getBaseURI()112 Str& getBaseURI() 113 { return baseURI; } getDependency()114 XSL_OP getDependency() 115 { return dependency; } getStructure()116 StylesheetStructure* getStructure() 117 { return structure; } getParentSubtree()118 SubtreeInfo* getParentSubtree() 119 { return parentSubtree; } setParentSubtree(SubtreeInfo * parentSubtree_)120 void setParentSubtree(SubtreeInfo *parentSubtree_) 121 { parentSubtree = parentSubtree_; } getMasterSubtree()122 SubtreeInfo* getMasterSubtree() 123 { return masterSubtree ? masterSubtree : this; }; setMasterSubtree(SubtreeInfo * mstr)124 void setMasterSubtree(SubtreeInfo *mstr) 125 { masterSubtree = mstr; }; isInline()126 Bool isInline() { return inlineVal; }; getExcludedNS()127 UriList &getExcludedNS() { return excludedNS; }; 128 void pushNamespaceMarks(); 129 void popNamespaceMarks(); getExtensionNS()130 UriList &getExtensionNS() { return extensionNS; }; 131 132 // this is not thread safe, but it is used by the debugger only, 133 // what is single threaded by default 134 #ifdef SABLOT_DEBUGGER 135 int nextBPIndex; 136 #endif 137 138 private: 139 Str baseURI; 140 XSL_OP dependency; 141 Bool inlineVal; 142 StylesheetStructure* structure; 143 //was not used; now it hold pointer to the closest non-inline tree 144 SubtreeInfo* parentSubtree; 145 SubtreeInfo* masterSubtree; 146 UriList excludedNS; 147 UriList extensionNS; 148 List<int> excludedCount; 149 List<int> extensionCount; 150 }; 151 152 // the list of subtrees 153 // although a list, it also has a rooted tree structure 154 155 class SubtreeList : public PList<SubtreeInfo*> 156 { 157 public: SubtreeList()158 SubtreeList() 159 : currentSub(NULL) 160 { 161 }; 162 163 // append subtree to list, make it current in the tree structure push(SubtreeInfo * newSub)164 void push(SubtreeInfo* newSub) 165 { 166 append(newSub); 167 NZ(newSub) -> setParentSubtree(currentSub); 168 currentSub = newSub; 169 }; 170 171 // go one level higher in the tree structure (but keep subtree in list!) pop()172 SubtreeInfo* pop() 173 { 174 sabassert(currentSub); 175 SubtreeInfo *was = currentSub; 176 currentSub = currentSub -> getParentSubtree(); 177 return was; 178 }; 179 180 // get current subtree getCurrent()181 SubtreeInfo* getCurrent() 182 { 183 return currentSub; 184 } 185 findAmongPredecessors(const Str & uri)186 SubtreeInfo* findAmongPredecessors(const Str& uri) 187 { 188 sabassert(currentSub); 189 for (SubtreeInfo* i = currentSub -> getParentSubtree(); 190 i; 191 i = i -> getParentSubtree() ) 192 if (i -> getBaseURI() == uri) 193 return i; 194 return NULL; 195 } 196 197 private: 198 SubtreeInfo* currentSub; 199 }; 200 201 // 202 // 203 // VarDirectory 204 // list of top-level variables and params used to find those of 205 // highest import precedence, while checking for duplicates in 206 // each source document 207 // 208 209 class VarDirectoryItem 210 { 211 public: VarDirectoryItem(QName & name_,XSLElement * varElem_)212 VarDirectoryItem(QName &name_, XSLElement *varElem_) 213 : varElem(varElem_), name(name_) 214 {}; getElement()215 XSLElement* getElement() 216 { return varElem; } setElement(XSLElement * varElem_)217 void setElement(XSLElement *varElem_) 218 { varElem = varElem_; } getName()219 const QName &getName() 220 { return name; } setName(const QName & name_)221 void setName(const QName &name_) 222 { name = name_; } 223 private: 224 XSLElement *varElem; 225 QName name; 226 }; 227 228 class VarDirectory : public PList<VarDirectoryItem*> 229 { 230 public: 231 VarDirectory(); 232 // kills all VarDirectoryItems 233 ~VarDirectory(); 234 // find the var/param of the given QName (relative to the stylesheet 235 // dictionary), NULL if not found 236 XSLElement* find(QName& name); 237 // insert the var/param (overwriting any previous entry of the same name) 238 eFlag insert(Sit S, QName &name, XSLElement* var); 239 private: 240 // find index of entry with the given QName, -1 if not found 241 int findNdx(const QName& name); report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2)242 void report(Sit S, MsgType type, MsgCode code, 243 const Str &arg1, const Str &arg2) const 244 { S.message(type, code, arg1, arg2); } 245 }; 246 247 class SpaceNameList : public PList<EQName*> 248 { 249 public: 250 Bool findName(EQName &ename, double &prio); 251 }; 252 253 /**************************************** 254 StylesheetStructure 255 256 Holds information about the stylesheet tree (pointers 257 to template rules etc.) 258 Created when a document is parsed as stylesheet. 259 The 'imports' list points to structures for all 260 imported stylesheets (these form a tree). 261 ****************************************/ 262 263 class StylesheetStructure 264 { 265 public: StylesheetStructure(int importPrecedence_)266 StylesheetStructure(int importPrecedence_) 267 : importPrecedence(importPrecedence_), topLevelFound(false) {}; ~StylesheetStructure()268 ~StylesheetStructure() 269 { 270 importChildren.freeall(FALSE); 271 // rulesList.freeall(FALSE); - done in ~RuleSList 272 strippedNamesList.freeall(FALSE); 273 preservedNamesList.freeall(FALSE); 274 } 275 276 /*** 277 findBestRule 278 279 Finds the rule of highest import precedence and highest priority 280 that is satisfied by the current node of the context c. If 281 several rules are satisfied, returns the one that occurs last. 282 The current mode is given in currMode (may be NULL). The result, 283 a pointer to the template rule node, is returned in ret. 284 285 If no rule is found, asks the structures for imported stylesheets. 286 If this doesn't yield a match too, returns NULL. 287 288 If 'importsOnly' is true, looks only at the imported stylesheets. 289 290 ASSUMPTION: 'rules' is sorted by priority in reverse order. 291 ***/ 292 293 eFlag findBestRule(Sit S, XSLElement *&ret, Context *c, 294 QName *currMode, Bool importsOnly); 295 296 // finds the rule of given name with highest import precedence 297 // 't' is the stylesheet 298 XSLElement* findRuleByName(Tree& t, QName &q); 299 300 // return the list of template rules from this structure rules()301 RuleSList &rules() 302 { return rulesList; } 303 304 // insert a template rule into 'rulesList' 305 // the rule is given as a pointer to the corresponding xsl:template 306 eFlag insertRule(Sit S, XSLElement *tmpl); 307 308 // add structure for imported stylesheet addImportStructure(Sit S,StylesheetStructure * imported)309 void addImportStructure(Sit S, StylesheetStructure *imported) 310 //{ importChildren.append(imported); } 311 { importChildren.insertBefore(imported, 0); } 312 313 // get the import precedence associated with this imported subtree getImportPrecedence()314 int getImportPrecedence() 315 { return importPrecedence; } 316 317 //set the import precedence setImportPrecedence(int prec)318 void setImportPrecedence(int prec) 319 { importPrecedence = prec; } 320 strippedNames()321 SpaceNameList &strippedNames() { return strippedNamesList; } preservedNames()322 SpaceNameList &preservedNames() { return preservedNamesList; } 323 Bool findStrippedName(EQName &ename, int &prec, double &prio); 324 Bool findPreservedName(EQName &ename, int &prec, double &prio); 325 Bool hasAnyStripped(); 326 Bool hasAnyPreserved(); getTopLevelFound()327 Bool getTopLevelFound() { return topLevelFound; }; setTopLevelFound(Bool val)328 void setTopLevelFound(Bool val) { topLevelFound = val; } 329 private: 330 PList<StylesheetStructure*> importChildren; 331 RuleSList rulesList; 332 SpaceNameList strippedNamesList; 333 SpaceNameList preservedNamesList; 334 int importPrecedence; 335 Bool topLevelFound; //used during the xslt parse only, thread safe report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2)336 void report(Sit S, MsgType type, MsgCode code, 337 const Str &arg1, const Str &arg2) const 338 { S.message(type, code, arg1, arg2); } 339 }; 340 341 /**************************************************************** 342 343 AttributeSets 344 345 *****************************************************************/ 346 347 class AttSetMember 348 { 349 public: AttSetMember(QName & attName_)350 AttSetMember(QName &attName_) 351 : attDef(NULL), redefinition(NULL), 352 attName(attName_), precedence(-1) {}; getAttributeDef()353 XSLElement* getAttributeDef() 354 {return attDef;} 355 // see if there was multiple definition with highest import precedence getRedefinition()356 XSLElement* getRedefinition() 357 {return redefinition;} 358 getAttName()359 QName &getAttName() 360 { return attName; } 361 // sets to a new value if importPrecedence is smaller (stronger) 362 // sets 'redefinition' if equal precedence 363 void set(XSLElement *newAttDef); 364 private: 365 XSLElement 366 *attDef, 367 *redefinition; 368 QName attName; 369 int precedence; 370 }; 371 372 class AttSet : public PList<AttSetMember*> 373 { 374 public: 375 AttSet(QName &name_); 376 ~AttSet(); 377 void insertAttributeDef(XSLElement *attDef, QName &attName); 378 void insertUses(QName &usedSet); getName()379 const QName& getName() 380 { return name; } 381 eFlag checkRedefinitions(Sit S); 382 // execute the attribute set 383 eFlag execute(Sit S, Context *c, Tree& sheet, 384 QNameList& history, Bool resolvingGlobals); 385 int findNdx(QName &attName); 386 private: 387 QName name; 388 QNameList usedSets; report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2)389 void report(Sit S, MsgType type, MsgCode code, 390 const Str &arg1, const Str &arg2) const 391 { S.message(type, code, arg1, arg2); } 392 }; 393 394 class AttSetList : public PList<AttSet*> 395 { 396 public: 397 AttSetList(); 398 ~AttSetList(); 399 // check all attribute sets for multiply defined attributes 400 eFlag checkRedefinitions(Sit S); 401 // insert an AttSet named 'name' and return pointer (the set may already exist) 402 AttSet* insert(QName& name); 403 eFlag executeAttSet(Sit S, QName &name, Context *c, Tree &sheet, 404 QNameList& history, Bool resolvingGlobals); findByName(const QName & name)405 AttSet* findByName(const QName &name) const 406 { int ndx = findNdx(name); return (ndx == -1) ? NULL : (*this)[ndx]; } 407 private: 408 int findNdx(const QName &name) const; report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2)409 void report(Sit S, MsgType type, MsgCode code, 410 const Str &arg1, const Str &arg2) const 411 { S.message(type, code, arg1, arg2); } 412 }; 413 414 // 415 // 416 // AliasItem 417 // records one alias for use in AliasPrecList 418 // holds the key-value pair, checks import precedence on setting 419 // 420 // 421 422 class AliasItem 423 { 424 public: AliasItem()425 AliasItem() 426 :key(UNDEF_PHRASE), value(UNDEF_PHRASE), prefix(UNDEF_PHRASE), 427 precedence(-1), redefinition(NULL) {}; getKey()428 Phrase getKey() {return key;} getValue()429 Phrase getValue() {return value;} getPrefix()430 Phrase getPrefix() {return prefix;} 431 432 // see if there was multiple definition with highest import precedence getRedefinition()433 XSLElement* getRedefinition() 434 {return redefinition;} 435 // sets to a new value if newPrecedence is smaller (stronger) 436 // sets 'redefinition' if precedences were equal (typically an error) 437 // but sets key/value anyway 438 void set(Phrase newKey, Phrase newValue, Phrase newPrefix, 439 int newPrecedence, XSLElement *source); 440 private: 441 Phrase key, value, prefix; 442 int precedence; 443 XSLElement *redefinition; 444 }; 445 446 // 447 // 448 // AliasList 449 // list of namespace aliases defined by xsl:namespace-alias 450 // checks import precedence when inserting 451 // 452 // 453 454 class AliasList : public PList<AliasItem*> 455 { 456 public: 457 // find the value of the element with the given key 458 Phrase find(Phrase) const; 459 // insert an alias (or overwrite old if precedence is not weaker) 460 void insertAlias(Phrase key, Phrase value, Phrase prefix, int precedence, 461 XSLElement *source); 462 eFlag checkRedefinitions(Sit S, Tree &sheet); 463 private: 464 // find the index of the element with the given key 465 int findNdx(Phrase) const; report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2)466 void report(Sit S, MsgType type, MsgCode code, const Str &arg1, 467 const Str &arg2) const 468 { S.message(type, code, arg1, arg2); } 469 }; 470 471 472 473 474 /**************************************** 475 T r e e 476 477 Represents a XML tree in memory. Created by parsing a document. 478 A tree can be used in several processing sessions and even by 479 several threads, so it SHOULD NOT CHANGE during processing (in other 480 words, it holds information which is static with respect to processing). 481 ****************************************/ 482 483 class Tree 484 { 485 public: 486 // pass the URI of the tree's document 487 // isXSL_ = TRUE iff the tree represents a stylesheet 488 Tree(const Str& uri, Bool isXSL_); 489 ~Tree(); 490 BOOL XSLTree; 491 eFlag appendVertex(Sit S, Vertex *); 492 Vertex* popVertex(); 493 Vertex* appendText(Sit S, char *, int); 494 eFlag parseFinished(Sit S); 495 void dump(); 496 Vertex *stackTop; pendingNS()497 NSList &pendingNS() {return *(pendingNSList.last());}; 498 void dropCurrentElement(Vertex *); 499 void flushPendingText(); 500 Element& dummyElement() const; 501 HashTable& dict(); 502 SabArena& getArena(); 503 const QName& getTheEmptyQName() const; stdPhrase(StandardPhrase phrase_)504 Phrase stdPhrase(StandardPhrase phrase_) const 505 { 506 sabassert(phrase_ <= PHRASE_LAST); 507 return stdPhrases[phrase_]; 508 }; 509 Bool cmpQNames(const QName &q1, const QName &q2) const; 510 Bool cmpQNamesForeign(const QName &q, const HashTable& dictForeign, const QName &qForeign); 511 Bool cmpQNameStrings(const QName &q, const Str& uri, const Str& local); 512 void expandQ(const QName& q, EQName &expanded); 513 void expandQStr(const QName& q, Str &expName); 514 const Str& expand(Phrase ph); 515 Phrase unexpand(const Str& strg); getRoot()516 RootNode& getRoot() const {return* NZ(root);} 517 eFlag serialize(Sit S, char *& result); 518 eFlag serializeNode(Sit S, Element *v, char *& result); 519 void makeStamps(); 520 521 //// methods to access stylesheet structure 522 523 // finds the best matching rule 524 // see StylesheetStructure::findBestRule for description 525 eFlag findBestRule(Sit S, XSLElement *&ret, Context *c, 526 QName *currMode, Bool importsOnly, 527 SubtreeInfo *subtree = NULL); 528 529 // finds the rule of given name with highest import precedence 530 XSLElement* findRuleByName(QName &q); 531 532 533 // returns the list of attribute sets defined attSets()534 AttSetList &attSets() 535 { return attSetList; } 536 537 // The list of namespace aliases aliases()538 AliasList &aliases() 539 { return aliasesList; } 540 541 // Output definition holding compiled information from various 542 // xsl:output elements 543 // At runtime, this is copied by Processor and defaults are provided 544 // FOR THE COPY (cannot be guessed at parse time) 545 OutputDefinition outputDef; 546 547 // this is called after each element has been parsed in 548 // used to compile StylesheetStructure (template rule pointers), process 549 // includes/imports, etc. 550 eFlag processVertexAfterParse(Sit S, Vertex *v, TreeConstructer* tc); 551 552 // creates this tree by parsing the given dataline 553 eFlag parse(Sit S, DataLine *d); 554 555 // returns in 'result' the list of elements matching the given expression 556 // used for key creation 557 eFlag getMatchingList(Sit S, Expression& match, Context& result); 558 559 // find global variable in directory findVarInDirectory(QName & name)560 XSLElement* findVarInDirectory(QName &name) 561 { return toplevelVars.find(name); } 562 563 // the list of temporary nodes which belong to the tree but are not part 564 // of it (used for cleaning up in SDOM) 565 TmpList tmpList; 566 567 // EXTENSION NAMESPACES 568 // FIXME: efficiency? 569 // FIXME: extension URIs are only valid outside imports/includes!! 570 Bool isExtensionUri(Phrase uri); 571 // MAIN METHODS TO RECORD THE PARSING OF EXTERNAL ENTITIES/INCLUDES/IMPORTS 572 // start a subtree, recording its base URI. 573 // 'dependency' is XSL_NONE (external entity), XSL_INCLUDE or XSL_IMPORT 574 eFlag startSubtree(Sit S, const Str& baseURI, XSL_OP dependency, 575 Bool isInline = FALSE); 576 // end a subtree 577 eFlag endSubtree(Sit S, XSL_OP dependency); 578 // get the tree's URI getURI()579 const Str& getURI() 580 { 581 return subtrees[0] -> getBaseURI(); 582 } 583 // resolve all global variables before starting execute 584 // called from Processor::resolveGlobals 585 //eFlag resolveGlobals(Sit S, Context *c, Processor *proc); 586 //unparsed entties storge 587 void setUnparsedEntityUri(Str &name, Str &uri); 588 Str* getUnparsedEntityUri(Str &name); 589 int stripped; 590 Bool hasAnyStrippedName(); 591 Bool hasAnyPreservedName(); 592 Bool findPreservedName(EQName &name, int &prec, double &prio); 593 Bool findStrippedName(EQName &name, int &prec, double &prio); 594 Element* findStylesheet(Daddy& d); 595 eFlag pushPendingNS(Sit S, Tree* srcTree, NSList &other); 596 eFlag popPendingNS(Sit S); getRootSubtree()597 SubtreeInfo* getRootSubtree() { return subtrees[0]; } getCurrentInfo()598 SubtreeInfo* getCurrentInfo() 599 {return subtrees.getCurrent()->getMasterSubtree();} 600 eFlag markNamespacePrefixes(Sit S); 601 eFlag pushNamespacePrefixes(Sit, Str&, XSL_ATT); 602 eFlag popNamespacePrefixes(Sit); 603 void updateImportStatus(); 604 void speakDebug(); 605 void dumpStructure(Sit S); 606 private: 607 SabArena theArena; 608 Text *pendingTextNode; 609 DStr pendingText; 610 int vcount; // # of vertices in tree 611 Element *theDummyElement; 612 HashTable theDictionary; 613 PList<NSList*> pendingNSList; 614 const QName theEmptyQName; 615 Phrase stdPhrases[PHRASE_LAST]; 616 void initDict(); 617 RootNode *root; 618 RuleSList rulesList; 619 StrStrList unparsedEntities; 620 eFlag insertRule(Sit S, XSLElement *tmpl); 621 eFlag insertAttSet(Sit S, XSLElement *tmpl); 622 double defaultPriorityLP(Expression *); 623 double defaultPriority(XSLElement *); report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2)624 void report(Sit S, MsgType type, MsgCode code, const Str &arg1, const Str &arg2) const 625 { S.message(type, code, arg1, arg2); } 626 eFlag getSpaceNames(Sit S, Element &e, Str &str, SpaceNameList &where); 627 eFlag extractUsedSets(Sit S, Element *e); 628 void excludeStdNamespaces(); 629 // create a new structure 630 StylesheetStructure* createStylesheetStructure(Sit S); 631 632 // the structure information about the stylesheet 633 // (separated for import purposes) 634 StylesheetStructure structure; 635 636 // list of subtrees 637 SubtreeList subtrees; 638 AttSetList attSetList; 639 AliasList aliasesList; 640 VarDirectory toplevelVars; 641 int hasAnyStripped, hasAnyPreserved; 642 int importUnique; 643 }; 644 645 #endif //ifndef TreeHIncl 646 647 648