QueryFunctions.cs 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Dispatcher
  5. {
  6. using System.Collections.Generic;
  7. using System.Runtime;
  8. using System.Text;
  9. using System.Xml.XPath;
  10. using System.Xml.Xsl;
  11. internal class FunctionCallOpcode : Opcode
  12. {
  13. QueryFunction function;
  14. internal FunctionCallOpcode(QueryFunction function)
  15. : base(OpcodeID.Function)
  16. {
  17. Fx.Assert(null != function, "");
  18. this.function = function;
  19. }
  20. internal override bool Equals(Opcode op)
  21. {
  22. if (base.Equals(op))
  23. {
  24. FunctionCallOpcode functionCall = (FunctionCallOpcode)op;
  25. return functionCall.function.Equals(this.function);
  26. }
  27. return false;
  28. }
  29. internal override Opcode Eval(ProcessingContext context)
  30. {
  31. this.function.Eval(context);
  32. return this.next;
  33. }
  34. #if DEBUG_FILTER
  35. public override string ToString()
  36. {
  37. return string.Format("{0} {1}", base.ToString(), this.function.ToString());
  38. }
  39. #endif
  40. }
  41. internal class XsltFunctionCallOpcode : Opcode
  42. {
  43. static object[] NullArgs = new object[0];
  44. int argCount;
  45. XsltContext xsltContext;
  46. IXsltContextFunction function;
  47. List<NodeSequenceIterator> iterList;
  48. // REFACTOR, [....], make this a function on QueryValueModel
  49. internal XsltFunctionCallOpcode(XsltContext context, IXsltContextFunction function, int argCount)
  50. : base(OpcodeID.XsltFunction)
  51. {
  52. Fx.Assert(null != context && null != function, "");
  53. this.xsltContext = context;
  54. this.function = function;
  55. this.argCount = argCount;
  56. for (int i = 0; i < function.Maxargs; ++i)
  57. {
  58. if (function.ArgTypes[i] == XPathResultType.NodeSet)
  59. {
  60. this.iterList = new List<NodeSequenceIterator>();
  61. break;
  62. }
  63. }
  64. // Make sure the return type is valid
  65. switch (this.function.ReturnType)
  66. {
  67. case XPathResultType.String:
  68. case XPathResultType.Number:
  69. case XPathResultType.Boolean:
  70. case XPathResultType.NodeSet:
  71. break;
  72. default:
  73. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.InvalidType, SR.GetString(SR.QueryFunctionTypeNotSupported, this.function.ReturnType.ToString())));
  74. }
  75. }
  76. internal override bool Equals(Opcode op)
  77. {
  78. // We have no way of knowing if an Xslt function is stateless and can be merged
  79. return false;
  80. }
  81. internal override Opcode Eval(ProcessingContext context)
  82. {
  83. XPathNavigator nav = context.Processor.ContextNode;
  84. if (nav != null && context.Processor.ContextMessage != null)
  85. {
  86. ((SeekableMessageNavigator)nav).Atomize();
  87. }
  88. if (this.argCount == 0)
  89. {
  90. context.PushFrame();
  91. int count = context.IterationCount;
  92. if (count > 0)
  93. {
  94. object ret = this.function.Invoke(this.xsltContext, NullArgs, nav);
  95. switch (this.function.ReturnType)
  96. {
  97. case XPathResultType.String:
  98. context.Push((string)ret, count);
  99. break;
  100. case XPathResultType.Number:
  101. context.Push((double)ret, count);
  102. break;
  103. case XPathResultType.Boolean:
  104. context.Push((bool)ret, count);
  105. break;
  106. case XPathResultType.NodeSet:
  107. NodeSequence seq = context.CreateSequence();
  108. XPathNodeIterator iter = (XPathNodeIterator)ret;
  109. seq.Add(iter);
  110. context.Push(seq, count);
  111. break;
  112. default:
  113. // This should never be reached
  114. throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.Unexpected, SR.GetString(SR.QueryFunctionTypeNotSupported, this.function.ReturnType.ToString())));
  115. }
  116. }
  117. }
  118. else
  119. {
  120. // PERF, [....], see if we can cache these arrays to avoid allocations
  121. object[] xsltArgs = new object[this.argCount];
  122. int iterationCount = context.TopArg.Count;
  123. for (int iteration = 0; iteration < iterationCount; ++iteration)
  124. {
  125. for (int i = 0; i < this.argCount; ++i)
  126. {
  127. StackFrame arg = context[i];
  128. Fx.Assert(iteration < arg.Count, "");
  129. switch (this.function.ArgTypes[i])
  130. {
  131. case XPathResultType.String:
  132. xsltArgs[i] = context.PeekString(arg[iteration]);
  133. break;
  134. case XPathResultType.Number:
  135. xsltArgs[i] = context.PeekDouble(arg[iteration]);
  136. break;
  137. case XPathResultType.Boolean:
  138. xsltArgs[i] = context.PeekBoolean(arg[iteration]);
  139. break;
  140. case XPathResultType.NodeSet:
  141. NodeSequenceIterator iter = new NodeSequenceIterator(context.PeekSequence(arg[iteration]));
  142. xsltArgs[i] = iter;
  143. this.iterList.Add(iter);
  144. break;
  145. default:
  146. // This should never be reached
  147. throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.Unexpected, SR.GetString(SR.QueryFunctionTypeNotSupported, this.function.ArgTypes[i].ToString())));
  148. }
  149. }
  150. object ret = this.function.Invoke(this.xsltContext, xsltArgs, nav);
  151. if (this.iterList != null)
  152. {
  153. for (int i = 0; i < this.iterList.Count; ++i)
  154. {
  155. this.iterList[i].Clear();
  156. }
  157. this.iterList.Clear();
  158. }
  159. switch (this.function.ReturnType)
  160. {
  161. case XPathResultType.String:
  162. context.SetValue(context, context[this.argCount - 1][iteration], (string)ret);
  163. break;
  164. case XPathResultType.Number:
  165. context.SetValue(context, context[this.argCount - 1][iteration], (double)ret);
  166. break;
  167. case XPathResultType.Boolean:
  168. context.SetValue(context, context[this.argCount - 1][iteration], (bool)ret);
  169. break;
  170. case XPathResultType.NodeSet:
  171. NodeSequence seq = context.CreateSequence();
  172. XPathNodeIterator iter = (XPathNodeIterator)ret;
  173. seq.Add(iter);
  174. context.SetValue(context, context[this.argCount - 1][iteration], seq);
  175. break;
  176. default:
  177. // This should never be reached
  178. throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.Unexpected, SR.GetString(SR.QueryFunctionTypeNotSupported, this.function.ReturnType.ToString())));
  179. }
  180. }
  181. for (int i = 0; i < this.argCount - 1; ++i)
  182. {
  183. context.PopFrame();
  184. }
  185. }
  186. return this.next;
  187. }
  188. #if DEBUG_FILTER
  189. public override string ToString()
  190. {
  191. return string.Format("{0} IXsltContextFunction", base.ToString());
  192. }
  193. #endif
  194. }
  195. internal enum QueryFunctionFlag
  196. {
  197. None = 0x00000000,
  198. UsesContextNode = 0x00000001
  199. }
  200. internal abstract class QueryFunction
  201. {
  202. static ValueDataType[] emptyParams = new ValueDataType[0];
  203. QueryFunctionFlag flags;
  204. protected string name;
  205. ValueDataType[] paramTypes;
  206. ValueDataType returnType;
  207. internal QueryFunction(string name, ValueDataType returnType)
  208. : this(name, returnType, QueryFunction.emptyParams, QueryFunctionFlag.None)
  209. {
  210. }
  211. internal QueryFunction(string name, ValueDataType returnType, QueryFunctionFlag flags)
  212. : this(name, returnType, QueryFunction.emptyParams, flags)
  213. {
  214. }
  215. internal QueryFunction(string name, ValueDataType returnType, ValueDataType[] paramTypes)
  216. : this(name, returnType, paramTypes, QueryFunctionFlag.None)
  217. {
  218. }
  219. internal QueryFunction(string name, ValueDataType returnType, ValueDataType[] paramTypes, QueryFunctionFlag flags)
  220. {
  221. Fx.Assert(null != paramTypes, "");
  222. Fx.Assert(null != name, "");
  223. this.name = name;
  224. this.returnType = returnType;
  225. this.paramTypes = paramTypes;
  226. this.flags = flags;
  227. }
  228. internal ValueDataType[] ParamTypes
  229. {
  230. get
  231. {
  232. return this.paramTypes;
  233. }
  234. }
  235. internal ValueDataType ReturnType
  236. {
  237. get
  238. {
  239. return this.returnType;
  240. }
  241. }
  242. internal bool Bind(string name, XPathExprList args)
  243. {
  244. Fx.Assert(null != name && null != args, "");
  245. if (
  246. 0 != string.CompareOrdinal(this.name, name)
  247. || this.paramTypes.Length != args.Count
  248. )
  249. {
  250. return false;
  251. }
  252. return (this.paramTypes.Length == args.Count);
  253. }
  254. internal abstract bool Equals(QueryFunction function);
  255. internal abstract void Eval(ProcessingContext context);
  256. internal bool TestFlag(QueryFunctionFlag flag)
  257. {
  258. return (0 != (this.flags & flag));
  259. }
  260. #if DEBUG_FILTER
  261. public override string ToString()
  262. {
  263. StringBuilder text = new StringBuilder();
  264. text.Append(this.name);
  265. text.Append('(');
  266. for (int i = 0; i < this.paramTypes.Length; ++i)
  267. {
  268. if (i > 0)
  269. {
  270. text.Append(',');
  271. }
  272. text.Append(this.paramTypes[i].ToString());
  273. }
  274. text.Append(')');
  275. return text.ToString();
  276. }
  277. #endif
  278. }
  279. internal interface IFunctionLibrary
  280. {
  281. QueryFunction Bind(string functionName, string functionNamespace, XPathExprList args);
  282. }
  283. internal enum XPathFunctionID
  284. {
  285. // Set
  286. IterateSequences,
  287. Count,
  288. Position,
  289. Last,
  290. LocalName,
  291. LocalNameDefault,
  292. Name,
  293. NameDefault,
  294. NamespaceUri,
  295. NamespaceUriDefault,
  296. // Boolean
  297. Boolean,
  298. Not,
  299. True,
  300. False,
  301. Lang,
  302. // Number
  303. Number,
  304. NumberDefault,
  305. Ceiling,
  306. Floor,
  307. Round,
  308. Sum,
  309. // String
  310. String,
  311. StringDefault,
  312. StartsWith,
  313. ConcatTwo,
  314. ConcatThree,
  315. ConcatFour,
  316. Contains,
  317. NormalizeSpace,
  318. NormalizeSpaceDefault,
  319. StringLength,
  320. StringLengthDefault,
  321. SubstringBefore,
  322. SubstringAfter,
  323. Substring,
  324. SubstringLimit,
  325. Translate
  326. }
  327. internal class XPathFunctionLibrary : IFunctionLibrary
  328. {
  329. static XPathFunction[] functionTable;
  330. static XPathFunctionLibrary()
  331. {
  332. XPathFunctionLibrary.functionTable = new XPathFunction[] {
  333. new XPathFunction(XPathFunctionID.Boolean, "boolean", ValueDataType.Boolean, new ValueDataType[] { ValueDataType.None }),
  334. new XPathFunction(XPathFunctionID.False, "false", ValueDataType.Boolean),
  335. new XPathFunction(XPathFunctionID.True, "true", ValueDataType.Boolean),
  336. new XPathFunction(XPathFunctionID.Not, "not", ValueDataType.Boolean, new ValueDataType[] { ValueDataType.Boolean }),
  337. new XPathFunction(XPathFunctionID.Lang, "lang", ValueDataType.Boolean, new ValueDataType[] { ValueDataType.String }),
  338. new XPathFunction(XPathFunctionID.Number, "number", ValueDataType.Double, new ValueDataType[] { ValueDataType.None }),
  339. new XPathFunction(XPathFunctionID.NumberDefault, "number", ValueDataType.Double),
  340. new XPathFunction(XPathFunctionID.Sum, "sum", ValueDataType.Double, new ValueDataType[] { ValueDataType.Sequence }),
  341. new XPathFunction(XPathFunctionID.Floor, "floor", ValueDataType.Double, new ValueDataType[] { ValueDataType.Double }),
  342. new XPathFunction(XPathFunctionID.Ceiling, "ceiling", ValueDataType.Double, new ValueDataType[] { ValueDataType.Double }),
  343. new XPathFunction(XPathFunctionID.Round, "round", ValueDataType.Double, new ValueDataType[] { ValueDataType.Double }),
  344. new XPathFunction(XPathFunctionID.String, "string", ValueDataType.String, new ValueDataType[] { ValueDataType.None }),
  345. new XPathFunction(XPathFunctionID.StringDefault, "string", ValueDataType.String, QueryFunctionFlag.UsesContextNode),
  346. new XPathFunction(XPathFunctionID.ConcatTwo, "concat", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.String }),
  347. new XPathFunction(XPathFunctionID.ConcatThree, "concat", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.String, ValueDataType.String }),
  348. new XPathFunction(XPathFunctionID.ConcatFour, "concat", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.String, ValueDataType.String, ValueDataType.String }),
  349. new XPathFunction(XPathFunctionID.StartsWith, "starts-with", ValueDataType.Boolean, new ValueDataType[] { ValueDataType.String, ValueDataType.String }),
  350. new XPathFunction(XPathFunctionID.NormalizeSpace, "normalize-space", ValueDataType.String, new ValueDataType[] { ValueDataType.String }),
  351. new XPathFunction(XPathFunctionID.NormalizeSpaceDefault, "normalize-space", ValueDataType.String, QueryFunctionFlag.UsesContextNode),
  352. new XPathFunction(XPathFunctionID.Contains, "contains", ValueDataType.Boolean, new ValueDataType[] { ValueDataType.String, ValueDataType.String }),
  353. new XPathFunction(XPathFunctionID.SubstringBefore, "substring-before", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.String }),
  354. new XPathFunction(XPathFunctionID.SubstringAfter, "substring-after", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.String }),
  355. new XPathFunction(XPathFunctionID.Substring, "substring", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.Double }),
  356. new XPathFunction(XPathFunctionID.SubstringLimit, "substring", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.Double, ValueDataType.Double }),
  357. new XPathFunction(XPathFunctionID.StringLength, "string-length", ValueDataType.Double, new ValueDataType[] { ValueDataType.String }),
  358. new XPathFunction(XPathFunctionID.StringLengthDefault, "string-length", ValueDataType.Double, QueryFunctionFlag.UsesContextNode),
  359. new XPathFunction(XPathFunctionID.Translate, "translate", ValueDataType.String, new ValueDataType[] { ValueDataType.String, ValueDataType.String, ValueDataType.String }),
  360. new XPathFunction(XPathFunctionID.Last, "last", ValueDataType.Double, QueryFunctionFlag.UsesContextNode),
  361. new XPathFunction(XPathFunctionID.Position, "position", ValueDataType.Double, QueryFunctionFlag.UsesContextNode),
  362. new XPathFunction(XPathFunctionID.Count, "count", ValueDataType.Double, new ValueDataType[] { ValueDataType.Sequence }),
  363. new XPathFunction(XPathFunctionID.LocalName, "local-name", ValueDataType.String, new ValueDataType[] { ValueDataType.Sequence }),
  364. new XPathFunction(XPathFunctionID.LocalNameDefault, "local-name", ValueDataType.String, QueryFunctionFlag.UsesContextNode),
  365. new XPathFunction(XPathFunctionID.Name, "name", ValueDataType.String, new ValueDataType[] { ValueDataType.Sequence }),
  366. new XPathFunction(XPathFunctionID.NameDefault, "name", ValueDataType.String, QueryFunctionFlag.UsesContextNode),
  367. new XPathFunction(XPathFunctionID.NamespaceUri, "namespace-uri", ValueDataType.String, new ValueDataType[] { ValueDataType.Sequence }),
  368. new XPathFunction(XPathFunctionID.NamespaceUriDefault, "namespace-uri", ValueDataType.String, QueryFunctionFlag.UsesContextNode)
  369. };
  370. }
  371. internal XPathFunctionLibrary()
  372. {
  373. }
  374. public QueryFunction Bind(string functionName, string functionNamespace, XPathExprList args)
  375. {
  376. Fx.Assert(null != functionName && null != args, "");
  377. // Variable length argument list requires a special case here
  378. if (functionName == "concat" && args.Count > 4)
  379. {
  380. ConcatFunction f = new ConcatFunction(args.Count);
  381. if (f.Bind(functionName, args))
  382. {
  383. return f;
  384. }
  385. }
  386. else
  387. {
  388. for (int i = 0; i < XPathFunctionLibrary.functionTable.Length; ++i)
  389. {
  390. // XPath functions are typeless, so don't check types
  391. if (XPathFunctionLibrary.functionTable[i].Bind(functionName, args))
  392. {
  393. return XPathFunctionLibrary.functionTable[i];
  394. }
  395. }
  396. }
  397. return null;
  398. }
  399. }
  400. internal class ConcatFunction : QueryFunction
  401. {
  402. int argCount;
  403. internal ConcatFunction(int argCount)
  404. : base("concat", ValueDataType.String, ConcatFunction.MakeTypes(argCount))
  405. {
  406. Fx.Assert(argCount >= 2, "");
  407. this.argCount = argCount;
  408. }
  409. internal override bool Equals(QueryFunction function)
  410. {
  411. ConcatFunction f = function as ConcatFunction;
  412. if (f != null && this.argCount == f.argCount)
  413. {
  414. return true;
  415. }
  416. return false;
  417. }
  418. internal override void Eval(ProcessingContext context)
  419. {
  420. Fx.Assert(context != null, "");
  421. StackFrame[] args = new StackFrame[argCount];
  422. for (int i = 0; i < this.argCount; ++i)
  423. {
  424. args[i] = context[i];
  425. }
  426. StringBuilder builder = new StringBuilder();
  427. while (args[0].basePtr <= args[0].endPtr)
  428. {
  429. builder.Length = 0;
  430. for (int i = 0; i < this.argCount; ++i)
  431. {
  432. builder.Append(context.PeekString(args[i].basePtr));
  433. }
  434. context.SetValue(context, args[this.argCount - 1].basePtr, builder.ToString());
  435. for (int i = 0; i < this.argCount; ++i)
  436. {
  437. args[i].basePtr++;
  438. }
  439. }
  440. for (int i = 0; i < this.argCount - 1; ++i)
  441. {
  442. context.PopFrame();
  443. }
  444. }
  445. internal static ValueDataType[] MakeTypes(int size)
  446. {
  447. ValueDataType[] t = new ValueDataType[size];
  448. for (int i = 0; i < size; ++i)
  449. {
  450. t[i] = ValueDataType.String;
  451. }
  452. return t;
  453. }
  454. }
  455. internal class XPathFunction : QueryFunction
  456. {
  457. XPathFunctionID functionID;
  458. internal XPathFunction(XPathFunctionID functionID, string name, ValueDataType returnType)
  459. : base(name, returnType)
  460. {
  461. this.functionID = functionID;
  462. }
  463. internal XPathFunction(XPathFunctionID functionID, string name, ValueDataType returnType, QueryFunctionFlag flags)
  464. : base(name, returnType, flags)
  465. {
  466. this.functionID = functionID;
  467. }
  468. internal XPathFunction(XPathFunctionID functionID, string name, ValueDataType returnType, ValueDataType[] argTypes)
  469. : base(name, returnType, argTypes)
  470. {
  471. this.functionID = functionID;
  472. }
  473. internal XPathFunctionID ID
  474. {
  475. get
  476. {
  477. return this.functionID;
  478. }
  479. }
  480. internal override bool Equals(QueryFunction function)
  481. {
  482. XPathFunction xpathFunction = function as XPathFunction;
  483. if (null == xpathFunction)
  484. {
  485. return false;
  486. }
  487. return (xpathFunction.ID == this.ID);
  488. }
  489. static void ConvertFirstArg(ProcessingContext context, ValueDataType type)
  490. {
  491. StackFrame arg = context.TopArg;
  492. Value[] values = context.Values;
  493. while (arg.basePtr <= arg.endPtr)
  494. {
  495. values[arg.basePtr++].ConvertTo(context, type);
  496. }
  497. }
  498. internal override void Eval(ProcessingContext context)
  499. {
  500. Fx.Assert(null != context, "");
  501. switch (this.functionID)
  502. {
  503. default:
  504. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException(SR.GetString(SR.QueryNotImplemented, this.name)));
  505. case XPathFunctionID.IterateSequences:
  506. XPathFunction.IterateAndPushSequences(context);
  507. break;
  508. case XPathFunctionID.Count:
  509. XPathFunction.NodesetCount(context);
  510. break;
  511. case XPathFunctionID.Position:
  512. XPathFunction.NodesetPosition(context);
  513. break;
  514. case XPathFunctionID.Last:
  515. XPathFunction.NodesetLast(context);
  516. break;
  517. case XPathFunctionID.LocalName:
  518. XPathFunction.NodesetLocalName(context);
  519. break;
  520. case XPathFunctionID.LocalNameDefault:
  521. XPathFunction.NodesetLocalNameDefault(context);
  522. break;
  523. case XPathFunctionID.Name:
  524. XPathFunction.NodesetName(context);
  525. break;
  526. case XPathFunctionID.NameDefault:
  527. XPathFunction.NodesetNameDefault(context);
  528. break;
  529. case XPathFunctionID.NamespaceUri:
  530. XPathFunction.NodesetNamespaceUri(context);
  531. break;
  532. case XPathFunctionID.NamespaceUriDefault:
  533. XPathFunction.NodesetNamespaceUriDefault(context);
  534. break;
  535. case XPathFunctionID.Boolean:
  536. XPathFunction.BooleanBoolean(context);
  537. break;
  538. case XPathFunctionID.False:
  539. XPathFunction.BooleanFalse(context);
  540. break;
  541. case XPathFunctionID.True:
  542. XPathFunction.BooleanTrue(context);
  543. break;
  544. case XPathFunctionID.Not:
  545. XPathFunction.BooleanNot(context);
  546. break;
  547. case XPathFunctionID.Lang:
  548. XPathFunction.BooleanLang(context);
  549. break;
  550. case XPathFunctionID.Contains:
  551. XPathFunction.StringContains(context);
  552. break;
  553. case XPathFunctionID.Number:
  554. XPathFunction.NumberNumber(context);
  555. break;
  556. case XPathFunctionID.NumberDefault:
  557. XPathFunction.NumberNumberDefault(context);
  558. break;
  559. case XPathFunctionID.Ceiling:
  560. XPathFunction.NumberCeiling(context);
  561. break;
  562. case XPathFunctionID.Floor:
  563. XPathFunction.NumberFloor(context);
  564. break;
  565. case XPathFunctionID.Round:
  566. XPathFunction.NumberRound(context);
  567. break;
  568. case XPathFunctionID.Sum:
  569. XPathFunction.NumberSum(context);
  570. break;
  571. case XPathFunctionID.String:
  572. XPathFunction.StringString(context);
  573. break;
  574. case XPathFunctionID.StringDefault:
  575. XPathFunction.StringStringDefault(context);
  576. break;
  577. case XPathFunctionID.ConcatTwo:
  578. XPathFunction.StringConcatTwo(context);
  579. break;
  580. case XPathFunctionID.ConcatThree:
  581. XPathFunction.StringConcatThree(context);
  582. break;
  583. case XPathFunctionID.ConcatFour:
  584. XPathFunction.StringConcatFour(context);
  585. break;
  586. case XPathFunctionID.StartsWith:
  587. XPathFunction.StringStartsWith(context);
  588. break;
  589. case XPathFunctionID.StringLength:
  590. XPathFunction.StringLength(context);
  591. break;
  592. case XPathFunctionID.StringLengthDefault:
  593. XPathFunction.StringLengthDefault(context);
  594. break;
  595. case XPathFunctionID.SubstringBefore:
  596. XPathFunction.SubstringBefore(context);
  597. break;
  598. case XPathFunctionID.SubstringAfter:
  599. XPathFunction.SubstringAfter(context);
  600. break;
  601. case XPathFunctionID.Substring:
  602. XPathFunction.Substring(context);
  603. break;
  604. case XPathFunctionID.SubstringLimit:
  605. XPathFunction.SubstringLimit(context);
  606. break;
  607. case XPathFunctionID.Translate:
  608. XPathFunction.Translate(context);
  609. break;
  610. case XPathFunctionID.NormalizeSpace:
  611. XPathFunction.NormalizeSpace(context);
  612. break;
  613. case XPathFunctionID.NormalizeSpaceDefault:
  614. XPathFunction.NormalizeSpaceDefault(context);
  615. break;
  616. }
  617. }
  618. internal static void BooleanBoolean(ProcessingContext context)
  619. {
  620. StackFrame arg = context.TopArg;
  621. Value[] values = context.Values;
  622. while (arg.basePtr <= arg.endPtr)
  623. {
  624. values[arg.basePtr++].ConvertTo(context, ValueDataType.Boolean);
  625. }
  626. }
  627. internal static void BooleanFalse(ProcessingContext context)
  628. {
  629. context.PushFrame();
  630. int count = context.IterationCount;
  631. if (count > 0)
  632. {
  633. context.Push(false, count);
  634. }
  635. }
  636. internal static void BooleanNot(ProcessingContext context)
  637. {
  638. StackFrame arg = context.TopArg;
  639. Value[] values = context.Values;
  640. while (arg.basePtr <= arg.endPtr)
  641. {
  642. values[arg.basePtr++].Not();
  643. }
  644. }
  645. internal static void BooleanTrue(ProcessingContext context)
  646. {
  647. context.PushFrame();
  648. int count = context.IterationCount;
  649. if (count > 0)
  650. {
  651. context.Push(true, count);
  652. }
  653. }
  654. internal static void BooleanLang(ProcessingContext context)
  655. {
  656. StackFrame langArg = context.TopArg;
  657. StackFrame sequences = context.TopSequenceArg;
  658. Value[] sequenceBuffer = context.Sequences;
  659. while (sequences.basePtr <= sequences.endPtr)
  660. {
  661. NodeSequence sourceSeq = sequenceBuffer[sequences.basePtr++].Sequence;
  662. for (int item = 0; item < sourceSeq.Count; ++item)
  663. {
  664. string lang = context.PeekString(langArg.basePtr).ToUpperInvariant();
  665. QueryNode node = sourceSeq.Items[item].Node;
  666. long pos = node.Node.CurrentPosition;
  667. node.Node.CurrentPosition = node.Position;
  668. string docLang = node.Node.XmlLang.ToUpperInvariant();
  669. node.Node.CurrentPosition = pos;
  670. if (lang.Length == docLang.Length && string.CompareOrdinal(lang, docLang) == 0)
  671. {
  672. context.SetValue(context, langArg.basePtr++, true);
  673. }
  674. else if (docLang.Length > 0 && lang.Length < docLang.Length && docLang.StartsWith(lang, StringComparison.Ordinal) && docLang[lang.Length] == '-')
  675. {
  676. context.SetValue(context, langArg.basePtr++, true);
  677. }
  678. else
  679. {
  680. context.SetValue(context, langArg.basePtr++, false);
  681. }
  682. }
  683. sequences.basePtr++;
  684. }
  685. }
  686. internal static void IterateAndPushSequences(ProcessingContext context)
  687. {
  688. StackFrame sequences = context.TopSequenceArg;
  689. Value[] sequenceBuffer = context.Sequences;
  690. context.PushFrame();
  691. while (sequences.basePtr <= sequences.endPtr)
  692. {
  693. NodeSequence sourceSeq = sequenceBuffer[sequences.basePtr++].Sequence;
  694. int count = sourceSeq.Count;
  695. if (count == 0)
  696. {
  697. context.PushSequence(NodeSequence.Empty);
  698. }
  699. else
  700. {
  701. for (int item = 0; item < sourceSeq.Count; ++item)
  702. {
  703. NodeSequence newSequence = context.CreateSequence();
  704. newSequence.StartNodeset();
  705. newSequence.Add(ref sourceSeq.Items[item]);
  706. newSequence.StopNodeset();
  707. context.Push(newSequence);
  708. }
  709. }
  710. }
  711. }
  712. internal static void NodesetCount(ProcessingContext context)
  713. {
  714. StackFrame arg = context.TopArg;
  715. while (arg.basePtr <= arg.endPtr)
  716. {
  717. context.SetValue(context, arg.basePtr, context.PeekSequence(arg.basePtr).Count);
  718. arg.basePtr++;
  719. }
  720. }
  721. internal static void NodesetLast(ProcessingContext context)
  722. {
  723. context.TransferSequenceSize();
  724. }
  725. internal static void NodesetLocalName(ProcessingContext context)
  726. {
  727. StackFrame arg = context.TopArg;
  728. while (arg.basePtr <= arg.endPtr)
  729. {
  730. NodeSequence sequence = context.PeekSequence(arg.basePtr);
  731. context.SetValue(context, arg.basePtr, sequence.LocalName);
  732. arg.basePtr++;
  733. }
  734. }
  735. internal static void NodesetLocalNameDefault(ProcessingContext context)
  736. {
  737. XPathFunction.IterateAndPushSequences(context);
  738. XPathFunction.NodesetLocalName(context);
  739. }
  740. internal static void NodesetName(ProcessingContext context)
  741. {
  742. StackFrame arg = context.TopArg;
  743. while (arg.basePtr <= arg.endPtr)
  744. {
  745. NodeSequence sequence = context.PeekSequence(arg.basePtr);
  746. context.SetValue(context, arg.basePtr, sequence.Name);
  747. arg.basePtr++;
  748. }
  749. }
  750. internal static void NodesetNameDefault(ProcessingContext context)
  751. {
  752. XPathFunction.IterateAndPushSequences(context);
  753. XPathFunction.NodesetName(context);
  754. }
  755. internal static void NodesetNamespaceUri(ProcessingContext context)
  756. {
  757. StackFrame arg = context.TopArg;
  758. while (arg.basePtr <= arg.endPtr)
  759. {
  760. NodeSequence sequence = context.PeekSequence(arg.basePtr);
  761. context.SetValue(context, arg.basePtr, sequence.Namespace);
  762. arg.basePtr++;
  763. }
  764. }
  765. internal static void NodesetNamespaceUriDefault(ProcessingContext context)
  766. {
  767. XPathFunction.IterateAndPushSequences(context);
  768. XPathFunction.NodesetNamespaceUri(context);
  769. }
  770. internal static void NodesetPosition(ProcessingContext context)
  771. {
  772. context.TransferSequencePositions();
  773. }
  774. internal static void NumberCeiling(ProcessingContext context)
  775. {
  776. StackFrame arg = context.TopArg;
  777. while (arg.basePtr <= arg.endPtr)
  778. {
  779. context.SetValue(context, arg.basePtr, Math.Ceiling(context.PeekDouble(arg.basePtr)));
  780. arg.basePtr++;
  781. }
  782. }
  783. internal static void NumberNumber(ProcessingContext context)
  784. {
  785. StackFrame arg = context.TopArg;
  786. Value[] values = context.Values;
  787. while (arg.basePtr <= arg.endPtr)
  788. {
  789. values[arg.basePtr++].ConvertTo(context, ValueDataType.Double);
  790. }
  791. }
  792. internal static void NumberNumberDefault(ProcessingContext context)
  793. {
  794. XPathFunction.IterateAndPushSequences(context);
  795. XPathFunction.NumberNumber(context);
  796. }
  797. internal static void NumberFloor(ProcessingContext context)
  798. {
  799. StackFrame arg = context.TopArg;
  800. while (arg.basePtr <= arg.endPtr)
  801. {
  802. context.SetValue(context, arg.basePtr, Math.Floor(context.PeekDouble(arg.basePtr)));
  803. arg.basePtr++;
  804. }
  805. }
  806. internal static void NumberRound(ProcessingContext context)
  807. {
  808. StackFrame arg = context.TopArg;
  809. while (arg.basePtr <= arg.endPtr)
  810. {
  811. double val = context.PeekDouble(arg.basePtr);
  812. context.SetValue(context, arg.basePtr, QueryValueModel.Round(context.PeekDouble(arg.basePtr)));
  813. arg.basePtr++;
  814. }
  815. }
  816. internal static void NumberSum(ProcessingContext context)
  817. {
  818. StackFrame arg = context.TopArg;
  819. while (arg.basePtr <= arg.endPtr)
  820. {
  821. NodeSequence sequence = context.PeekSequence(arg.basePtr);
  822. double sum = 0.0;
  823. for (int item = 0; item < sequence.Count; ++item)
  824. {
  825. sum += QueryValueModel.Double(sequence[item].StringValue());
  826. }
  827. context.SetValue(context, arg.basePtr, sum);
  828. arg.basePtr++;
  829. }
  830. }
  831. internal static void StringString(ProcessingContext context)
  832. {
  833. StackFrame arg = context.TopArg;
  834. Value[] values = context.Values;
  835. while (arg.basePtr <= arg.endPtr)
  836. {
  837. values[arg.basePtr++].ConvertTo(context, ValueDataType.String);
  838. }
  839. }
  840. internal static void StringStringDefault(ProcessingContext context)
  841. {
  842. XPathFunction.IterateAndPushSequences(context);
  843. XPathFunction.StringString(context);
  844. }
  845. internal static void StringConcatTwo(ProcessingContext context)
  846. {
  847. StackFrame arg1 = context[0];
  848. StackFrame arg2 = context[1];
  849. while (arg1.basePtr <= arg1.endPtr)
  850. {
  851. string str1 = context.PeekString(arg1.basePtr);
  852. string str2 = context.PeekString(arg2.basePtr);
  853. context.SetValue(context, arg2.basePtr, str1 + str2);
  854. arg1.basePtr++;
  855. arg2.basePtr++;
  856. }
  857. context.PopFrame();
  858. }
  859. internal static void StringConcatThree(ProcessingContext context)
  860. {
  861. StackFrame arg1 = context[0];
  862. StackFrame arg2 = context[1];
  863. StackFrame arg3 = context[2];
  864. while (arg1.basePtr <= arg1.endPtr)
  865. {
  866. string str1 = context.PeekString(arg1.basePtr);
  867. string str2 = context.PeekString(arg2.basePtr);
  868. string str3 = context.PeekString(arg3.basePtr);
  869. context.SetValue(context, arg3.basePtr, str1 + str2 + str3);
  870. arg1.basePtr++;
  871. arg2.basePtr++;
  872. arg3.basePtr++;
  873. }
  874. context.PopFrame();
  875. context.PopFrame();
  876. }
  877. internal static void StringConcatFour(ProcessingContext context)
  878. {
  879. StackFrame arg1 = context[0];
  880. StackFrame arg2 = context[1];
  881. StackFrame arg3 = context[2];
  882. StackFrame arg4 = context[3];
  883. while (arg1.basePtr <= arg1.endPtr)
  884. {
  885. string str1 = context.PeekString(arg1.basePtr);
  886. string str2 = context.PeekString(arg2.basePtr);
  887. string str3 = context.PeekString(arg3.basePtr);
  888. string str4 = context.PeekString(arg4.basePtr);
  889. context.SetValue(context, arg4.basePtr, str1 + str2 + str3 + str4);
  890. arg1.basePtr++;
  891. arg2.basePtr++;
  892. arg3.basePtr++;
  893. arg4.basePtr++;
  894. }
  895. context.PopFrame();
  896. context.PopFrame();
  897. context.PopFrame();
  898. }
  899. internal static void StringContains(ProcessingContext context)
  900. {
  901. StackFrame arg1 = context.TopArg;
  902. StackFrame arg2 = context.SecondArg;
  903. Fx.Assert(arg1.Count == arg2.Count, "");
  904. while (arg1.basePtr <= arg1.endPtr)
  905. {
  906. string leftString = context.PeekString(arg1.basePtr);
  907. string rightString = context.PeekString(arg2.basePtr);
  908. context.SetValue(context, arg2.basePtr, (-1 != leftString.IndexOf(rightString, StringComparison.Ordinal)));
  909. arg1.basePtr++;
  910. arg2.basePtr++;
  911. }
  912. context.PopFrame();
  913. }
  914. internal static void StringLength(ProcessingContext context)
  915. {
  916. StackFrame arg = context.TopArg;
  917. while (arg.basePtr <= arg.endPtr)
  918. {
  919. context.SetValue(context, arg.basePtr, context.PeekString(arg.basePtr).Length);
  920. arg.basePtr++;
  921. }
  922. }
  923. internal static void StringLengthDefault(ProcessingContext context)
  924. {
  925. XPathFunction.IterateAndPushSequences(context);
  926. XPathFunction.ConvertFirstArg(context, ValueDataType.String);
  927. XPathFunction.StringLength(context);
  928. }
  929. internal static void StringStartsWith(ProcessingContext context)
  930. {
  931. StackFrame arg1 = context.TopArg;
  932. StackFrame arg2 = context.SecondArg;
  933. Fx.Assert(arg1.Count == arg2.Count, "");
  934. while (arg1.basePtr <= arg1.endPtr)
  935. {
  936. string leftString = context.PeekString(arg1.basePtr);
  937. string rightString = context.PeekString(arg2.basePtr);
  938. context.SetValue(context, arg2.basePtr, leftString.StartsWith(rightString, StringComparison.Ordinal));
  939. arg1.basePtr++;
  940. arg2.basePtr++;
  941. }
  942. context.PopFrame();
  943. }
  944. internal static void SubstringBefore(ProcessingContext context)
  945. {
  946. StackFrame arg1 = context.TopArg;
  947. StackFrame arg2 = context.SecondArg;
  948. Fx.Assert(arg1.Count == arg2.Count, "");
  949. while (arg1.basePtr <= arg1.endPtr)
  950. {
  951. string str1 = context.PeekString(arg1.basePtr);
  952. string str2 = context.PeekString(arg2.basePtr);
  953. int idx = str1.IndexOf(str2, StringComparison.Ordinal);
  954. context.SetValue(context, arg2.basePtr, idx == -1 ? string.Empty : str1.Substring(0, idx));
  955. arg1.basePtr++;
  956. arg2.basePtr++;
  957. }
  958. context.PopFrame();
  959. }
  960. internal static void SubstringAfter(ProcessingContext context)
  961. {
  962. StackFrame arg1 = context.TopArg;
  963. StackFrame arg2 = context.SecondArg;
  964. Fx.Assert(arg1.Count == arg2.Count, "");
  965. while (arg1.basePtr <= arg1.endPtr)
  966. {
  967. string str1 = context.PeekString(arg1.basePtr);
  968. string str2 = context.PeekString(arg2.basePtr);
  969. int idx = str1.IndexOf(str2, StringComparison.Ordinal);
  970. context.SetValue(context, arg2.basePtr, idx == -1 ? string.Empty : str1.Substring(idx + str2.Length));
  971. arg1.basePtr++;
  972. arg2.basePtr++;
  973. }
  974. context.PopFrame();
  975. }
  976. internal static void Substring(ProcessingContext context)
  977. {
  978. StackFrame arg1 = context.TopArg;
  979. StackFrame arg2 = context.SecondArg;
  980. Fx.Assert(arg1.Count == arg2.Count, "");
  981. while (arg1.basePtr <= arg1.endPtr)
  982. {
  983. string str = context.PeekString(arg1.basePtr);
  984. int startAt = ((int)Math.Round(context.PeekDouble(arg2.basePtr))) - 1;
  985. if (startAt < 0)
  986. {
  987. startAt = 0;
  988. }
  989. context.SetValue(context, arg2.basePtr, (startAt >= str.Length) ? string.Empty : str.Substring(startAt));
  990. arg1.basePtr++;
  991. arg2.basePtr++;
  992. }
  993. context.PopFrame();
  994. }
  995. internal static void SubstringLimit(ProcessingContext context)
  996. {
  997. StackFrame argString = context.TopArg;
  998. StackFrame argStartAt = context.SecondArg;
  999. StackFrame argLimit = context[2];
  1000. Fx.Assert(argString.Count == argStartAt.Count, "");
  1001. Fx.Assert(argString.Count == argLimit.Count, "");
  1002. while (argString.basePtr <= argString.endPtr)
  1003. {
  1004. string str = context.PeekString(argString.basePtr);
  1005. int startAt = ((int)Math.Round(context.PeekDouble(argStartAt.basePtr))) - 1;
  1006. if (startAt < 0)
  1007. {
  1008. startAt = 0;
  1009. }
  1010. int length = (int)Math.Round(context.PeekDouble(argLimit.basePtr));
  1011. string substr;
  1012. if (length < 1 || ((startAt + length) >= str.Length))
  1013. {
  1014. substr = string.Empty;
  1015. }
  1016. else
  1017. {
  1018. substr = str.Substring(startAt, length);
  1019. }
  1020. context.SetValue(context, argLimit.basePtr, substr);
  1021. argStartAt.basePtr++;
  1022. argString.basePtr++;
  1023. argLimit.basePtr++;
  1024. }
  1025. context.PopFrame();
  1026. context.PopFrame();
  1027. }
  1028. internal static void Translate(ProcessingContext context)
  1029. {
  1030. StackFrame argSource = context.TopArg;
  1031. StackFrame argKeys = context.SecondArg;
  1032. StackFrame argValues = context[2];
  1033. // PERF, [....], this is really slow.
  1034. StringBuilder builder = new StringBuilder();
  1035. while (argSource.basePtr <= argSource.endPtr)
  1036. {
  1037. builder.Length = 0;
  1038. string source = context.PeekString(argSource.basePtr);
  1039. string keys = context.PeekString(argKeys.basePtr);
  1040. string values = context.PeekString(argValues.basePtr);
  1041. for (int i = 0; i < source.Length; ++i)
  1042. {
  1043. char c = source[i];
  1044. int idx = keys.IndexOf(c);
  1045. if (idx < 0)
  1046. {
  1047. builder.Append(c);
  1048. }
  1049. else if (idx < values.Length)
  1050. {
  1051. builder.Append(values[idx]);
  1052. }
  1053. }
  1054. context.SetValue(context, argValues.basePtr, builder.ToString());
  1055. argSource.basePtr++;
  1056. argKeys.basePtr++;
  1057. argValues.basePtr++;
  1058. }
  1059. context.PopFrame();
  1060. context.PopFrame();
  1061. }
  1062. internal static void NormalizeSpace(ProcessingContext context)
  1063. {
  1064. StackFrame argStr = context.TopArg;
  1065. StringBuilder builder = new StringBuilder();
  1066. while (argStr.basePtr <= argStr.endPtr)
  1067. {
  1068. char[] whitespace = new char[] { ' ', '\t', '\r', '\n' };
  1069. string str = context.PeekString(argStr.basePtr).Trim(whitespace);
  1070. bool eatingWhitespace = false;
  1071. builder.Length = 0;
  1072. for (int i = 0; i < str.Length; ++i)
  1073. {
  1074. char c = str[i];
  1075. if (XPathCharTypes.IsWhitespace(c))
  1076. {
  1077. if (!eatingWhitespace)
  1078. {
  1079. builder.Append(' ');
  1080. eatingWhitespace = true;
  1081. }
  1082. }
  1083. else
  1084. {
  1085. builder.Append(c);
  1086. eatingWhitespace = false;
  1087. }
  1088. }
  1089. context.SetValue(context, argStr.basePtr, builder.ToString());
  1090. argStr.basePtr++;
  1091. }
  1092. }
  1093. internal static void NormalizeSpaceDefault(ProcessingContext context)
  1094. {
  1095. XPathFunction.IterateAndPushSequences(context);
  1096. XPathFunction.ConvertFirstArg(context, ValueDataType.String);
  1097. XPathFunction.NormalizeSpace(context);
  1098. }
  1099. #if NO
  1100. internal static bool IsWhitespace(char c)
  1101. {
  1102. return c == ' ' || c == '\r' || c == '\n' || c == '\t';
  1103. }
  1104. #endif
  1105. }
  1106. }