| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293 |
- //------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------
- namespace System.ServiceModel.Dispatcher
- {
- using System.Collections.Generic;
- using System.Runtime;
- using System.Text;
- using System.Xml.XPath;
- using System.Xml.Xsl;
- internal class FunctionCallOpcode : Opcode
- {
- QueryFunction function;
- internal FunctionCallOpcode(QueryFunction function)
- : base(OpcodeID.Function)
- {
- Fx.Assert(null != function, "");
- this.function = function;
- }
- internal override bool Equals(Opcode op)
- {
- if (base.Equals(op))
- {
- FunctionCallOpcode functionCall = (FunctionCallOpcode)op;
- return functionCall.function.Equals(this.function);
- }
- return false;
- }
- internal override Opcode Eval(ProcessingContext context)
- {
- this.function.Eval(context);
- return this.next;
- }
- #if DEBUG_FILTER
- public override string ToString()
- {
- return string.Format("{0} {1}", base.ToString(), this.function.ToString());
- }
- #endif
- }
- internal class XsltFunctionCallOpcode : Opcode
- {
- static object[] NullArgs = new object[0];
- int argCount;
- XsltContext xsltContext;
- IXsltContextFunction function;
- List<NodeSequenceIterator> iterList;
- // REFACTOR, [....], make this a function on QueryValueModel
- internal XsltFunctionCallOpcode(XsltContext context, IXsltContextFunction function, int argCount)
- : base(OpcodeID.XsltFunction)
- {
- Fx.Assert(null != context && null != function, "");
- this.xsltContext = context;
- this.function = function;
- this.argCount = argCount;
- for (int i = 0; i < function.Maxargs; ++i)
- {
- if (function.ArgTypes[i] == XPathResultType.NodeSet)
- {
- this.iterList = new List<NodeSequenceIterator>();
- break;
- }
- }
- // Make sure the return type is valid
- switch (this.function.ReturnType)
- {
- case XPathResultType.String:
- case XPathResultType.Number:
- case XPathResultType.Boolean:
- case XPathResultType.NodeSet:
- break;
- default:
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.InvalidType, SR.GetString(SR.QueryFunctionTypeNotSupported, this.function.ReturnType.ToString())));
- }
- }
- internal override bool Equals(Opcode op)
- {
- // We have no way of knowing if an Xslt function is stateless and can be merged
- return false;
- }
- internal override Opcode Eval(ProcessingContext context)
- {
- XPathNavigator nav = context.Processor.ContextNode;
- if (nav != null && context.Processor.ContextMessage != null)
- {
- ((SeekableMessageNavigator)nav).Atomize();
- }
- if (this.argCount == 0)
- {
- context.PushFrame();
- int count = context.IterationCount;
- if (count > 0)
- {
- object ret = this.function.Invoke(this.xsltContext, NullArgs, nav);
- switch (this.function.ReturnType)
- {
- case XPathResultType.String:
- context.Push((string)ret, count);
- break;
- case XPathResultType.Number:
- context.Push((double)ret, count);
- break;
- case XPathResultType.Boolean:
- context.Push((bool)ret, count);
- break;
- case XPathResultType.NodeSet:
- NodeSequence seq = context.CreateSequence();
- XPathNodeIterator iter = (XPathNodeIterator)ret;
- seq.Add(iter);
- context.Push(seq, count);
- break;
- default:
- // This should never be reached
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.Unexpected, SR.GetString(SR.QueryFunctionTypeNotSupported, this.function.ReturnType.ToString())));
- }
- }
- }
- else
- {
- // PERF, [....], see if we can cache these arrays to avoid allocations
- object[] xsltArgs = new object[this.argCount];
- int iterationCount = context.TopArg.Count;
- for (int iteration = 0; iteration < iterationCount; ++iteration)
- {
- for (int i = 0; i < this.argCount; ++i)
- {
- StackFrame arg = context[i];
- Fx.Assert(iteration < arg.Count, "");
- switch (this.function.ArgTypes[i])
- {
- case XPathResultType.String:
- xsltArgs[i] = context.PeekString(arg[iteration]);
- break;
- case XPathResultType.Number:
- xsltArgs[i] = context.PeekDouble(arg[iteration]);
- break;
- case XPathResultType.Boolean:
- xsltArgs[i] = context.PeekBoolean(arg[iteration]);
- break;
- case XPathResultType.NodeSet:
- NodeSequenceIterator iter = new NodeSequenceIterator(context.PeekSequence(arg[iteration]));
- xsltArgs[i] = iter;
- this.iterList.Add(iter);
- break;
- default:
- // This should never be reached
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.Unexpected, SR.GetString(SR.QueryFunctionTypeNotSupported, this.function.ArgTypes[i].ToString())));
- }
- }
- object ret = this.function.Invoke(this.xsltContext, xsltArgs, nav);
- if (this.iterList != null)
- {
- for (int i = 0; i < this.iterList.Count; ++i)
- {
- this.iterList[i].Clear();
- }
- this.iterList.Clear();
- }
- switch (this.function.ReturnType)
- {
- case XPathResultType.String:
- context.SetValue(context, context[this.argCount - 1][iteration], (string)ret);
- break;
- case XPathResultType.Number:
- context.SetValue(context, context[this.argCount - 1][iteration], (double)ret);
- break;
- case XPathResultType.Boolean:
- context.SetValue(context, context[this.argCount - 1][iteration], (bool)ret);
- break;
- case XPathResultType.NodeSet:
- NodeSequence seq = context.CreateSequence();
- XPathNodeIterator iter = (XPathNodeIterator)ret;
- seq.Add(iter);
- context.SetValue(context, context[this.argCount - 1][iteration], seq);
- break;
- default:
- // This should never be reached
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.Unexpected, SR.GetString(SR.QueryFunctionTypeNotSupported, this.function.ReturnType.ToString())));
- }
- }
- for (int i = 0; i < this.argCount - 1; ++i)
- {
- context.PopFrame();
- }
- }
- return this.next;
- }
- #if DEBUG_FILTER
- public override string ToString()
- {
- return string.Format("{0} IXsltContextFunction", base.ToString());
- }
- #endif
- }
- internal enum QueryFunctionFlag
- {
- None = 0x00000000,
- UsesContextNode = 0x00000001
- }
- internal abstract class QueryFunction
- {
- static ValueDataType[] emptyParams = new ValueDataType[0];
- QueryFunctionFlag flags;
- protected string name;
- ValueDataType[] paramTypes;
- ValueDataType returnType;
- internal QueryFunction(string name, ValueDataType returnType)
- : this(name, returnType, QueryFunction.emptyParams, QueryFunctionFlag.None)
- {
- }
- internal QueryFunction(string name, ValueDataType returnType, QueryFunctionFlag flags)
- : this(name, returnType, QueryFunction.emptyParams, flags)
- {
- }
- internal QueryFunction(string name, ValueDataType returnType, ValueDataType[] paramTypes)
- : this(name, returnType, paramTypes, QueryFunctionFlag.None)
- {
- }
- internal QueryFunction(string name, ValueDataType returnType, ValueDataType[] paramTypes, QueryFunctionFlag flags)
- {
- Fx.Assert(null != paramTypes, "");
- Fx.Assert(null != name, "");
- this.name = name;
- this.returnType = returnType;
- this.paramTypes = paramTypes;
- this.flags = flags;
- }
- internal ValueDataType[] ParamTypes
- {
- get
- {
- return this.paramTypes;
- }
- }
- internal ValueDataType ReturnType
- {
- get
- {
- return this.returnType;
- }
- }
- internal bool Bind(string name, XPathExprList args)
- {
- Fx.Assert(null != name && null != args, "");
- if (
- 0 != string.CompareOrdinal(this.name, name)
- || this.paramTypes.Length != args.Count
- )
- {
- return false;
- }
- return (this.paramTypes.Length == args.Count);
- }
- internal abstract bool Equals(QueryFunction function);
- internal abstract void Eval(ProcessingContext context);
- internal bool TestFlag(QueryFunctionFlag flag)
- {
- return (0 != (this.flags & flag));
- }
- #if DEBUG_FILTER
- public override string ToString()
- {
- StringBuilder text = new StringBuilder();
- text.Append(this.name);
- text.Append('(');
- for (int i = 0; i < this.paramTypes.Length; ++i)
- {
- if (i > 0)
- {
- text.Append(',');
- }
- text.Append(this.paramTypes[i].ToString());
- }
- text.Append(')');
- return text.ToString();
- }
- #endif
- }
- internal interface IFunctionLibrary
- {
- QueryFunction Bind(string functionName, string functionNamespace, XPathExprList args);
- }
- internal enum XPathFunctionID
- {
- // Set
- IterateSequences,
- Count,
- Position,
- Last,
- LocalName,
- LocalNameDefault,
- Name,
- NameDefault,
- NamespaceUri,
- NamespaceUriDefault,
- // Boolean
- Boolean,
- Not,
- True,
- False,
- Lang,
- // Number
- Number,
- NumberDefault,
- Ceiling,
- Floor,
- Round,
- Sum,
- // String
- String,
- StringDefault,
- StartsWith,
- ConcatTwo,
- ConcatThree,
- ConcatFour,
- Contains,
- NormalizeSpace,
- NormalizeSpaceDefault,
- StringLength,
- StringLengthDefault,
- SubstringBefore,
- SubstringAfter,
- Substring,
- SubstringLimit,
- Translate
- }
- internal class XPathFunctionLibrary : IFunctionLibrary
- {
- static XPathFunction[] functionTable;
- static XPathFunctionLibrary()
- {
- XPathFunctionLibrary.functionTable = new XPathFunction[] {
- new XPathFunction(XPathFunctionID.Boolean, "boolean", ValueDataType.Boolean, new ValueDataType[] { ValueDataType.None }),
- new XPathFunction(XPathFunctionID.False, "false", ValueDataType.Boolean),
- new XPathFunction(XPathFunctionID.True, "true", ValueDataType.Boolean),
- new XPathFunction(XPathFunctionID.Not, "not", ValueDataType.Boolean, new ValueDataType[] { ValueDataType.Boolean }),
- new XPathFunction(XPathFunctionID.Lang, "lang", ValueDataType.Boolean, new ValueDataType[] { ValueDataType.String }),
- new XPathFunction(XPathFunctionID.Number, "number", ValueDataType.Double, new ValueDataType[] { ValueDataType.None }),
- new XPathFunction(XPathFunctionID.NumberDefault, "number", ValueDataType.Double),
- new XPathFunction(XPathFunctionID.Sum, "sum", ValueDataType.Double, new ValueDataType[] { ValueDataType.Sequence }),
- new XPathFunction(XPathFunctionID.Floor, "floor", ValueDataType.Double, new ValueDataType[] { ValueDataType.Double }),
- new XPathFunction(XPathFunctionID.Ceiling, "ceiling", ValueDataType.Double, new ValueDataType[] { ValueDataType.Double }),
- new XPathFunction(XPathFunctionID.Round, "round", ValueDataType.Double, new ValueDataType[] { ValueDataType.Double }),
- new XPathFunction(XPathFunctionID.String, "string", ValueDataType.String, new ValueDataType[] { ValueDataType.None }),
- new XPathFunction(XPathFunctionID.StringDefault, "string", ValueDataType.String, QueryFunctionFlag.UsesContextNode),
- new XPathFunction(XPathFunctionID.ConcatTwo, "concat", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.String }),
- new XPathFunction(XPathFunctionID.ConcatThree, "concat", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.String, ValueDataType.String }),
- new XPathFunction(XPathFunctionID.ConcatFour, "concat", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.String, ValueDataType.String, ValueDataType.String }),
- new XPathFunction(XPathFunctionID.StartsWith, "starts-with", ValueDataType.Boolean, new ValueDataType[] { ValueDataType.String, ValueDataType.String }),
- new XPathFunction(XPathFunctionID.NormalizeSpace, "normalize-space", ValueDataType.String, new ValueDataType[] { ValueDataType.String }),
- new XPathFunction(XPathFunctionID.NormalizeSpaceDefault, "normalize-space", ValueDataType.String, QueryFunctionFlag.UsesContextNode),
- new XPathFunction(XPathFunctionID.Contains, "contains", ValueDataType.Boolean, new ValueDataType[] { ValueDataType.String, ValueDataType.String }),
- new XPathFunction(XPathFunctionID.SubstringBefore, "substring-before", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.String }),
- new XPathFunction(XPathFunctionID.SubstringAfter, "substring-after", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.String }),
- new XPathFunction(XPathFunctionID.Substring, "substring", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.Double }),
- new XPathFunction(XPathFunctionID.SubstringLimit, "substring", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.Double, ValueDataType.Double }),
- new XPathFunction(XPathFunctionID.StringLength, "string-length", ValueDataType.Double, new ValueDataType[] { ValueDataType.String }),
- new XPathFunction(XPathFunctionID.StringLengthDefault, "string-length", ValueDataType.Double, QueryFunctionFlag.UsesContextNode),
- new XPathFunction(XPathFunctionID.Translate, "translate", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.String, ValueDataType.String }),
- new XPathFunction(XPathFunctionID.Last, "last", ValueDataType.Double, QueryFunctionFlag.UsesContextNode),
- new XPathFunction(XPathFunctionID.Position, "position", ValueDataType.Double, QueryFunctionFlag.UsesContextNode),
- new XPathFunction(XPathFunctionID.Count, "count", ValueDataType.Double, new ValueDataType[] { ValueDataType.Sequence }),
- new XPathFunction(XPathFunctionID.LocalName, "local-name", ValueDataType.String, new ValueDataType[] { ValueDataType.Sequence }),
- new XPathFunction(XPathFunctionID.LocalNameDefault, "local-name", ValueDataType.String, QueryFunctionFlag.UsesContextNode),
- new XPathFunction(XPathFunctionID.Name, "name", ValueDataType.String, new ValueDataType[] { ValueDataType.Sequence }),
- new XPathFunction(XPathFunctionID.NameDefault, "name", ValueDataType.String, QueryFunctionFlag.UsesContextNode),
- new XPathFunction(XPathFunctionID.NamespaceUri, "namespace-uri", ValueDataType.String, new ValueDataType[] { ValueDataType.Sequence }),
- new XPathFunction(XPathFunctionID.NamespaceUriDefault, "namespace-uri", ValueDataType.String, QueryFunctionFlag.UsesContextNode)
- };
- }
- internal XPathFunctionLibrary()
- {
- }
- public QueryFunction Bind(string functionName, string functionNamespace, XPathExprList args)
- {
- Fx.Assert(null != functionName && null != args, "");
- // Variable length argument list requires a special case here
- if (functionName == "concat" && args.Count > 4)
- {
- ConcatFunction f = new ConcatFunction(args.Count);
- if (f.Bind(functionName, args))
- {
- return f;
- }
- }
- else
- {
- for (int i = 0; i < XPathFunctionLibrary.functionTable.Length; ++i)
- {
- // XPath functions are typeless, so don't check types
- if (XPathFunctionLibrary.functionTable[i].Bind(functionName, args))
- {
- return XPathFunctionLibrary.functionTable[i];
- }
- }
- }
- return null;
- }
- }
- internal class ConcatFunction : QueryFunction
- {
- int argCount;
- internal ConcatFunction(int argCount)
- : base("concat", ValueDataType.String, ConcatFunction.MakeTypes(argCount))
- {
- Fx.Assert(argCount >= 2, "");
- this.argCount = argCount;
- }
- internal override bool Equals(QueryFunction function)
- {
- ConcatFunction f = function as ConcatFunction;
- if (f != null && this.argCount == f.argCount)
- {
- return true;
- }
- return false;
- }
- internal override void Eval(ProcessingContext context)
- {
- Fx.Assert(context != null, "");
- StackFrame[] args = new StackFrame[argCount];
- for (int i = 0; i < this.argCount; ++i)
- {
- args[i] = context[i];
- }
- StringBuilder builder = new StringBuilder();
- while (args[0].basePtr <= args[0].endPtr)
- {
- builder.Length = 0;
- for (int i = 0; i < this.argCount; ++i)
- {
- builder.Append(context.PeekString(args[i].basePtr));
- }
- context.SetValue(context, args[this.argCount - 1].basePtr, builder.ToString());
- for (int i = 0; i < this.argCount; ++i)
- {
- args[i].basePtr++;
- }
- }
- for (int i = 0; i < this.argCount - 1; ++i)
- {
- context.PopFrame();
- }
- }
- internal static ValueDataType[] MakeTypes(int size)
- {
- ValueDataType[] t = new ValueDataType[size];
- for (int i = 0; i < size; ++i)
- {
- t[i] = ValueDataType.String;
- }
- return t;
- }
- }
- internal class XPathFunction : QueryFunction
- {
- XPathFunctionID functionID;
- internal XPathFunction(XPathFunctionID functionID, string name, ValueDataType returnType)
- : base(name, returnType)
- {
- this.functionID = functionID;
- }
- internal XPathFunction(XPathFunctionID functionID, string name, ValueDataType returnType, QueryFunctionFlag flags)
- : base(name, returnType, flags)
- {
- this.functionID = functionID;
- }
- internal XPathFunction(XPathFunctionID functionID, string name, ValueDataType returnType, ValueDataType[] argTypes)
- : base(name, returnType, argTypes)
- {
- this.functionID = functionID;
- }
- internal XPathFunctionID ID
- {
- get
- {
- return this.functionID;
- }
- }
- internal override bool Equals(QueryFunction function)
- {
- XPathFunction xpathFunction = function as XPathFunction;
- if (null == xpathFunction)
- {
- return false;
- }
- return (xpathFunction.ID == this.ID);
- }
- static void ConvertFirstArg(ProcessingContext context, ValueDataType type)
- {
- StackFrame arg = context.TopArg;
- Value[] values = context.Values;
- while (arg.basePtr <= arg.endPtr)
- {
- values[arg.basePtr++].ConvertTo(context, type);
- }
- }
- internal override void Eval(ProcessingContext context)
- {
- Fx.Assert(null != context, "");
- switch (this.functionID)
- {
- default:
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException(SR.GetString(SR.QueryNotImplemented, this.name)));
- case XPathFunctionID.IterateSequences:
- XPathFunction.IterateAndPushSequences(context);
- break;
- case XPathFunctionID.Count:
- XPathFunction.NodesetCount(context);
- break;
- case XPathFunctionID.Position:
- XPathFunction.NodesetPosition(context);
- break;
- case XPathFunctionID.Last:
- XPathFunction.NodesetLast(context);
- break;
- case XPathFunctionID.LocalName:
- XPathFunction.NodesetLocalName(context);
- break;
- case XPathFunctionID.LocalNameDefault:
- XPathFunction.NodesetLocalNameDefault(context);
- break;
- case XPathFunctionID.Name:
- XPathFunction.NodesetName(context);
- break;
- case XPathFunctionID.NameDefault:
- XPathFunction.NodesetNameDefault(context);
- break;
- case XPathFunctionID.NamespaceUri:
- XPathFunction.NodesetNamespaceUri(context);
- break;
- case XPathFunctionID.NamespaceUriDefault:
- XPathFunction.NodesetNamespaceUriDefault(context);
- break;
- case XPathFunctionID.Boolean:
- XPathFunction.BooleanBoolean(context);
- break;
- case XPathFunctionID.False:
- XPathFunction.BooleanFalse(context);
- break;
- case XPathFunctionID.True:
- XPathFunction.BooleanTrue(context);
- break;
- case XPathFunctionID.Not:
- XPathFunction.BooleanNot(context);
- break;
- case XPathFunctionID.Lang:
- XPathFunction.BooleanLang(context);
- break;
- case XPathFunctionID.Contains:
- XPathFunction.StringContains(context);
- break;
- case XPathFunctionID.Number:
- XPathFunction.NumberNumber(context);
- break;
- case XPathFunctionID.NumberDefault:
- XPathFunction.NumberNumberDefault(context);
- break;
- case XPathFunctionID.Ceiling:
- XPathFunction.NumberCeiling(context);
- break;
- case XPathFunctionID.Floor:
- XPathFunction.NumberFloor(context);
- break;
- case XPathFunctionID.Round:
- XPathFunction.NumberRound(context);
- break;
- case XPathFunctionID.Sum:
- XPathFunction.NumberSum(context);
- break;
- case XPathFunctionID.String:
- XPathFunction.StringString(context);
- break;
- case XPathFunctionID.StringDefault:
- XPathFunction.StringStringDefault(context);
- break;
- case XPathFunctionID.ConcatTwo:
- XPathFunction.StringConcatTwo(context);
- break;
- case XPathFunctionID.ConcatThree:
- XPathFunction.StringConcatThree(context);
- break;
- case XPathFunctionID.ConcatFour:
- XPathFunction.StringConcatFour(context);
- break;
- case XPathFunctionID.StartsWith:
- XPathFunction.StringStartsWith(context);
- break;
- case XPathFunctionID.StringLength:
- XPathFunction.StringLength(context);
- break;
- case XPathFunctionID.StringLengthDefault:
- XPathFunction.StringLengthDefault(context);
- break;
- case XPathFunctionID.SubstringBefore:
- XPathFunction.SubstringBefore(context);
- break;
- case XPathFunctionID.SubstringAfter:
- XPathFunction.SubstringAfter(context);
- break;
- case XPathFunctionID.Substring:
- XPathFunction.Substring(context);
- break;
- case XPathFunctionID.SubstringLimit:
- XPathFunction.SubstringLimit(context);
- break;
- case XPathFunctionID.Translate:
- XPathFunction.Translate(context);
- break;
- case XPathFunctionID.NormalizeSpace:
- XPathFunction.NormalizeSpace(context);
- break;
- case XPathFunctionID.NormalizeSpaceDefault:
- XPathFunction.NormalizeSpaceDefault(context);
- break;
- }
- }
- internal static void BooleanBoolean(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- Value[] values = context.Values;
- while (arg.basePtr <= arg.endPtr)
- {
- values[arg.basePtr++].ConvertTo(context, ValueDataType.Boolean);
- }
- }
- internal static void BooleanFalse(ProcessingContext context)
- {
- context.PushFrame();
- int count = context.IterationCount;
- if (count > 0)
- {
- context.Push(false, count);
- }
- }
- internal static void BooleanNot(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- Value[] values = context.Values;
- while (arg.basePtr <= arg.endPtr)
- {
- values[arg.basePtr++].Not();
- }
- }
- internal static void BooleanTrue(ProcessingContext context)
- {
- context.PushFrame();
- int count = context.IterationCount;
- if (count > 0)
- {
- context.Push(true, count);
- }
- }
- internal static void BooleanLang(ProcessingContext context)
- {
- StackFrame langArg = context.TopArg;
- StackFrame sequences = context.TopSequenceArg;
- Value[] sequenceBuffer = context.Sequences;
- while (sequences.basePtr <= sequences.endPtr)
- {
- NodeSequence sourceSeq = sequenceBuffer[sequences.basePtr++].Sequence;
- for (int item = 0; item < sourceSeq.Count; ++item)
- {
- string lang = context.PeekString(langArg.basePtr).ToUpperInvariant();
- QueryNode node = sourceSeq.Items[item].Node;
- long pos = node.Node.CurrentPosition;
- node.Node.CurrentPosition = node.Position;
- string docLang = node.Node.XmlLang.ToUpperInvariant();
- node.Node.CurrentPosition = pos;
- if (lang.Length == docLang.Length && string.CompareOrdinal(lang, docLang) == 0)
- {
- context.SetValue(context, langArg.basePtr++, true);
- }
- else if (docLang.Length > 0 && lang.Length < docLang.Length && docLang.StartsWith(lang, StringComparison.Ordinal) && docLang[lang.Length] == '-')
- {
- context.SetValue(context, langArg.basePtr++, true);
- }
- else
- {
- context.SetValue(context, langArg.basePtr++, false);
- }
- }
- sequences.basePtr++;
- }
- }
- internal static void IterateAndPushSequences(ProcessingContext context)
- {
- StackFrame sequences = context.TopSequenceArg;
- Value[] sequenceBuffer = context.Sequences;
- context.PushFrame();
- while (sequences.basePtr <= sequences.endPtr)
- {
- NodeSequence sourceSeq = sequenceBuffer[sequences.basePtr++].Sequence;
- int count = sourceSeq.Count;
- if (count == 0)
- {
- context.PushSequence(NodeSequence.Empty);
- }
- else
- {
- for (int item = 0; item < sourceSeq.Count; ++item)
- {
- NodeSequence newSequence = context.CreateSequence();
- newSequence.StartNodeset();
- newSequence.Add(ref sourceSeq.Items[item]);
- newSequence.StopNodeset();
- context.Push(newSequence);
- }
- }
- }
- }
- internal static void NodesetCount(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- while (arg.basePtr <= arg.endPtr)
- {
- context.SetValue(context, arg.basePtr, context.PeekSequence(arg.basePtr).Count);
- arg.basePtr++;
- }
- }
- internal static void NodesetLast(ProcessingContext context)
- {
- context.TransferSequenceSize();
- }
- internal static void NodesetLocalName(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- while (arg.basePtr <= arg.endPtr)
- {
- NodeSequence sequence = context.PeekSequence(arg.basePtr);
- context.SetValue(context, arg.basePtr, sequence.LocalName);
- arg.basePtr++;
- }
- }
- internal static void NodesetLocalNameDefault(ProcessingContext context)
- {
- XPathFunction.IterateAndPushSequences(context);
- XPathFunction.NodesetLocalName(context);
- }
- internal static void NodesetName(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- while (arg.basePtr <= arg.endPtr)
- {
- NodeSequence sequence = context.PeekSequence(arg.basePtr);
- context.SetValue(context, arg.basePtr, sequence.Name);
- arg.basePtr++;
- }
- }
- internal static void NodesetNameDefault(ProcessingContext context)
- {
- XPathFunction.IterateAndPushSequences(context);
- XPathFunction.NodesetName(context);
- }
- internal static void NodesetNamespaceUri(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- while (arg.basePtr <= arg.endPtr)
- {
- NodeSequence sequence = context.PeekSequence(arg.basePtr);
- context.SetValue(context, arg.basePtr, sequence.Namespace);
- arg.basePtr++;
- }
- }
- internal static void NodesetNamespaceUriDefault(ProcessingContext context)
- {
- XPathFunction.IterateAndPushSequences(context);
- XPathFunction.NodesetNamespaceUri(context);
- }
- internal static void NodesetPosition(ProcessingContext context)
- {
- context.TransferSequencePositions();
- }
- internal static void NumberCeiling(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- while (arg.basePtr <= arg.endPtr)
- {
- context.SetValue(context, arg.basePtr, Math.Ceiling(context.PeekDouble(arg.basePtr)));
- arg.basePtr++;
- }
- }
- internal static void NumberNumber(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- Value[] values = context.Values;
- while (arg.basePtr <= arg.endPtr)
- {
- values[arg.basePtr++].ConvertTo(context, ValueDataType.Double);
- }
- }
- internal static void NumberNumberDefault(ProcessingContext context)
- {
- XPathFunction.IterateAndPushSequences(context);
- XPathFunction.NumberNumber(context);
- }
- internal static void NumberFloor(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- while (arg.basePtr <= arg.endPtr)
- {
- context.SetValue(context, arg.basePtr, Math.Floor(context.PeekDouble(arg.basePtr)));
- arg.basePtr++;
- }
- }
- internal static void NumberRound(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- while (arg.basePtr <= arg.endPtr)
- {
- double val = context.PeekDouble(arg.basePtr);
- context.SetValue(context, arg.basePtr, QueryValueModel.Round(context.PeekDouble(arg.basePtr)));
- arg.basePtr++;
- }
- }
- internal static void NumberSum(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- while (arg.basePtr <= arg.endPtr)
- {
- NodeSequence sequence = context.PeekSequence(arg.basePtr);
- double sum = 0.0;
- for (int item = 0; item < sequence.Count; ++item)
- {
- sum += QueryValueModel.Double(sequence[item].StringValue());
- }
- context.SetValue(context, arg.basePtr, sum);
- arg.basePtr++;
- }
- }
- internal static void StringString(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- Value[] values = context.Values;
- while (arg.basePtr <= arg.endPtr)
- {
- values[arg.basePtr++].ConvertTo(context, ValueDataType.String);
- }
- }
- internal static void StringStringDefault(ProcessingContext context)
- {
- XPathFunction.IterateAndPushSequences(context);
- XPathFunction.StringString(context);
- }
- internal static void StringConcatTwo(ProcessingContext context)
- {
- StackFrame arg1 = context[0];
- StackFrame arg2 = context[1];
- while (arg1.basePtr <= arg1.endPtr)
- {
- string str1 = context.PeekString(arg1.basePtr);
- string str2 = context.PeekString(arg2.basePtr);
- context.SetValue(context, arg2.basePtr, str1 + str2);
- arg1.basePtr++;
- arg2.basePtr++;
- }
- context.PopFrame();
- }
- internal static void StringConcatThree(ProcessingContext context)
- {
- StackFrame arg1 = context[0];
- StackFrame arg2 = context[1];
- StackFrame arg3 = context[2];
- while (arg1.basePtr <= arg1.endPtr)
- {
- string str1 = context.PeekString(arg1.basePtr);
- string str2 = context.PeekString(arg2.basePtr);
- string str3 = context.PeekString(arg3.basePtr);
- context.SetValue(context, arg3.basePtr, str1 + str2 + str3);
- arg1.basePtr++;
- arg2.basePtr++;
- arg3.basePtr++;
- }
- context.PopFrame();
- context.PopFrame();
- }
- internal static void StringConcatFour(ProcessingContext context)
- {
- StackFrame arg1 = context[0];
- StackFrame arg2 = context[1];
- StackFrame arg3 = context[2];
- StackFrame arg4 = context[3];
- while (arg1.basePtr <= arg1.endPtr)
- {
- string str1 = context.PeekString(arg1.basePtr);
- string str2 = context.PeekString(arg2.basePtr);
- string str3 = context.PeekString(arg3.basePtr);
- string str4 = context.PeekString(arg4.basePtr);
- context.SetValue(context, arg4.basePtr, str1 + str2 + str3 + str4);
- arg1.basePtr++;
- arg2.basePtr++;
- arg3.basePtr++;
- arg4.basePtr++;
- }
- context.PopFrame();
- context.PopFrame();
- context.PopFrame();
- }
- internal static void StringContains(ProcessingContext context)
- {
- StackFrame arg1 = context.TopArg;
- StackFrame arg2 = context.SecondArg;
- Fx.Assert(arg1.Count == arg2.Count, "");
- while (arg1.basePtr <= arg1.endPtr)
- {
- string leftString = context.PeekString(arg1.basePtr);
- string rightString = context.PeekString(arg2.basePtr);
- context.SetValue(context, arg2.basePtr, (-1 != leftString.IndexOf(rightString, StringComparison.Ordinal)));
- arg1.basePtr++;
- arg2.basePtr++;
- }
- context.PopFrame();
- }
- internal static void StringLength(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- while (arg.basePtr <= arg.endPtr)
- {
- context.SetValue(context, arg.basePtr, context.PeekString(arg.basePtr).Length);
- arg.basePtr++;
- }
- }
- internal static void StringLengthDefault(ProcessingContext context)
- {
- XPathFunction.IterateAndPushSequences(context);
- XPathFunction.ConvertFirstArg(context, ValueDataType.String);
- XPathFunction.StringLength(context);
- }
- internal static void StringStartsWith(ProcessingContext context)
- {
- StackFrame arg1 = context.TopArg;
- StackFrame arg2 = context.SecondArg;
- Fx.Assert(arg1.Count == arg2.Count, "");
- while (arg1.basePtr <= arg1.endPtr)
- {
- string leftString = context.PeekString(arg1.basePtr);
- string rightString = context.PeekString(arg2.basePtr);
- context.SetValue(context, arg2.basePtr, leftString.StartsWith(rightString, StringComparison.Ordinal));
- arg1.basePtr++;
- arg2.basePtr++;
- }
- context.PopFrame();
- }
- internal static void SubstringBefore(ProcessingContext context)
- {
- StackFrame arg1 = context.TopArg;
- StackFrame arg2 = context.SecondArg;
- Fx.Assert(arg1.Count == arg2.Count, "");
- while (arg1.basePtr <= arg1.endPtr)
- {
- string str1 = context.PeekString(arg1.basePtr);
- string str2 = context.PeekString(arg2.basePtr);
- int idx = str1.IndexOf(str2, StringComparison.Ordinal);
- context.SetValue(context, arg2.basePtr, idx == -1 ? string.Empty : str1.Substring(0, idx));
- arg1.basePtr++;
- arg2.basePtr++;
- }
- context.PopFrame();
- }
- internal static void SubstringAfter(ProcessingContext context)
- {
- StackFrame arg1 = context.TopArg;
- StackFrame arg2 = context.SecondArg;
- Fx.Assert(arg1.Count == arg2.Count, "");
- while (arg1.basePtr <= arg1.endPtr)
- {
- string str1 = context.PeekString(arg1.basePtr);
- string str2 = context.PeekString(arg2.basePtr);
- int idx = str1.IndexOf(str2, StringComparison.Ordinal);
- context.SetValue(context, arg2.basePtr, idx == -1 ? string.Empty : str1.Substring(idx + str2.Length));
- arg1.basePtr++;
- arg2.basePtr++;
- }
- context.PopFrame();
- }
- internal static void Substring(ProcessingContext context)
- {
- StackFrame arg1 = context.TopArg;
- StackFrame arg2 = context.SecondArg;
- Fx.Assert(arg1.Count == arg2.Count, "");
- while (arg1.basePtr <= arg1.endPtr)
- {
- string str = context.PeekString(arg1.basePtr);
- int startAt = ((int)Math.Round(context.PeekDouble(arg2.basePtr))) - 1;
- if (startAt < 0)
- {
- startAt = 0;
- }
- context.SetValue(context, arg2.basePtr, (startAt >= str.Length) ? string.Empty : str.Substring(startAt));
- arg1.basePtr++;
- arg2.basePtr++;
- }
- context.PopFrame();
- }
- internal static void SubstringLimit(ProcessingContext context)
- {
- StackFrame argString = context.TopArg;
- StackFrame argStartAt = context.SecondArg;
- StackFrame argLimit = context[2];
- Fx.Assert(argString.Count == argStartAt.Count, "");
- Fx.Assert(argString.Count == argLimit.Count, "");
- while (argString.basePtr <= argString.endPtr)
- {
- string str = context.PeekString(argString.basePtr);
- int startAt = ((int)Math.Round(context.PeekDouble(argStartAt.basePtr))) - 1;
- if (startAt < 0)
- {
- startAt = 0;
- }
- int length = (int)Math.Round(context.PeekDouble(argLimit.basePtr));
- string substr;
- if (length < 1 || ((startAt + length) >= str.Length))
- {
- substr = string.Empty;
- }
- else
- {
- substr = str.Substring(startAt, length);
- }
- context.SetValue(context, argLimit.basePtr, substr);
- argStartAt.basePtr++;
- argString.basePtr++;
- argLimit.basePtr++;
- }
- context.PopFrame();
- context.PopFrame();
- }
- internal static void Translate(ProcessingContext context)
- {
- StackFrame argSource = context.TopArg;
- StackFrame argKeys = context.SecondArg;
- StackFrame argValues = context[2];
- // PERF, [....], this is really slow.
- StringBuilder builder = new StringBuilder();
- while (argSource.basePtr <= argSource.endPtr)
- {
- builder.Length = 0;
- string source = context.PeekString(argSource.basePtr);
- string keys = context.PeekString(argKeys.basePtr);
- string values = context.PeekString(argValues.basePtr);
- for (int i = 0; i < source.Length; ++i)
- {
- char c = source[i];
- int idx = keys.IndexOf(c);
- if (idx < 0)
- {
- builder.Append(c);
- }
- else if (idx < values.Length)
- {
- builder.Append(values[idx]);
- }
- }
- context.SetValue(context, argValues.basePtr, builder.ToString());
- argSource.basePtr++;
- argKeys.basePtr++;
- argValues.basePtr++;
- }
- context.PopFrame();
- context.PopFrame();
- }
- internal static void NormalizeSpace(ProcessingContext context)
- {
- StackFrame argStr = context.TopArg;
- StringBuilder builder = new StringBuilder();
- while (argStr.basePtr <= argStr.endPtr)
- {
- char[] whitespace = new char[] { ' ', '\t', '\r', '\n' };
- string str = context.PeekString(argStr.basePtr).Trim(whitespace);
- bool eatingWhitespace = false;
- builder.Length = 0;
- for (int i = 0; i < str.Length; ++i)
- {
- char c = str[i];
- if (XPathCharTypes.IsWhitespace(c))
- {
- if (!eatingWhitespace)
- {
- builder.Append(' ');
- eatingWhitespace = true;
- }
- }
- else
- {
- builder.Append(c);
- eatingWhitespace = false;
- }
- }
- context.SetValue(context, argStr.basePtr, builder.ToString());
- argStr.basePtr++;
- }
- }
- internal static void NormalizeSpaceDefault(ProcessingContext context)
- {
- XPathFunction.IterateAndPushSequences(context);
- XPathFunction.ConvertFirstArg(context, ValueDataType.String);
- XPathFunction.NormalizeSpace(context);
- }
- #if NO
- internal static bool IsWhitespace(char c)
- {
- return c == ' ' || c == '\r' || c == '\n' || c == '\t';
- }
- #endif
- }
- }
|