1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Diagnostics; 6 using System.Xml; 7 using System.Xml.XPath; 8 using System.Xml.Xsl; 9 10 namespace MS.Internal.Xml.XPath 11 { 12 internal sealed class LogicalExpr : ValueQuery 13 { 14 private Operator.Op _op; 15 private Query _opnd1; 16 private Query _opnd2; 17 LogicalExpr(Operator.Op op, Query opnd1, Query opnd2)18 public LogicalExpr(Operator.Op op, Query opnd1, Query opnd2) 19 { 20 Debug.Assert( 21 Operator.Op.LT == op || Operator.Op.GT == op || 22 Operator.Op.LE == op || Operator.Op.GE == op || 23 Operator.Op.EQ == op || Operator.Op.NE == op 24 ); 25 _op = op; 26 _opnd1 = opnd1; 27 _opnd2 = opnd2; 28 } LogicalExpr(LogicalExpr other)29 private LogicalExpr(LogicalExpr other) : base(other) 30 { 31 _op = other._op; 32 _opnd1 = Clone(other._opnd1); 33 _opnd2 = Clone(other._opnd2); 34 } 35 SetXsltContext(XsltContext context)36 public override void SetXsltContext(XsltContext context) 37 { 38 _opnd1.SetXsltContext(context); 39 _opnd2.SetXsltContext(context); 40 } 41 Evaluate(XPathNodeIterator nodeIterator)42 public override object Evaluate(XPathNodeIterator nodeIterator) 43 { 44 Operator.Op op = _op; 45 object val1 = _opnd1.Evaluate(nodeIterator); 46 object val2 = _opnd2.Evaluate(nodeIterator); 47 int type1 = (int)GetXPathType(val1); 48 int type2 = (int)GetXPathType(val2); 49 if (type1 < type2) 50 { 51 op = Operator.InvertOperator(op); 52 object valTemp = val1; 53 val1 = val2; 54 val2 = valTemp; 55 int typeTmp = type1; 56 type1 = type2; 57 type2 = typeTmp; 58 } 59 60 if (op == Operator.Op.EQ || op == Operator.Op.NE) 61 { 62 return s_CompXsltE[type1][type2](op, val1, val2); 63 } 64 else 65 { 66 return s_CompXsltO[type1][type2](op, val1, val2); 67 } 68 } 69 cmpXslt(Operator.Op op, object val1, object val2)70 private delegate bool cmpXslt(Operator.Op op, object val1, object val2); 71 72 // Number, String, Boolean, NodeSet, Navigator 73 private static readonly cmpXslt[][] s_CompXsltE = { 74 new cmpXslt[] { new cmpXslt(cmpNumberNumber), null , null , null , null }, 75 new cmpXslt[] { new cmpXslt(cmpStringNumber), new cmpXslt(cmpStringStringE), null , null , null }, 76 new cmpXslt[] { new cmpXslt(cmpBoolNumberE ), new cmpXslt(cmpBoolStringE ), new cmpXslt(cmpBoolBoolE ), null , null }, 77 new cmpXslt[] { new cmpXslt(cmpQueryNumber ), new cmpXslt(cmpQueryStringE ), new cmpXslt(cmpQueryBoolE ), new cmpXslt(cmpQueryQueryE ), null }, 78 new cmpXslt[] { new cmpXslt(cmpRtfNumber ), new cmpXslt(cmpRtfStringE ), new cmpXslt(cmpRtfBoolE ), new cmpXslt(cmpRtfQueryE ), new cmpXslt(cmpRtfRtfE) }, 79 }; 80 private static readonly cmpXslt[][] s_CompXsltO = { 81 new cmpXslt[] { new cmpXslt(cmpNumberNumber), null , null , null , null }, 82 new cmpXslt[] { new cmpXslt(cmpStringNumber), new cmpXslt(cmpStringStringO), null , null , null }, 83 new cmpXslt[] { new cmpXslt(cmpBoolNumberO ), new cmpXslt(cmpBoolStringO ), new cmpXslt(cmpBoolBoolO ), null , null }, 84 new cmpXslt[] { new cmpXslt(cmpQueryNumber ), new cmpXslt(cmpQueryStringO ), new cmpXslt(cmpQueryBoolO ), new cmpXslt(cmpQueryQueryO ), null }, 85 new cmpXslt[] { new cmpXslt(cmpRtfNumber ), new cmpXslt(cmpRtfStringO ), new cmpXslt(cmpRtfBoolO ), new cmpXslt(cmpRtfQueryO ), new cmpXslt(cmpRtfRtfO) }, 86 }; 87 88 /*cmpXslt:*/ cmpQueryQueryE(Operator.Op op, object val1, object val2)89 private static bool cmpQueryQueryE(Operator.Op op, object val1, object val2) 90 { 91 Debug.Assert(op == Operator.Op.EQ || op == Operator.Op.NE); 92 bool isEQ = (op == Operator.Op.EQ); 93 94 NodeSet n1 = new NodeSet(val1); 95 NodeSet n2 = new NodeSet(val2); 96 97 while (true) 98 { 99 if (!n1.MoveNext()) 100 { 101 return false; 102 } 103 if (!n2.MoveNext()) 104 { 105 return false; 106 } 107 108 string str1 = n1.Value; 109 110 do 111 { 112 if ((str1 == n2.Value) == isEQ) 113 { 114 return true; 115 } 116 } while (n2.MoveNext()); 117 n2.Reset(); 118 } 119 } 120 121 /*cmpXslt:*/ cmpQueryQueryO(Operator.Op op, object val1, object val2)122 private static bool cmpQueryQueryO(Operator.Op op, object val1, object val2) 123 { 124 Debug.Assert( 125 op == Operator.Op.LT || op == Operator.Op.GT || 126 op == Operator.Op.LE || op == Operator.Op.GE 127 ); 128 129 NodeSet n1 = new NodeSet(val1); 130 NodeSet n2 = new NodeSet(val2); 131 132 while (true) 133 { 134 if (!n1.MoveNext()) 135 { 136 return false; 137 } 138 if (!n2.MoveNext()) 139 { 140 return false; 141 } 142 143 double num1 = NumberFunctions.Number(n1.Value); 144 145 do 146 { 147 if (cmpNumberNumber(op, num1, NumberFunctions.Number(n2.Value))) 148 { 149 return true; 150 } 151 } while (n2.MoveNext()); 152 n2.Reset(); 153 } 154 } cmpQueryNumber(Operator.Op op, object val1, object val2)155 private static bool cmpQueryNumber(Operator.Op op, object val1, object val2) 156 { 157 NodeSet n1 = new NodeSet(val1); 158 double n2 = (double)val2; 159 160 while (n1.MoveNext()) 161 { 162 if (cmpNumberNumber(op, NumberFunctions.Number(n1.Value), n2)) 163 { 164 return true; 165 } 166 } 167 return false; 168 } 169 cmpQueryStringE(Operator.Op op, object val1, object val2)170 private static bool cmpQueryStringE(Operator.Op op, object val1, object val2) 171 { 172 NodeSet n1 = new NodeSet(val1); 173 string n2 = (string)val2; 174 175 while (n1.MoveNext()) 176 { 177 if (cmpStringStringE(op, n1.Value, n2)) 178 { 179 return true; 180 } 181 } 182 return false; 183 } 184 cmpQueryStringO(Operator.Op op, object val1, object val2)185 private static bool cmpQueryStringO(Operator.Op op, object val1, object val2) 186 { 187 NodeSet n1 = new NodeSet(val1); 188 double n2 = NumberFunctions.Number((string)val2); 189 190 while (n1.MoveNext()) 191 { 192 if (cmpNumberNumberO(op, NumberFunctions.Number(n1.Value), n2)) 193 { 194 return true; 195 } 196 } 197 return false; 198 } 199 cmpRtfQueryE(Operator.Op op, object val1, object val2)200 private static bool cmpRtfQueryE(Operator.Op op, object val1, object val2) 201 { 202 string n1 = Rtf(val1); 203 NodeSet n2 = new NodeSet(val2); 204 205 while (n2.MoveNext()) 206 { 207 if (cmpStringStringE(op, n1, n2.Value)) 208 { 209 return true; 210 } 211 } 212 return false; 213 } 214 cmpRtfQueryO(Operator.Op op, object val1, object val2)215 private static bool cmpRtfQueryO(Operator.Op op, object val1, object val2) 216 { 217 double n1 = NumberFunctions.Number(Rtf(val1)); 218 NodeSet n2 = new NodeSet(val2); 219 220 while (n2.MoveNext()) 221 { 222 if (cmpNumberNumberO(op, n1, NumberFunctions.Number(n2.Value))) 223 { 224 return true; 225 } 226 } 227 return false; 228 } 229 cmpQueryBoolE(Operator.Op op, object val1, object val2)230 private static bool cmpQueryBoolE(Operator.Op op, object val1, object val2) 231 { 232 NodeSet n1 = new NodeSet(val1); 233 bool b1 = n1.MoveNext(); 234 bool b2 = (bool)val2; 235 return cmpBoolBoolE(op, b1, b2); 236 } 237 cmpQueryBoolO(Operator.Op op, object val1, object val2)238 private static bool cmpQueryBoolO(Operator.Op op, object val1, object val2) 239 { 240 NodeSet n1 = new NodeSet(val1); 241 double d1 = n1.MoveNext() ? 1.0 : 0; 242 double d2 = NumberFunctions.Number((bool)val2); 243 return cmpNumberNumberO(op, d1, d2); 244 } 245 cmpBoolBoolE(Operator.Op op, bool n1, bool n2)246 private static bool cmpBoolBoolE(Operator.Op op, bool n1, bool n2) 247 { 248 Debug.Assert(op == Operator.Op.EQ || op == Operator.Op.NE, 249 "Unexpected Operator.op code in cmpBoolBoolE()" 250 ); 251 return (op == Operator.Op.EQ) == (n1 == n2); 252 } cmpBoolBoolE(Operator.Op op, object val1, object val2)253 private static bool cmpBoolBoolE(Operator.Op op, object val1, object val2) 254 { 255 bool n1 = (bool)val1; 256 bool n2 = (bool)val2; 257 return cmpBoolBoolE(op, n1, n2); 258 } 259 cmpBoolBoolO(Operator.Op op, object val1, object val2)260 private static bool cmpBoolBoolO(Operator.Op op, object val1, object val2) 261 { 262 double n1 = NumberFunctions.Number((bool)val1); 263 double n2 = NumberFunctions.Number((bool)val2); 264 return cmpNumberNumberO(op, n1, n2); 265 } 266 cmpBoolNumberE(Operator.Op op, object val1, object val2)267 private static bool cmpBoolNumberE(Operator.Op op, object val1, object val2) 268 { 269 bool n1 = (bool)val1; 270 bool n2 = BooleanFunctions.toBoolean((double)val2); 271 return cmpBoolBoolE(op, n1, n2); 272 } 273 cmpBoolNumberO(Operator.Op op, object val1, object val2)274 private static bool cmpBoolNumberO(Operator.Op op, object val1, object val2) 275 { 276 double n1 = NumberFunctions.Number((bool)val1); 277 double n2 = (double)val2; 278 return cmpNumberNumberO(op, n1, n2); 279 } 280 cmpBoolStringE(Operator.Op op, object val1, object val2)281 private static bool cmpBoolStringE(Operator.Op op, object val1, object val2) 282 { 283 bool n1 = (bool)val1; 284 bool n2 = BooleanFunctions.toBoolean((string)val2); 285 return cmpBoolBoolE(op, n1, n2); 286 } 287 cmpRtfBoolE(Operator.Op op, object val1, object val2)288 private static bool cmpRtfBoolE(Operator.Op op, object val1, object val2) 289 { 290 bool n1 = BooleanFunctions.toBoolean(Rtf(val1)); 291 bool n2 = (bool)val2; 292 return cmpBoolBoolE(op, n1, n2); 293 } 294 cmpBoolStringO(Operator.Op op, object val1, object val2)295 private static bool cmpBoolStringO(Operator.Op op, object val1, object val2) 296 { 297 return cmpNumberNumberO(op, 298 NumberFunctions.Number((bool)val1), 299 NumberFunctions.Number((string)val2) 300 ); 301 } 302 cmpRtfBoolO(Operator.Op op, object val1, object val2)303 private static bool cmpRtfBoolO(Operator.Op op, object val1, object val2) 304 { 305 return cmpNumberNumberO(op, 306 NumberFunctions.Number(Rtf(val1)), 307 NumberFunctions.Number((bool)val2) 308 ); 309 } 310 cmpNumberNumber(Operator.Op op, double n1, double n2)311 private static bool cmpNumberNumber(Operator.Op op, double n1, double n2) 312 { 313 switch (op) 314 { 315 case Operator.Op.LT: return (n1 < n2); 316 case Operator.Op.GT: return (n1 > n2); 317 case Operator.Op.LE: return (n1 <= n2); 318 case Operator.Op.GE: return (n1 >= n2); 319 case Operator.Op.EQ: return (n1 == n2); 320 case Operator.Op.NE: return (n1 != n2); 321 } 322 Debug.Fail("Unexpected Operator.op code in cmpNumberNumber()"); 323 return false; 324 } cmpNumberNumberO(Operator.Op op, double n1, double n2)325 private static bool cmpNumberNumberO(Operator.Op op, double n1, double n2) 326 { 327 switch (op) 328 { 329 case Operator.Op.LT: return (n1 < n2); 330 case Operator.Op.GT: return (n1 > n2); 331 case Operator.Op.LE: return (n1 <= n2); 332 case Operator.Op.GE: return (n1 >= n2); 333 } 334 Debug.Fail("Unexpected Operator.op code in cmpNumberNumber()"); 335 return false; 336 } cmpNumberNumber(Operator.Op op, object val1, object val2)337 private static bool cmpNumberNumber(Operator.Op op, object val1, object val2) 338 { 339 double n1 = (double)val1; 340 double n2 = (double)val2; 341 return cmpNumberNumber(op, n1, n2); 342 } 343 cmpStringNumber(Operator.Op op, object val1, object val2)344 private static bool cmpStringNumber(Operator.Op op, object val1, object val2) 345 { 346 double n2 = (double)val2; 347 double n1 = NumberFunctions.Number((string)val1); 348 return cmpNumberNumber(op, n1, n2); 349 } 350 cmpRtfNumber(Operator.Op op, object val1, object val2)351 private static bool cmpRtfNumber(Operator.Op op, object val1, object val2) 352 { 353 double n2 = (double)val2; 354 double n1 = NumberFunctions.Number(Rtf(val1)); 355 return cmpNumberNumber(op, n1, n2); 356 } 357 cmpStringStringE(Operator.Op op, string n1, string n2)358 private static bool cmpStringStringE(Operator.Op op, string n1, string n2) 359 { 360 Debug.Assert(op == Operator.Op.EQ || op == Operator.Op.NE, 361 "Unexpected Operator.op code in cmpStringStringE()" 362 ); 363 return (op == Operator.Op.EQ) == (n1 == n2); 364 } cmpStringStringE(Operator.Op op, object val1, object val2)365 private static bool cmpStringStringE(Operator.Op op, object val1, object val2) 366 { 367 string n1 = (string)val1; 368 string n2 = (string)val2; 369 return cmpStringStringE(op, n1, n2); 370 } cmpRtfStringE(Operator.Op op, object val1, object val2)371 private static bool cmpRtfStringE(Operator.Op op, object val1, object val2) 372 { 373 string n1 = Rtf(val1); 374 string n2 = (string)val2; 375 return cmpStringStringE(op, n1, n2); 376 } cmpRtfRtfE(Operator.Op op, object val1, object val2)377 private static bool cmpRtfRtfE(Operator.Op op, object val1, object val2) 378 { 379 string n1 = Rtf(val1); 380 string n2 = Rtf(val2); 381 return cmpStringStringE(op, n1, n2); 382 } 383 cmpStringStringO(Operator.Op op, object val1, object val2)384 private static bool cmpStringStringO(Operator.Op op, object val1, object val2) 385 { 386 double n1 = NumberFunctions.Number((string)val1); 387 double n2 = NumberFunctions.Number((string)val2); 388 return cmpNumberNumberO(op, n1, n2); 389 } 390 cmpRtfStringO(Operator.Op op, object val1, object val2)391 private static bool cmpRtfStringO(Operator.Op op, object val1, object val2) 392 { 393 double n1 = NumberFunctions.Number(Rtf(val1)); 394 double n2 = NumberFunctions.Number((string)val2); 395 return cmpNumberNumberO(op, n1, n2); 396 } 397 cmpRtfRtfO(Operator.Op op, object val1, object val2)398 private static bool cmpRtfRtfO(Operator.Op op, object val1, object val2) 399 { 400 double n1 = NumberFunctions.Number(Rtf(val1)); 401 double n2 = NumberFunctions.Number(Rtf(val2)); 402 return cmpNumberNumberO(op, n1, n2); 403 } 404 Clone()405 public override XPathNodeIterator Clone() { return new LogicalExpr(this); } 406 407 private struct NodeSet 408 { 409 private Query _opnd; 410 private XPathNavigator _current; 411 NodeSetMS.Internal.Xml.XPath.LogicalExpr.NodeSet412 public NodeSet(object opnd) 413 { 414 _opnd = (Query)opnd; 415 _current = null; 416 } MoveNextMS.Internal.Xml.XPath.LogicalExpr.NodeSet417 public bool MoveNext() 418 { 419 _current = _opnd.Advance(); 420 return _current != null; 421 } 422 ResetMS.Internal.Xml.XPath.LogicalExpr.NodeSet423 public void Reset() 424 { 425 _opnd.Reset(); 426 } 427 428 public string Value { get { return _current.Value; } } 429 } 430 Rtf(object o)431 private static string Rtf(object o) { return ((XPathNavigator)o).Value; } 432 433 public override XPathResultType StaticType { get { return XPathResultType.Boolean; } } 434 } 435 } 436