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