9a86ec723bd0e52bfcad6483928b6f7162f8274b
[mono.git] / mcs / class / referencesource / System.Data.SqlXml / System / Xml / Xsl / XsltOld / Processor.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="Processor.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7
8 namespace System.Xml.Xsl.XsltOld {
9     using Res = System.Xml.Utils.Res;
10     using System.Globalization;
11     using System.Diagnostics;
12     using System.IO;
13     using System.Xml.XPath;
14     using MS.Internal.Xml.XPath;
15     using System.Text;
16     using System.Collections;
17     using System.Collections.Generic;
18     using System.Xml.Xsl.XsltOld.Debugger;
19     using System.Reflection;
20     using System.Security;
21
22     internal sealed class Processor : IXsltProcessor {
23         //
24         // Static constants
25         //
26
27         const int StackIncrement = 10;
28
29         //
30         // Execution result
31         //
32
33         internal enum ExecResult {
34             Continue,           // Continues next iteration immediately
35             Interrupt,          // Returns to caller, was processed enough
36             Done                // Execution finished
37         }
38
39         internal enum OutputResult {
40             Continue,
41             Interrupt,
42             Overflow,
43             Error,
44             Ignore
45         }
46
47         private ExecResult     execResult;
48
49         //
50         // Compiled stylesheet
51         //
52
53         private Stylesheet      stylesheet;     // Root of import tree of template managers
54         private RootAction      rootAction;
55         private Key[]           keyList;
56         private List<TheQuery>  queryStore;
57         public  PermissionSet   permissions;   // used by XsltCompiledContext in document and extension functions
58
59         //
60         // Document Being transformed
61         //
62
63         private XPathNavigator    document;
64
65         //
66         // Execution action stack
67         //
68
69         private HWStack         actionStack;
70         private HWStack         debuggerStack;
71
72         //
73         // Register for returning value from calling nested action
74         //
75
76         private StringBuilder   sharedStringBuilder;
77
78         //
79         // Output related member variables
80         //
81         int                     ignoreLevel;
82         StateMachine            xsm;
83         RecordBuilder           builder;
84
85         XsltOutput              output;
86
87         XmlNameTable            nameTable      = new NameTable();
88
89         XmlResolver             resolver;
90
91 #pragma warning disable 618
92         XsltArgumentList        args;
93 #pragma warning restore 618
94         Hashtable               scriptExtensions;
95
96         ArrayList               numberList;
97         //
98         // Template lookup action
99         //
100
101         TemplateLookupAction    templateLookup = new TemplateLookupAction();
102
103         private IXsltDebugger   debugger;
104         Query[]                 queryList;
105
106         private ArrayList sortArray;
107
108         private Hashtable documentCache;
109
110         // NOTE: ValueOf() can call Matches() through XsltCompileContext.PreserveWhitespace(),
111         // that's why we use two different contexts here, valueOfContext and matchesContext
112         private XsltCompileContext  valueOfContext;
113         private XsltCompileContext  matchesContext;
114
115         internal XPathNavigator Current {
116             get {
117                 ActionFrame frame = (ActionFrame) this.actionStack.Peek();
118                 return frame != null ? frame.Node : null;
119             }
120         }
121
122         internal ExecResult ExecutionResult {
123             get { return this.execResult; }
124
125             set {
126                 Debug.Assert(this.execResult == ExecResult.Continue);
127                 this.execResult = value;
128             }
129         }
130
131         internal Stylesheet Stylesheet {
132             get { return this.stylesheet; }
133         }
134
135         internal XmlResolver Resolver {
136             get {
137                 Debug.Assert(this.resolver != null, "Constructor should create it if null passed");
138                 return this.resolver;
139             }
140         }
141
142         internal ArrayList SortArray {
143             get {
144                 Debug.Assert(this.sortArray != null, "InitSortArray() wasn't called");
145                 return this.sortArray;
146             }
147         }
148
149         internal Key[] KeyList {
150             get { return this.keyList; }
151         }
152
153         internal XPathNavigator GetNavigator(Uri ruri) {
154             XPathNavigator result = null;
155             if (documentCache != null) {
156                 result = documentCache[ruri] as XPathNavigator;
157                 if (result != null) {
158                     return result.Clone();
159                 }
160             }
161             else {
162                 documentCache = new Hashtable();
163             }
164
165             Object input = resolver.GetEntity(ruri, null, null);
166             if (input is Stream) {
167                 XmlTextReaderImpl tr  = new XmlTextReaderImpl(ruri.ToString(), (Stream) input); {
168                     tr.XmlResolver = this.resolver;
169                 }
170                 // reader is closed by Compiler.LoadDocument()
171                 result = ((IXPathNavigable)Compiler.LoadDocument(tr)).CreateNavigator();
172             }
173             else if (input is XPathNavigator){
174                 result = (XPathNavigator) input;
175             }
176             else {
177                 throw XsltException.Create(Res.Xslt_CantResolve, ruri.ToString());
178             }
179             documentCache[ruri] = result.Clone();
180             return result;
181         }
182
183         internal void AddSort(Sort sortinfo) {
184             Debug.Assert(this.sortArray != null, "InitSortArray() wasn't called");
185             this.sortArray.Add(sortinfo);
186         }
187
188         internal void InitSortArray() {
189             if (this.sortArray == null) {
190                 this.sortArray = new ArrayList();
191             }
192             else {
193                 this.sortArray.Clear();
194             }
195         }
196
197         internal object GetGlobalParameter(XmlQualifiedName qname) {
198             object parameter = args.GetParam(qname.Name, qname.Namespace);
199             if (parameter == null) {
200                 return null;
201             }
202             // 
203             if (
204                 parameter is XPathNodeIterator ||
205                 parameter is XPathNavigator ||
206                 parameter is Boolean ||
207                 parameter is Double ||
208                 parameter is String
209             ) {
210                 // doing nothing
211             } else if (
212                 parameter is Int16 || parameter is UInt16 ||
213                 parameter is Int32 || parameter is UInt32 ||
214                 parameter is Int64 || parameter is UInt64 ||
215                 parameter is Single || parameter is Decimal
216             ) {
217                 parameter = XmlConvert.ToXPathDouble(parameter);
218             } else {
219                 parameter = parameter.ToString();
220             }
221             return parameter;
222         }
223
224         internal object GetExtensionObject(string nsUri) {
225             return args.GetExtensionObject(nsUri);
226         }
227
228         internal object GetScriptObject(string nsUri) {
229             return scriptExtensions[nsUri];
230         }
231
232         internal RootAction RootAction {
233             get { return this.rootAction; }
234         }
235
236         internal XPathNavigator Document {
237             get { return this.document; }
238         }
239
240 #if DEBUG
241         private bool stringBuilderLocked = false;
242 #endif
243
244         internal StringBuilder GetSharedStringBuilder() {
245 #if DEBUG
246             Debug.Assert(! stringBuilderLocked);
247 #endif
248             if (sharedStringBuilder == null) {
249                 sharedStringBuilder = new StringBuilder();
250             }
251             else {
252                 sharedStringBuilder.Length = 0;
253             }
254 #if DEBUG
255             stringBuilderLocked = true;
256 #endif
257             return sharedStringBuilder;
258         }
259
260         internal void ReleaseSharedStringBuilder() {
261             // don't clean stringBuilderLocked here. ToString() will happen after this call
262 #if DEBUG
263             stringBuilderLocked = false;
264 #endif
265         }
266
267         internal ArrayList NumberList {
268             get {
269                 if (this.numberList == null) {
270                     this.numberList = new ArrayList();
271                 }
272                 return this.numberList;
273             }
274         }
275
276         internal IXsltDebugger Debugger {
277             get { return this.debugger; }
278         }
279
280         internal HWStack ActionStack {
281             get { return this.actionStack; }
282         }
283
284         internal RecordBuilder Builder {
285             get { return this.builder; }
286         }
287
288         internal XsltOutput Output {
289             get { return this.output; }
290         }
291
292         //
293         // Construction
294         //
295         public Processor(
296             XPathNavigator doc, XsltArgumentList args, XmlResolver resolver,
297             Stylesheet stylesheet, List<TheQuery> queryStore, RootAction rootAction,
298             IXsltDebugger debugger
299         ) {
300             this.stylesheet = stylesheet;
301             this.queryStore = queryStore;
302             this.rootAction = rootAction;
303             this.queryList  = new Query[queryStore.Count]; {
304                 for(int i = 0; i < queryStore.Count; i ++) {
305                     queryList[i] = Query.Clone(queryStore[i].CompiledQuery.QueryTree);
306                 }
307             }
308
309             this.xsm                 = new StateMachine();
310             this.document            = doc;
311             this.builder             = null;
312             this.actionStack         = new HWStack(StackIncrement);
313             this.output              = this.rootAction.Output;
314             this.permissions         = this.rootAction.permissions;
315             this.resolver            = resolver ?? XmlNullResolver.Singleton;
316             this.args                = args     ?? new XsltArgumentList();
317             this.debugger            = debugger;
318             if (this.debugger != null) {
319                 this.debuggerStack = new HWStack(StackIncrement, /*limit:*/1000);
320                 templateLookup     = new TemplateLookupActionDbg();
321             }
322
323             // Clone the compile-time KeyList
324             if (this.rootAction.KeyList != null) {
325                 this.keyList = new Key[this.rootAction.KeyList.Count];
326                 for (int i = 0; i < this.keyList.Length; i ++) {
327                     this.keyList[i] = this.rootAction.KeyList[i].Clone();
328                 }
329             }
330
331             this.scriptExtensions = new Hashtable(this.stylesheet.ScriptObjectTypes.Count); {
332                 foreach(DictionaryEntry entry in this.stylesheet.ScriptObjectTypes) {
333                     string namespaceUri = (string)entry.Key;
334                     if (GetExtensionObject(namespaceUri) != null) {
335                         throw XsltException.Create(Res.Xslt_ScriptDub, namespaceUri);
336                     }
337                     scriptExtensions.Add(namespaceUri, Activator.CreateInstance((Type)entry.Value,
338                         BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, null, null));
339                 }
340             }
341
342             this.PushActionFrame(this.rootAction, /*nodeSet:*/null);
343         }
344
345         public ReaderOutput StartReader() {
346             ReaderOutput output = new ReaderOutput(this);
347             this.builder = new RecordBuilder(output, this.nameTable);
348             return output;
349         }
350
351         public void Execute(Stream stream) {
352             RecordOutput recOutput = null;
353
354             switch (this.output.Method) {
355             case XsltOutput.OutputMethod.Text:
356                 recOutput = new TextOnlyOutput(this, stream);
357                 break;
358             case XsltOutput.OutputMethod.Xml:
359             case XsltOutput.OutputMethod.Html:
360             case XsltOutput.OutputMethod.Other:
361             case XsltOutput.OutputMethod.Unknown:
362                 recOutput = new TextOutput(this, stream);
363                 break;
364             }
365             this.builder = new RecordBuilder(recOutput, this.nameTable);
366             Execute();
367         }
368
369         public void Execute(TextWriter writer) {
370             RecordOutput recOutput = null;
371
372             switch (this.output.Method) {
373             case XsltOutput.OutputMethod.Text:
374                 recOutput = new TextOnlyOutput(this, writer);
375                 break;
376             case XsltOutput.OutputMethod.Xml:
377             case XsltOutput.OutputMethod.Html:
378             case XsltOutput.OutputMethod.Other:
379             case XsltOutput.OutputMethod.Unknown:
380                 recOutput = new TextOutput(this, writer);
381                 break;
382             }
383             this.builder = new RecordBuilder(recOutput, this.nameTable);
384             Execute();
385         }
386
387         public void Execute(XmlWriter writer) {
388             this.builder = new RecordBuilder(new WriterOutput(this, writer), this.nameTable);
389             Execute();
390         }
391
392         //
393         //  Execution part of processor
394         //
395         internal void Execute() {
396             Debug.Assert(this.actionStack != null);
397
398             while (this.execResult == ExecResult.Continue) {
399                 ActionFrame frame = (ActionFrame) this.actionStack.Peek();
400
401                 if (frame == null) {
402                     Debug.Assert(this.builder != null);
403                     this.builder.TheEnd();
404                     ExecutionResult = ExecResult.Done;
405                     break;
406                 }
407
408                 // Execute the action which was on the top of the stack
409                 if (frame.Execute(this)) {
410                     this.actionStack.Pop();
411                 }
412             }
413
414             if (this.execResult == ExecResult.Interrupt) {
415                 this.execResult = ExecResult.Continue;
416             }
417         }
418
419         //
420         // Action frame support
421         //
422
423         internal ActionFrame PushNewFrame() {
424             ActionFrame prent = (ActionFrame) this.actionStack.Peek();
425             ActionFrame frame = (ActionFrame) this.actionStack.Push();
426             if (frame == null) {
427                 frame = new ActionFrame();
428                 this.actionStack.AddToTop(frame);
429             }
430             Debug.Assert(frame != null);
431
432             if (prent != null) {
433                 frame.Inherit(prent);
434             }
435
436             return frame;
437         }
438
439         internal void PushActionFrame(Action action, XPathNodeIterator nodeSet) {
440             ActionFrame frame = PushNewFrame();
441             frame.Init(action, nodeSet);
442         }
443
444         internal void PushActionFrame(ActionFrame container) {
445             this.PushActionFrame(container, container.NodeSet);
446         }
447
448         internal void PushActionFrame(ActionFrame container, XPathNodeIterator nodeSet) {
449             ActionFrame frame = PushNewFrame();
450             frame.Init(container, nodeSet);
451         }
452
453         internal void PushTemplateLookup(XPathNodeIterator nodeSet, XmlQualifiedName mode, Stylesheet importsOf) {
454             Debug.Assert(this.templateLookup != null);
455             this.templateLookup.Initialize(mode, importsOf);
456             PushActionFrame(this.templateLookup, nodeSet);
457         }
458
459         internal string GetQueryExpression(int key) {
460             Debug.Assert(key != Compiler.InvalidQueryKey);
461             return this.queryStore[key].CompiledQuery.Expression;
462         }
463
464         internal Query GetCompiledQuery(int key) {
465             Debug.Assert(key != Compiler.InvalidQueryKey);
466             TheQuery theQuery = this.queryStore[key];
467             theQuery.CompiledQuery.CheckErrors();
468             Query expr = Query.Clone(this.queryList[key]);
469             expr.SetXsltContext(new XsltCompileContext(theQuery._ScopeManager, this));
470             return expr;
471         }
472
473         internal Query GetValueQuery(int key) {
474             return GetValueQuery(key, null);
475         }
476
477         internal Query GetValueQuery(int key, XsltCompileContext context) {
478             Debug.Assert(key != Compiler.InvalidQueryKey);
479             TheQuery theQuery = this.queryStore[key];
480             theQuery.CompiledQuery.CheckErrors();
481             Query expr = this.queryList[key];
482
483             if (context == null) {
484                 context = new XsltCompileContext(theQuery._ScopeManager, this);
485             } else {
486                 context.Reinitialize(theQuery._ScopeManager, this);
487             }
488
489             expr.SetXsltContext(context);
490             return expr;
491         }
492
493         private XsltCompileContext GetValueOfContext() {
494             if (this.valueOfContext == null) {
495                 this.valueOfContext = new XsltCompileContext();
496             }
497             return this.valueOfContext;
498         }
499
500         [Conditional("DEBUG")]
501         private void RecycleValueOfContext() {
502             if (this.valueOfContext != null) {
503                 this.valueOfContext.Recycle();
504             }
505         }
506
507         private XsltCompileContext GetMatchesContext() {
508             if (this.matchesContext == null) {
509                 this.matchesContext = new XsltCompileContext();
510             }
511             return this.matchesContext;
512         }
513
514         [Conditional("DEBUG")]
515         private void RecycleMatchesContext() {
516             if (this.matchesContext != null) {
517                 this.matchesContext.Recycle();
518             }
519         }
520
521         internal String ValueOf(ActionFrame context, int key) {
522             string result;
523
524             Query query = this.GetValueQuery(key, GetValueOfContext());
525             object value = query.Evaluate(context.NodeSet);
526             if (value is XPathNodeIterator) {
527                 XPathNavigator n = query.Advance();
528                 result = n != null ? ValueOf(n) : string.Empty;
529             } else {
530                 result = XmlConvert.ToXPathString(value);
531             }
532
533             RecycleValueOfContext();
534             return result;
535         }
536
537         internal String ValueOf(XPathNavigator n) {
538             if (this.stylesheet.Whitespace && n.NodeType == XPathNodeType.Element) {
539                 StringBuilder builder = this.GetSharedStringBuilder();
540                 ElementValueWithoutWS(n, builder);
541                 this.ReleaseSharedStringBuilder();
542                 return builder.ToString();
543             }
544             return n.Value;
545         }
546
547         private void ElementValueWithoutWS(XPathNavigator nav, StringBuilder builder) {
548             Debug.Assert(nav.NodeType == XPathNodeType.Element);
549             bool preserve = this.Stylesheet.PreserveWhiteSpace(this, nav);
550             if (nav.MoveToFirstChild()) {
551                 do {
552                     switch (nav.NodeType) {
553                     case XPathNodeType.Text :
554                     case XPathNodeType.SignificantWhitespace :
555                         builder.Append(nav.Value);
556                         break;
557                     case XPathNodeType.Whitespace :
558                         if (preserve) {
559                             builder.Append(nav.Value);
560                         }
561                         break;
562                     case XPathNodeType.Element :
563                         ElementValueWithoutWS(nav, builder);
564                         break;
565                     }
566                 }while (nav.MoveToNext());
567                 nav.MoveToParent();
568             }
569         }
570
571         internal XPathNodeIterator StartQuery(XPathNodeIterator context, int key) {
572             Query query = GetCompiledQuery(key);
573             object result = query.Evaluate(context);
574             if (result is XPathNodeIterator) {
575                 // ToDo: We create XPathSelectionIterator to count positions, but it's better create special query in this case at compile time.
576                 return new XPathSelectionIterator(context.Current, query);
577             }
578             throw XsltException.Create(Res.XPath_NodeSetExpected);
579         }
580
581         internal object Evaluate(ActionFrame context, int key) {
582             return GetValueQuery(key).Evaluate(context.NodeSet);
583         }
584
585         internal object RunQuery(ActionFrame context, int key) {
586             Query query = GetCompiledQuery(key);
587             object value = query.Evaluate(context.NodeSet);
588             XPathNodeIterator it = value as XPathNodeIterator;
589             if (it != null) {
590                 return new XPathArrayIterator(it);
591             }
592
593             return value;
594         }
595
596         internal string EvaluateString(ActionFrame context, int key) {
597             object objValue = Evaluate(context, key);
598             string value = null;
599             if (objValue != null)
600                 value = XmlConvert.ToXPathString(objValue);
601             if (value == null)
602                 value = string.Empty;
603             return value;
604         }
605
606         internal bool EvaluateBoolean(ActionFrame context, int key) {
607             object objValue = Evaluate(context, key);
608
609             if (objValue != null) {
610                 XPathNavigator nav = objValue as XPathNavigator;
611                 return nav != null ? Convert.ToBoolean(nav.Value, CultureInfo.InvariantCulture) : Convert.ToBoolean(objValue, CultureInfo.InvariantCulture);
612             }
613             else {
614                 return false;
615             }
616         }
617
618         internal bool Matches(XPathNavigator context, int key) {
619             // We don't use XPathNavigator.Matches() to avoid cloning of Query on each call
620             Query query = this.GetValueQuery(key, GetMatchesContext());
621
622             try {
623                 bool result = query.MatchNode(context) != null;
624
625                 RecycleMatchesContext();
626                 return result;
627             } catch(XPathException) {
628                 throw XsltException.Create(Res.Xslt_InvalidPattern, this.GetQueryExpression(key));
629             }
630         }
631
632         //
633         // Outputting part of processor
634         //
635
636         internal XmlNameTable NameTable {
637             get { return this.nameTable; }
638         }
639
640         internal bool CanContinue {
641             get { return this.execResult == ExecResult.Continue; }
642         }
643
644         internal bool ExecutionDone {
645             get { return this.execResult == ExecResult.Done; }
646         }
647
648         internal void ResetOutput() {
649             Debug.Assert(this.builder != null);
650             this.builder.Reset();
651         }
652         internal bool BeginEvent(XPathNodeType nodeType, string prefix, string name, string nspace, bool empty) {
653             return BeginEvent(nodeType, prefix, name,  nspace,  empty, null, true);
654         }
655
656         internal bool BeginEvent(XPathNodeType nodeType, string prefix, string name, string nspace, bool empty, Object htmlProps, bool search) {
657             Debug.Assert(this.xsm != null);
658
659             int stateOutlook = this.xsm.BeginOutlook(nodeType);
660
661             if (this.ignoreLevel > 0 || stateOutlook == StateMachine.Error) {
662                 this.ignoreLevel ++;
663                 return true;                        // We consumed the event, so pretend it was output.
664             }
665
666             switch (this.builder.BeginEvent(stateOutlook, nodeType, prefix, name, nspace, empty, htmlProps, search)) {
667             case OutputResult.Continue:
668                 this.xsm.Begin(nodeType);
669                 Debug.Assert(StateMachine.StateOnly(stateOutlook) == this.xsm.State);
670                 Debug.Assert(ExecutionResult == ExecResult.Continue);
671                 return true;
672             case OutputResult.Interrupt:
673                 this.xsm.Begin(nodeType);
674                 Debug.Assert(StateMachine.StateOnly(stateOutlook) == this.xsm.State);
675                 ExecutionResult = ExecResult.Interrupt;
676                 return true;
677             case OutputResult.Overflow:
678                 ExecutionResult = ExecResult.Interrupt;
679                 return false;
680             case OutputResult.Error:
681                 this.ignoreLevel ++;
682                 return true;
683             case OutputResult.Ignore:
684                 return true;
685             default:
686                 Debug.Fail("Unexpected result of RecordBuilder.BeginEvent()");
687                 return true;
688             }
689         }
690
691         internal bool TextEvent(string text) {
692             return this.TextEvent(text, false);
693         }
694
695         internal bool TextEvent(string text, bool disableOutputEscaping) {
696             Debug.Assert(this.xsm != null);
697
698             if (this.ignoreLevel > 0) {
699                 return true;
700             }
701
702             int stateOutlook = this.xsm.BeginOutlook(XPathNodeType.Text);
703
704             switch (this.builder.TextEvent(stateOutlook, text, disableOutputEscaping)) {
705                 case OutputResult.Continue:
706                 this.xsm.Begin(XPathNodeType.Text);
707                 Debug.Assert(StateMachine.StateOnly(stateOutlook) == this.xsm.State);
708                 Debug.Assert(ExecutionResult == ExecResult.Continue);
709                 return true;
710             case OutputResult.Interrupt:
711                 this.xsm.Begin(XPathNodeType.Text);
712                 Debug.Assert(StateMachine.StateOnly(stateOutlook) == this.xsm.State);
713                 ExecutionResult = ExecResult.Interrupt;
714                 return true;
715             case OutputResult.Overflow:
716                 ExecutionResult = ExecResult.Interrupt;
717                 return false;
718             case OutputResult.Error:
719             case OutputResult.Ignore:
720                 return true;
721             default:
722                 Debug.Fail("Unexpected result of RecordBuilder.TextEvent()");
723                 return true;
724             }
725         }
726
727         internal bool EndEvent(XPathNodeType nodeType) {
728             Debug.Assert(this.xsm != null);
729
730             if (this.ignoreLevel > 0) {
731                 this.ignoreLevel --;
732                 return true;
733             }
734
735             int stateOutlook = this.xsm.EndOutlook(nodeType);
736
737             switch (this.builder.EndEvent(stateOutlook, nodeType)) {
738                 case OutputResult.Continue:
739                 this.xsm.End(nodeType);
740                 Debug.Assert(StateMachine.StateOnly(stateOutlook) == this.xsm.State);
741                 return true;
742             case OutputResult.Interrupt:
743                 this.xsm.End(nodeType);
744                 Debug.Assert(StateMachine.StateOnly(stateOutlook) == this.xsm.State,
745                              "StateMachine.StateOnly(stateOutlook) == this.xsm.State");
746                 ExecutionResult = ExecResult.Interrupt;
747                 return true;
748             case OutputResult.Overflow:
749                 ExecutionResult = ExecResult.Interrupt;
750                 return false;
751             case OutputResult.Error:
752             case OutputResult.Ignore:
753             default:
754                 Debug.Fail("Unexpected result of RecordBuilder.TextEvent()");
755                 return true;
756             }
757         }
758
759         internal bool CopyBeginEvent(XPathNavigator node, bool emptyflag) {
760             switch (node.NodeType) {
761             case XPathNodeType.Element:
762             case XPathNodeType.Attribute:
763             case XPathNodeType.ProcessingInstruction:
764             case XPathNodeType.Comment:
765                 return BeginEvent(node.NodeType, node.Prefix, node.LocalName, node.NamespaceURI, emptyflag);
766             case XPathNodeType.Namespace:
767                 // value instead of namespace here!
768                 return BeginEvent(XPathNodeType.Namespace, null, node.LocalName, node.Value, false);
769             case XPathNodeType.Text:
770                 // Text will be copied in CopyContents();
771                 break;
772
773             case XPathNodeType.Root:
774             case XPathNodeType.Whitespace:
775             case XPathNodeType.SignificantWhitespace:
776             case XPathNodeType.All:
777                 break;
778
779             default:
780                 Debug.Fail("Invalid XPathNodeType in CopyBeginEvent");
781                 break;
782             }
783
784             return true;
785         }
786
787         internal bool CopyTextEvent(XPathNavigator node) {
788             switch (node.NodeType) {
789             case XPathNodeType.Element:
790             case XPathNodeType.Namespace:
791                 break;
792
793             case XPathNodeType.Attribute:
794             case XPathNodeType.ProcessingInstruction:
795             case XPathNodeType.Comment:
796             case XPathNodeType.Text:
797             case XPathNodeType.Whitespace:
798             case XPathNodeType.SignificantWhitespace:
799                 string text = node.Value;
800                 return TextEvent(text);
801
802             case XPathNodeType.Root:
803             case XPathNodeType.All:
804                 break;
805
806             default:
807                 Debug.Fail("Invalid XPathNodeType in CopyTextEvent");
808                 break;
809             }
810
811             return true;
812         }
813
814         internal bool CopyEndEvent(XPathNavigator node) {
815             switch (node.NodeType) {
816             case XPathNodeType.Element:
817             case XPathNodeType.Attribute:
818             case XPathNodeType.ProcessingInstruction:
819             case XPathNodeType.Comment:
820             case XPathNodeType.Namespace:
821                 return EndEvent(node.NodeType);
822
823             case XPathNodeType.Text:
824                 // Text was copied in CopyContents();
825                 break;
826
827
828             case XPathNodeType.Root:
829             case XPathNodeType.Whitespace:
830             case XPathNodeType.SignificantWhitespace:
831             case XPathNodeType.All:
832                 break;
833
834             default:
835                 Debug.Fail("Invalid XPathNodeType in CopyEndEvent");
836                 break;
837             }
838
839             return true;
840         }
841
842         internal static bool IsRoot(XPathNavigator navigator) {
843             Debug.Assert(navigator != null);
844
845             if (navigator.NodeType == XPathNodeType.Root) {
846                 return true;
847             }
848             else if (navigator.NodeType == XPathNodeType.Element) {
849                 XPathNavigator clone = navigator.Clone();
850                 clone.MoveToRoot();
851                 return clone.IsSamePosition(navigator);
852             }
853             else {
854                 return false;
855             }
856         }
857
858         //
859         // Builder stack
860         //
861         internal void PushOutput(RecordOutput output) {
862             Debug.Assert(output != null);
863             this.builder.OutputState = this.xsm.State;
864             RecordBuilder lastBuilder = this.builder;
865             this.builder      = new RecordBuilder(output, this.nameTable);
866             this.builder.Next = lastBuilder;
867
868             this.xsm.Reset();
869         }
870
871         internal RecordOutput PopOutput() {
872             Debug.Assert(this.builder != null);
873
874             RecordBuilder topBuilder = this.builder;
875             this.builder              = topBuilder.Next;
876             this.xsm.State            = this.builder.OutputState;
877
878             topBuilder.TheEnd();
879
880             return topBuilder.Output;
881         }
882
883         internal bool SetDefaultOutput(XsltOutput.OutputMethod method) {
884             if(Output.Method != method) {
885                 this.output = this.output.CreateDerivedOutput(method);
886                 return true;
887             }
888             return false;
889         }
890
891         internal object GetVariableValue(VariableAction variable) {
892             int variablekey = variable.VarKey;
893             if (variable.IsGlobal) {
894                 ActionFrame rootFrame = (ActionFrame) this.actionStack[0];
895                 object result = rootFrame.GetVariable(variablekey);
896                 if (result == VariableAction.BeingComputedMark) {
897                     throw XsltException.Create(Res.Xslt_CircularReference, variable.NameStr);
898                 }
899                 if (result != null) {
900                     return result;
901                 }
902                 // Variable wasn't evaluated yet
903                 int saveStackSize = this.actionStack.Length;
904                 ActionFrame varFrame = PushNewFrame();
905                 varFrame.Inherit(rootFrame);
906                 varFrame.Init(variable, rootFrame.NodeSet);
907                 do {
908                     bool endOfFrame = ((ActionFrame) this.actionStack.Peek()).Execute(this);
909                     if (endOfFrame) {
910                         this.actionStack.Pop();
911                     }
912                 } while (saveStackSize < this.actionStack.Length);
913                 Debug.Assert(saveStackSize == this.actionStack.Length);
914                 result = rootFrame.GetVariable(variablekey);
915                 Debug.Assert(result != null, "Variable was just calculated and result can't be null");
916                 return result;
917             } else {
918                 return ((ActionFrame) this.actionStack.Peek()).GetVariable(variablekey);
919             }
920         }
921
922         internal void SetParameter(XmlQualifiedName name, object value) {
923             Debug.Assert(1 < actionStack.Length);
924             ActionFrame parentFrame = (ActionFrame) this.actionStack[actionStack.Length - 2];
925             parentFrame.SetParameter(name, value);
926         }
927
928         internal void ResetParams() {
929             ActionFrame frame = (ActionFrame) this.actionStack[actionStack.Length - 1];
930             frame.ResetParams();
931         }
932
933         internal object GetParameter(XmlQualifiedName name) {
934             Debug.Assert(2 < actionStack.Length);
935             ActionFrame parentFrame = (ActionFrame) this.actionStack[actionStack.Length - 3];
936             return parentFrame.GetParameter(name);
937         }
938
939         // ---------------------- Debugger stack -----------------------
940
941         internal class DebuggerFrame {
942             internal ActionFrame        actionFrame;
943             internal XmlQualifiedName   currentMode;
944         }
945
946         internal void PushDebuggerStack() {
947             Debug.Assert(this.Debugger != null, "We don't generate calls this function if ! debugger");
948             DebuggerFrame dbgFrame = (DebuggerFrame) this.debuggerStack.Push();
949             if (dbgFrame == null) {
950                 dbgFrame = new DebuggerFrame();
951                 this.debuggerStack.AddToTop(dbgFrame);
952             }
953             dbgFrame.actionFrame = (ActionFrame) this.actionStack.Peek(); // In a case of next builtIn action.
954         }
955
956         internal void PopDebuggerStack() {
957             Debug.Assert(this.Debugger != null, "We don't generate calls this function if ! debugger");
958             this.debuggerStack.Pop();
959         }
960
961         internal void OnInstructionExecute() {
962             Debug.Assert(this.Debugger != null, "We don't generate calls this function if ! debugger");
963             DebuggerFrame dbgFrame = (DebuggerFrame) this.debuggerStack.Peek();
964             Debug.Assert(dbgFrame != null, "PushDebuggerStack() wasn't ever called");
965             dbgFrame.actionFrame = (ActionFrame) this.actionStack.Peek();
966             this.Debugger.OnInstructionExecute((IXsltProcessor) this);
967         }
968
969         internal XmlQualifiedName GetPrevioseMode() {
970             Debug.Assert(this.Debugger != null, "We don't generate calls this function if ! debugger");
971             Debug.Assert(2 <= this.debuggerStack.Length);
972             return ((DebuggerFrame) this.debuggerStack[this.debuggerStack.Length - 2]).currentMode;
973         }
974
975         internal void SetCurrentMode(XmlQualifiedName mode) {
976             Debug.Assert(this.Debugger != null, "We don't generate calls this function if ! debugger");
977             ((DebuggerFrame) this.debuggerStack[this.debuggerStack.Length - 1]).currentMode = mode;
978         }
979
980         // ----------------------- IXsltProcessor : --------------------
981         int IXsltProcessor.StackDepth {
982             get {return this.debuggerStack.Length;}
983         }
984
985         IStackFrame IXsltProcessor.GetStackFrame(int depth) {
986             return ((DebuggerFrame) this.debuggerStack[depth]).actionFrame;
987         }
988     }
989 }