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 Xunit.Abstractions; 6 using System; 7 using System.IO; 8 using System.Text; 9 using System.Xml; 10 using System.Xml.Schema; 11 12 public enum NodeFlags 13 { 14 None = 0, 15 EmptyElement = 1, 16 HasValue = 2, 17 SingleQuote = 4, 18 DefaultAttribute = 8, 19 UnparsedEntities = 16, 20 IsWhitespace = 32, 21 DocumentRoot = 64, 22 AttributeTextNode = 128, 23 MixedContent = 256, 24 Indent = 512 25 } 26 27 abstract public class CXmlBase 28 { 29 protected XmlNodeType _nType; 30 protected string _strName; 31 protected string _strLocalName; 32 protected string _strPrefix; 33 protected string _strNamespace; 34 internal int _nDepth; 35 internal NodeFlags _eFlags = NodeFlags.None; 36 internal CXmlBase _rNextNode = null; 37 internal CXmlBase _rParentNode = null; 38 internal CXmlBase _rFirstChildNode = null; 39 internal CXmlBase _rLastChildNode = null; 40 internal int _nChildNodes = 0; 41 42 // 43 // Constructors 44 // CXmlBase(string strPrefix, string strName, string strLocalName, XmlNodeType NodeType, string strNamespace)45 public CXmlBase(string strPrefix, string strName, string strLocalName, XmlNodeType NodeType, string strNamespace) 46 { 47 _strPrefix = strPrefix; 48 _strName = strName; 49 _strLocalName = strLocalName; 50 _nType = NodeType; 51 _strNamespace = strNamespace; 52 } 53 CXmlBase(string strPrefix, string strName, XmlNodeType NodeType, string strNamespace)54 public CXmlBase(string strPrefix, string strName, XmlNodeType NodeType, string strNamespace) 55 : this(strPrefix, strName, strName, NodeType, strNamespace) 56 { } 57 CXmlBase(string strPrefix, string strName, XmlNodeType NodeType)58 public CXmlBase(string strPrefix, string strName, XmlNodeType NodeType) 59 : this(strPrefix, strName, strName, NodeType, "") 60 { } 61 CXmlBase(string strName, XmlNodeType NodeType)62 public CXmlBase(string strName, XmlNodeType NodeType) 63 : this("", strName, strName, NodeType, "") 64 { } 65 66 // 67 // Virtual Methods and Properties 68 // Write(XmlWriter rXmlWriter)69 abstract public void Write(XmlWriter rXmlWriter); 70 WriteXml(TextWriter rTW)71 abstract public void WriteXml(TextWriter rTW); 72 73 abstract public string Value 74 { get; } 75 76 // 77 // Public Methods and Properties 78 // 79 public string Name 80 { 81 get { return _strName; } 82 } 83 84 public string LocalName 85 { 86 get { return _strLocalName; } 87 } 88 89 public string Prefix 90 { 91 get { return _strPrefix; } 92 } 93 94 public string Namespace 95 { 96 get { return _strNamespace; } 97 } 98 99 public int Depth 100 { 101 get { return _nDepth; } 102 } 103 104 public XmlNodeType NodeType 105 { 106 get { return _nType; } 107 } 108 109 public NodeFlags Flags 110 { 111 get { return _eFlags; } 112 } 113 114 public int ChildNodeCount 115 { 116 get { return _nChildNodes; } 117 } 118 InsertNode(CXmlBase rNode)119 public void InsertNode(CXmlBase rNode) 120 { 121 if (_rFirstChildNode == null) 122 { 123 _rFirstChildNode = _rLastChildNode = rNode; 124 } 125 else 126 { 127 _rLastChildNode._rNextNode = rNode; 128 _rLastChildNode = rNode; 129 } 130 131 if ((this._eFlags & NodeFlags.IsWhitespace) == 0) 132 _nChildNodes++; 133 134 rNode._rParentNode = this; 135 } 136 137 // 138 // Internal Methods and Properties 139 // _Child(int n)140 internal CXmlBase _Child(int n) 141 { 142 int i; 143 int j; 144 CXmlBase rChild = _rFirstChildNode; 145 146 for (i = 0, j = 0; rChild != null; i++, rChild = rChild._rNextNode) 147 { 148 if ((rChild._eFlags & NodeFlags.IsWhitespace) == 0) 149 { 150 if (j++ == n) break; 151 } 152 } 153 154 return rChild; 155 } 156 _Child(string str)157 internal CXmlBase _Child(string str) 158 { 159 CXmlBase rChild; 160 161 for (rChild = _rFirstChildNode; rChild != null; rChild = rChild._rNextNode) 162 if (rChild.Name == str) break; 163 164 return rChild; 165 } 166 } 167 168 public class CXmlAttribute : CXmlBase 169 { 170 // 171 // Constructor 172 // CXmlAttribute(XmlReader rXmlReader)173 public CXmlAttribute(XmlReader rXmlReader) 174 : base(rXmlReader.Prefix, rXmlReader.Name, rXmlReader.LocalName, rXmlReader.NodeType, rXmlReader.NamespaceURI) 175 { 176 if (rXmlReader.IsDefault) 177 _eFlags |= NodeFlags.DefaultAttribute; 178 179 if (rXmlReader.QuoteChar == '\'') 180 _eFlags |= NodeFlags.SingleQuote; 181 } 182 183 // 184 // Public Methods and Properties (Override) 185 // Write(XmlWriter rXmlWriter)186 override public void Write(XmlWriter rXmlWriter) 187 { 188 CXmlBase rNode; 189 190 if ((this._eFlags & NodeFlags.DefaultAttribute) == 0) 191 { 192 if (rXmlWriter is XmlTextWriter) 193 ((XmlTextWriter)rXmlWriter).QuoteChar = this.Quote; 194 195 rXmlWriter.WriteStartAttribute(this.Prefix, this.LocalName, this.Namespace); 196 197 for (rNode = this._rFirstChildNode; rNode != null; rNode = rNode._rNextNode) 198 { 199 rNode.Write(rXmlWriter); 200 } 201 202 rXmlWriter.WriteEndAttribute(); 203 } 204 } 205 WriteXml(TextWriter rTW)206 override public void WriteXml(TextWriter rTW) 207 { 208 if ((this._eFlags & NodeFlags.DefaultAttribute) == 0) 209 { 210 CXmlBase rNode; 211 212 rTW.Write(' ' + this.Name + '=' + this.Quote); 213 for (rNode = this._rFirstChildNode; rNode != null; rNode = rNode._rNextNode) 214 { 215 rNode.WriteXml(rTW); 216 } 217 rTW.Write(this.Quote); 218 } 219 } 220 221 // 222 // Public Methods and Properties 223 // 224 override public string Value 225 { 226 get 227 { 228 CXmlNode rNode; 229 string strValue = string.Empty; 230 231 for (rNode = (CXmlNode)this._rFirstChildNode; rNode != null; rNode = rNode.NextNode) 232 strValue += rNode.Value; 233 234 return strValue; 235 } 236 } 237 238 public CXmlAttribute NextAttribute 239 { 240 get { return (CXmlAttribute)this._rNextNode; } 241 } 242 243 public char Quote 244 { 245 get { return ((base._eFlags & NodeFlags.SingleQuote) != 0 ? '\'' : '"'); } 246 set { if (value == '\'') base._eFlags |= NodeFlags.SingleQuote; else base._eFlags &= ~NodeFlags.SingleQuote; } 247 } 248 249 public CXmlNode FirstChild 250 { 251 get { return (CXmlNode)base._rFirstChildNode; } 252 } 253 Child(int n)254 public CXmlNode Child(int n) 255 { 256 return (CXmlNode)base._Child(n); 257 } 258 Child(string str)259 public CXmlNode Child(string str) 260 { 261 return (CXmlNode)base._Child(str); 262 } 263 } 264 265 public class CXmlNode : CXmlBase 266 { 267 internal string _strValue = null; 268 private CXmlAttribute _rFirstAttribute = null; 269 private CXmlAttribute _rLastAttribute = null; 270 private int _nAttributeCount = 0; 271 272 // 273 // Constructors 274 // CXmlNode(string strPrefix, string strName, XmlNodeType NodeType)275 public CXmlNode(string strPrefix, string strName, XmlNodeType NodeType) 276 : base(strPrefix, strName, NodeType) 277 { } 278 CXmlNode(XmlReader rXmlReader)279 public CXmlNode(XmlReader rXmlReader) 280 : base(rXmlReader.Prefix, rXmlReader.Name, rXmlReader.LocalName, rXmlReader.NodeType, rXmlReader.NamespaceURI) 281 { 282 _eFlags |= CXmlCache._eDefaultFlags; 283 284 if (NodeType == XmlNodeType.Whitespace || 285 NodeType == XmlNodeType.SignificantWhitespace) 286 { 287 _eFlags |= NodeFlags.IsWhitespace; 288 } 289 290 if (rXmlReader.IsEmptyElement) 291 { 292 _eFlags |= NodeFlags.EmptyElement; 293 } 294 295 if (rXmlReader.HasValue) 296 { 297 _eFlags |= NodeFlags.HasValue; 298 _strValue = rXmlReader.Value; 299 } 300 } 301 302 // 303 // Public Methods and Properties (Override) 304 // Write(XmlWriter rXmlWriter)305 override public void Write(XmlWriter rXmlWriter) 306 { 307 CXmlBase rNode; 308 CXmlAttribute rAttribute; 309 string DocTypePublic = null; 310 string DocTypeSystem = null; 311 312 switch (this.NodeType) 313 { 314 case XmlNodeType.CDATA: 315 rXmlWriter.WriteCData(this._strValue); 316 break; 317 318 case XmlNodeType.Comment: 319 rXmlWriter.WriteComment(this._strValue); 320 break; 321 322 case XmlNodeType.DocumentType: 323 for (rAttribute = _rFirstAttribute; rAttribute != null; rAttribute = rAttribute.NextAttribute) 324 { 325 if (rAttribute.Name == "PUBLIC") 326 { DocTypePublic = rAttribute.Value; } 327 if (rAttribute.Name == "SYSTEM") 328 { DocTypeSystem = rAttribute.Value; } 329 } 330 rXmlWriter.WriteDocType(this.Name, DocTypePublic, DocTypeSystem, this._strValue); 331 break; 332 333 case XmlNodeType.EntityReference: 334 rXmlWriter.WriteEntityRef(this.Name); 335 break; 336 337 case XmlNodeType.ProcessingInstruction: 338 rXmlWriter.WriteProcessingInstruction(this.Name, this._strValue); 339 break; 340 341 case XmlNodeType.Text: 342 if (this.Name == string.Empty) 343 { 344 if ((this.Flags & NodeFlags.UnparsedEntities) == 0) 345 { 346 rXmlWriter.WriteString(this._strValue); 347 } 348 else 349 { 350 rXmlWriter.WriteRaw(this._strValue.ToCharArray(), 0, this._strValue.Length); 351 } 352 } 353 else 354 { 355 if (this._strName[0] == '#') 356 rXmlWriter.WriteCharEntity(this._strValue[0]); 357 else 358 rXmlWriter.WriteEntityRef(this.Name); 359 } 360 break; 361 362 case XmlNodeType.Whitespace: 363 case XmlNodeType.SignificantWhitespace: 364 if ((this._rParentNode._eFlags & NodeFlags.DocumentRoot) != 0) 365 rXmlWriter.WriteRaw(this._strValue.ToCharArray(), 0, this._strValue.Length); 366 else 367 rXmlWriter.WriteString(this._strValue); 368 break; 369 370 case XmlNodeType.Element: 371 rXmlWriter.WriteStartElement(this.Prefix, this.LocalName, null); 372 373 for (rAttribute = _rFirstAttribute; rAttribute != null; rAttribute = rAttribute.NextAttribute) 374 { 375 rAttribute.Write(rXmlWriter); 376 } 377 378 if ((this.Flags & NodeFlags.EmptyElement) == 0) 379 rXmlWriter.WriteString(string.Empty); 380 381 for (rNode = base._rFirstChildNode; rNode != null; rNode = rNode._rNextNode) 382 { 383 rNode.Write(rXmlWriter); 384 } 385 386 // Should only produce empty tag if the original document used empty tag 387 if ((this.Flags & NodeFlags.EmptyElement) == 0) 388 rXmlWriter.WriteFullEndElement(); 389 else 390 rXmlWriter.WriteEndElement(); 391 392 break; 393 394 case XmlNodeType.XmlDeclaration: 395 rXmlWriter.WriteRaw("<?xml " + this._strValue + "?>"); 396 break; 397 398 default: 399 throw (new Exception("Node.Write: Unhandled node type " + this.NodeType.ToString())); 400 } 401 } 402 WriteXml(TextWriter rTW)403 override public void WriteXml(TextWriter rTW) 404 { 405 String strXml; 406 CXmlAttribute rAttribute; 407 CXmlBase rNode; 408 409 switch (this._nType) 410 { 411 case XmlNodeType.Text: 412 if (this._strName == "") 413 { 414 rTW.Write(this._strValue); 415 } 416 else 417 { 418 if (this._strName.StartsWith("#")) 419 { 420 rTW.Write("&" + Convert.ToString(Convert.ToInt32(this._strValue[0])) + ";"); 421 } 422 else 423 { 424 rTW.Write("&" + this.Name + ";"); 425 } 426 } 427 break; 428 429 case XmlNodeType.Whitespace: 430 case XmlNodeType.SignificantWhitespace: 431 case XmlNodeType.DocumentType: 432 rTW.Write(this._strValue); 433 break; 434 435 case XmlNodeType.Element: 436 strXml = this.Name; 437 rTW.Write('<' + strXml); 438 439 //Put in all the Attributes 440 for (rAttribute = _rFirstAttribute; rAttribute != null; rAttribute = rAttribute.NextAttribute) 441 { 442 rAttribute.WriteXml(rTW); 443 } 444 445 //If there is children, put those in, otherwise close the tag. 446 if ((base._eFlags & NodeFlags.EmptyElement) == 0) 447 { 448 rTW.Write('>'); 449 450 for (rNode = base._rFirstChildNode; rNode != null; rNode = rNode._rNextNode) 451 { 452 rNode.WriteXml(rTW); 453 } 454 455 rTW.Write("</" + strXml + ">"); 456 } 457 else 458 { 459 rTW.Write(" />"); 460 } 461 462 break; 463 464 case XmlNodeType.EntityReference: 465 rTW.Write("&" + this._strName + ";"); 466 break; 467 468 case XmlNodeType.Notation: 469 rTW.Write("<!NOTATION " + this._strValue + ">"); 470 break; 471 472 case XmlNodeType.CDATA: 473 rTW.Write("<![CDATA[" + this._strValue + "]]>"); 474 break; 475 476 case XmlNodeType.XmlDeclaration: 477 case XmlNodeType.ProcessingInstruction: 478 rTW.Write("<?" + this._strName + " " + this._strValue + "?>"); 479 break; 480 481 case XmlNodeType.Comment: 482 rTW.Write("<!--" + this._strValue + "-->"); 483 break; 484 485 default: 486 throw (new Exception("Unhandled NodeType " + this._nType.ToString())); 487 } 488 } 489 490 // 491 // Public Methods and Properties 492 // 493 public string NodeValue 494 { 495 get { return _strValue; } 496 } 497 498 override public string Value 499 { 500 get 501 { 502 string strValue = ""; 503 CXmlNode rChild; 504 505 if ((this._eFlags & NodeFlags.HasValue) != 0) 506 { 507 char chEnt; 508 int nIndexAmp = 0; 509 int nIndexSem = 0; 510 511 if ((this._eFlags & NodeFlags.UnparsedEntities) == 0) 512 return this._strValue; 513 514 strValue = this._strValue; 515 516 while ((nIndexAmp = strValue.IndexOf('&', nIndexAmp)) != -1) 517 { 518 nIndexSem = strValue.IndexOf(';', nIndexAmp); 519 chEnt = ResolveCharEntity(strValue.Substring(nIndexAmp + 1, nIndexSem - nIndexAmp - 1)); 520 if (chEnt != char.MinValue) 521 { 522 strValue = strValue.Substring(0, nIndexAmp) + chEnt + strValue.Substring(nIndexSem + 1); 523 nIndexAmp++; 524 } 525 else 526 nIndexAmp = nIndexSem; 527 } 528 return strValue; 529 } 530 531 for (rChild = (CXmlNode)this._rFirstChildNode; rChild != null; rChild = (CXmlNode)rChild._rNextNode) 532 { 533 strValue = strValue + rChild.Value; 534 } 535 536 return strValue; 537 } 538 } 539 540 public CXmlNode NextNode 541 { 542 get 543 { 544 CXmlBase rNode = this._rNextNode; 545 546 while (rNode != null && 547 (rNode.Flags & NodeFlags.IsWhitespace) != 0) 548 rNode = rNode._rNextNode; 549 return (CXmlNode)rNode; 550 } 551 } 552 553 public CXmlNode FirstChild 554 { 555 get 556 { 557 CXmlBase rNode = this._rFirstChildNode; 558 559 while (rNode != null && 560 (rNode.Flags & NodeFlags.IsWhitespace) != 0) 561 rNode = rNode._rNextNode; 562 return (CXmlNode)rNode; 563 } 564 } 565 Child(int n)566 public CXmlNode Child(int n) 567 { 568 int i; 569 CXmlNode rChild; 570 571 i = 0; 572 for (rChild = FirstChild; rChild != null; rChild = rChild.NextNode) 573 if (i++ == n) break; 574 575 return rChild; 576 } 577 Child(string str)578 public CXmlNode Child(string str) 579 { 580 return (CXmlNode)base._Child(str); 581 } 582 583 public int Type 584 { 585 get { return Convert.ToInt32(base._nType); } 586 } 587 588 public CXmlAttribute FirstAttribute 589 { 590 get { return _rFirstAttribute; } 591 } 592 593 public int AttributeCount 594 { 595 get { return _nAttributeCount; } 596 } 597 Attribute(int n)598 public CXmlAttribute Attribute(int n) 599 { 600 int i; 601 CXmlAttribute rAttribute; 602 603 i = 0; 604 for (rAttribute = _rFirstAttribute; rAttribute != null; rAttribute = rAttribute.NextAttribute) 605 if (i++ == n) break; 606 return rAttribute; 607 } 608 Attribute(string str)609 public CXmlAttribute Attribute(string str) 610 { 611 CXmlAttribute rAttribute; 612 613 for (rAttribute = _rFirstAttribute; rAttribute != null; rAttribute = rAttribute.NextAttribute) 614 { 615 if (rAttribute.Name == str) break; 616 } 617 618 return rAttribute; 619 } 620 AddAttribute(CXmlAttribute rAttribute)621 public void AddAttribute(CXmlAttribute rAttribute) 622 { 623 if (_rFirstAttribute == null) 624 { 625 _rFirstAttribute = rAttribute; 626 } 627 else 628 { 629 _rLastAttribute._rNextNode = rAttribute; 630 } 631 _rLastAttribute = rAttribute; 632 _nAttributeCount++; 633 } 634 ResolveCharEntity(string strName)635 private char ResolveCharEntity(string strName) 636 { 637 if (strName[0] == '#') 638 if (strName[1] == 'x') 639 return Convert.ToChar(Convert.ToInt32(strName.Substring(2), 16)); 640 else 641 return Convert.ToChar(Convert.ToInt32(strName.Substring(1))); 642 if (strName == "lt") 643 return '<'; 644 if (strName == "gt") 645 return '>'; 646 if (strName == "amp") 647 return '&'; 648 if (strName == "apos") 649 return '\''; 650 if (strName == "quot") 651 return '"'; 652 653 return char.MinValue; 654 } 655 } 656 657 public class CXmlCache 658 { 659 //CXmlCache Properties 660 private bool _fTrace = false; 661 662 private bool _fThrow = true; 663 private bool _fReadNode = true; 664 private int _hr = 0; 665 private Encoding _eEncoding = System.Text.Encoding.UTF8; 666 private string _strParseError = ""; 667 668 //XmlReader Properties 669 #pragma warning disable 0618 670 private ValidationType _eValidationMode = ValidationType.Auto; 671 #pragma warning restore 0618 672 673 private WhitespaceHandling _eWhitespaceMode = WhitespaceHandling.None; 674 private EntityHandling _eEntityMode = EntityHandling.ExpandEntities; 675 private bool _fNamespaces = true; 676 677 private bool _fValidationCallback = false; 678 private bool _fExpandAttributeValues = false; 679 680 //Internal stuff 681 protected XmlReader _rXmlReader = null; 682 683 protected CXmlNode _rDocumentRootNode; 684 protected CXmlNode _rRootNode = null; 685 internal static NodeFlags _eDefaultFlags = NodeFlags.None; 686 687 private ITestOutputHelper _output; CXmlCache(ITestOutputHelper output)688 public CXmlCache(ITestOutputHelper output) 689 { 690 _output = output; 691 } 692 693 // 694 // Constructor 695 // CXmlCache()696 public CXmlCache() 697 { 698 } 699 700 // 701 // Public Methods and Properties 702 // Load(XmlReader rXmlReader)703 public virtual bool Load(XmlReader rXmlReader) 704 { 705 //Hook up your reader as my reader 706 _rXmlReader = rXmlReader; 707 708 if (rXmlReader is XmlTextReader) 709 { 710 _eWhitespaceMode = ((XmlTextReader)rXmlReader).WhitespaceHandling; 711 _fNamespaces = ((XmlTextReader)rXmlReader).Namespaces; 712 _eValidationMode = ValidationType.None; 713 } 714 #pragma warning disable 0618 715 if (rXmlReader is XmlValidatingReader) 716 { 717 if (((XmlValidatingReader)rXmlReader).Reader is XmlTextReader) 718 { 719 _eWhitespaceMode = ((XmlTextReader)((XmlValidatingReader)rXmlReader).Reader).WhitespaceHandling; 720 } 721 else 722 { 723 _eWhitespaceMode = WhitespaceHandling.None; 724 } 725 _fNamespaces = ((XmlValidatingReader)rXmlReader).Namespaces; 726 _eValidationMode = ((XmlValidatingReader)rXmlReader).ValidationType; 727 _eEntityMode = ((XmlValidatingReader)rXmlReader).EntityHandling; 728 } 729 #pragma warning restore 0618 730 731 DebugTrace("Setting ValidationMode=" + _eValidationMode.ToString()); 732 DebugTrace("Setting EntityMode=" + _eEntityMode.ToString()); 733 DebugTrace("Setting WhitespaceMode=" + _eWhitespaceMode.ToString()); 734 735 //Process the Document 736 try 737 { 738 _rDocumentRootNode = new CXmlNode("", "", XmlNodeType.Element); 739 _rDocumentRootNode._eFlags = NodeFlags.DocumentRoot | NodeFlags.Indent; 740 Process(_rDocumentRootNode); 741 for (_rRootNode = _rDocumentRootNode.FirstChild; _rRootNode != null && _rRootNode.NodeType != XmlNodeType.Element; _rRootNode = _rRootNode.NextNode) ; 742 } 743 catch (Exception e) 744 { 745 //Unhook your reader 746 _rXmlReader = null; 747 748 _strParseError = e.ToString(); 749 750 if (_fThrow) 751 { 752 throw (e); 753 } 754 755 if (_hr == 0) 756 _hr = -1; 757 758 return false; 759 } 760 761 //Unhook your reader 762 _rXmlReader = null; 763 764 return true; 765 } 766 Load(string strFileName)767 public bool Load(string strFileName) 768 { 769 #pragma warning disable 0618 770 XmlTextReader rXmlTextReader; 771 XmlValidatingReader rXmlValidatingReader; 772 bool fRet; 773 774 rXmlTextReader = new XmlTextReader(strFileName); 775 rXmlTextReader.WhitespaceHandling = _eWhitespaceMode; 776 rXmlTextReader.Namespaces = _fNamespaces; 777 778 _eEncoding = rXmlTextReader.Encoding; 779 780 rXmlValidatingReader = new XmlValidatingReader(rXmlTextReader); 781 rXmlValidatingReader.ValidationType = _eValidationMode; 782 rXmlValidatingReader.EntityHandling = _eEntityMode; 783 #pragma warning restore 0618 784 785 if (_fValidationCallback) 786 rXmlValidatingReader.ValidationEventHandler += new ValidationEventHandler(this.ValidationCallback); 787 788 try 789 { 790 fRet = Load((XmlReader)rXmlValidatingReader); 791 } 792 catch (Exception e) 793 { 794 fRet = false; 795 rXmlValidatingReader.Dispose(); 796 rXmlTextReader.Dispose(); 797 798 if (_strParseError == string.Empty) 799 _strParseError = e.ToString(); 800 801 if (_fThrow) 802 throw (e); 803 } 804 805 rXmlValidatingReader.Dispose(); 806 rXmlTextReader.Dispose(); 807 return fRet; 808 } 809 Save(string strName)810 public void Save(string strName) 811 { 812 Save(strName, false, _eEncoding); 813 } 814 Save(string strName, bool fOverWrite)815 public void Save(string strName, bool fOverWrite) 816 { 817 Save(strName, fOverWrite, _eEncoding); 818 } 819 Save(string strName, bool fOverWrite, System.Text.Encoding Encoding)820 public void Save(string strName, bool fOverWrite, System.Text.Encoding Encoding) 821 { 822 CXmlBase rNode; 823 XmlTextWriter rXmlTextWriter = null; 824 825 try 826 { 827 if (fOverWrite) 828 { 829 File.Delete(strName); 830 } 831 832 rXmlTextWriter = new XmlTextWriter(strName, Encoding); 833 rXmlTextWriter.Namespaces = _fNamespaces; 834 835 for (rNode = _rDocumentRootNode._rFirstChildNode; rNode != null; rNode = rNode._rNextNode) 836 { 837 rNode.Write(rXmlTextWriter); 838 } 839 rXmlTextWriter.Dispose(); 840 } 841 catch (Exception e) 842 { 843 DebugTrace(e.ToString()); 844 if (rXmlTextWriter != null) 845 rXmlTextWriter.Dispose(); 846 throw (e); 847 } 848 } 849 WriteXml(TextWriter rTW)850 public void WriteXml(TextWriter rTW) 851 { 852 CXmlBase rNode; 853 854 //Spit out the document 855 for (rNode = _rDocumentRootNode._rFirstChildNode; rNode != null; rNode = rNode._rNextNode) 856 rNode.WriteXml(rTW); 857 } 858 859 public CXmlNode RootNode 860 { 861 get { return _rRootNode; } 862 } 863 864 public string ParseError 865 { 866 get { return _strParseError; } 867 } 868 869 public int ParseErrorCode 870 { 871 get { return _hr; } 872 } 873 874 // 875 // XmlReader Properties 876 // 877 public string EntityMode 878 { 879 set 880 { 881 if (value == "ExpandEntities") 882 _eEntityMode = EntityHandling.ExpandEntities; 883 else if (value == "ExpandCharEntities") 884 _eEntityMode = EntityHandling.ExpandCharEntities; 885 else 886 throw (new Exception("Invalid Entity mode.")); 887 } 888 get { return _eEntityMode.ToString(); } 889 } 890 891 public string ValidationMode 892 { 893 set 894 { 895 #pragma warning disable 0618 896 if (value == "None") 897 _eValidationMode = ValidationType.None; 898 else if (value == "DTD") 899 _eValidationMode = ValidationType.DTD; 900 else if (value == "XDR") 901 _eValidationMode = ValidationType.XDR; 902 else if (value == "Schema") 903 _eValidationMode = ValidationType.Schema; 904 else if (value == "Auto") 905 _eValidationMode = ValidationType.Auto; 906 else 907 throw (new Exception("Invalid Validation mode.")); 908 #pragma warning restore 0618 909 } 910 get { return _eValidationMode.ToString(); } 911 } 912 913 public string WhitespaceMode 914 { 915 set 916 { 917 if (value == "All") 918 _eWhitespaceMode = WhitespaceHandling.All; 919 else if (value == "Significant") 920 _eWhitespaceMode = WhitespaceHandling.Significant; 921 else if (value == "None") 922 _eWhitespaceMode = WhitespaceHandling.None; 923 else 924 throw (new Exception("Invalid Whitespace mode.")); 925 } 926 get { return _eWhitespaceMode.ToString(); } 927 } 928 929 public bool Namespaces 930 { 931 set { _fNamespaces = value; } 932 get { return _fNamespaces; } 933 } 934 935 public bool UseValidationCallback 936 { 937 set { _fValidationCallback = value; } 938 get { return _fValidationCallback; } 939 } 940 941 public bool ExpandAttributeValues 942 { 943 set { _fExpandAttributeValues = value; } 944 get { return _fExpandAttributeValues; } 945 } 946 947 // 948 // Internal Properties 949 // 950 public bool Throw 951 { 952 get { return _fThrow; } 953 set { _fThrow = value; } 954 } 955 956 public bool Trace 957 { 958 set { _fTrace = value; } 959 get { return _fTrace; } 960 } 961 962 // 963 //Private Methods 964 // DebugTrace(string str)965 private void DebugTrace(string str) 966 { 967 DebugTrace(str, 0); 968 } 969 DebugTrace(string str, int nDepth)970 private void DebugTrace(string str, int nDepth) 971 { 972 if (_fTrace) 973 { 974 int i; 975 976 for (i = 0; i < nDepth; i++) 977 _output.WriteLine(" "); 978 _output.WriteLine(str); 979 } 980 } 981 DebugTrace(XmlReader rXmlReader)982 private void DebugTrace(XmlReader rXmlReader) 983 { 984 if (_fTrace) 985 { 986 string str; 987 988 str = rXmlReader.NodeType.ToString() + ", Depth=" + rXmlReader.Depth + " Name="; 989 if (rXmlReader.Prefix != "") 990 { 991 str += rXmlReader.Prefix + ":"; 992 } 993 str += rXmlReader.LocalName; 994 995 if (rXmlReader.HasValue) 996 str += " Value=" + rXmlReader.Value; 997 998 if (rXmlReader.NodeType == XmlNodeType.Attribute) 999 str += " QuoteChar=" + rXmlReader.QuoteChar; 1000 1001 DebugTrace(str, rXmlReader.Depth); 1002 } 1003 } 1004 Process(CXmlBase rParentNode)1005 protected void Process(CXmlBase rParentNode) 1006 { 1007 CXmlNode rNewNode; 1008 1009 while (true) 1010 { 1011 //We want to pop if Read() returns false, aka EOF 1012 if (_fReadNode) 1013 { 1014 if (!_rXmlReader.Read()) 1015 { 1016 DebugTrace("Read() == false"); 1017 return; 1018 } 1019 } 1020 else 1021 { 1022 if (!_rXmlReader.ReadAttributeValue()) 1023 { 1024 DebugTrace("ReadAttributeValue() == false"); 1025 return; 1026 } 1027 } 1028 1029 DebugTrace(_rXmlReader); 1030 1031 //We also want to pop if we get an EndElement or EndEntity 1032 if (_rXmlReader.NodeType == XmlNodeType.EndElement || 1033 _rXmlReader.NodeType == XmlNodeType.EndEntity) 1034 { 1035 DebugTrace("NodeType == EndElement or EndEntity"); 1036 return; 1037 } 1038 1039 rNewNode = GetNewNode(_rXmlReader); 1040 rNewNode._nDepth = _rXmlReader.Depth; 1041 1042 // Test for MixedContent and set Indent if necessary 1043 if ((rParentNode.Flags & NodeFlags.MixedContent) != 0) 1044 { 1045 rNewNode._eFlags |= NodeFlags.MixedContent; 1046 // Indent is off for all new nodes 1047 } 1048 else 1049 { 1050 rNewNode._eFlags |= NodeFlags.Indent; // Turn on Indent for current Node 1051 } 1052 1053 // Set all Depth 0 nodes to No Mixed Content and Indent True 1054 if (_rXmlReader.Depth == 0) 1055 { 1056 rNewNode._eFlags |= NodeFlags.Indent; // Turn on Indent 1057 rNewNode._eFlags &= ~NodeFlags.MixedContent; // Turn off MixedContent 1058 } 1059 1060 rParentNode.InsertNode(rNewNode); 1061 1062 //Do some special stuff based on NodeType 1063 switch (_rXmlReader.NodeType) 1064 { 1065 case XmlNodeType.EntityReference: 1066 if (_eValidationMode == ValidationType.DTD) 1067 { 1068 _rXmlReader.ResolveEntity(); 1069 Process(rNewNode); 1070 } 1071 break; 1072 1073 case XmlNodeType.Element: 1074 if (_rXmlReader.MoveToFirstAttribute()) 1075 { 1076 do 1077 { 1078 CXmlAttribute rNewAttribute = new CXmlAttribute(_rXmlReader); 1079 rNewNode.AddAttribute(rNewAttribute); 1080 1081 if (_fExpandAttributeValues) 1082 { 1083 DebugTrace("Attribute: " + _rXmlReader.Name); 1084 _fReadNode = false; 1085 Process(rNewAttribute); 1086 _fReadNode = true; 1087 } 1088 else 1089 { 1090 CXmlNode rValueNode = new CXmlNode("", "", XmlNodeType.Text); 1091 rValueNode._eFlags = _eDefaultFlags | NodeFlags.HasValue; 1092 1093 rValueNode._strValue = _rXmlReader.Value; 1094 1095 DebugTrace(" Value=" + rValueNode.Value, _rXmlReader.Depth + 1); 1096 1097 rNewAttribute.InsertNode(rValueNode); 1098 } 1099 } while (_rXmlReader.MoveToNextAttribute()); 1100 } 1101 1102 if ((rNewNode.Flags & NodeFlags.EmptyElement) == 0) 1103 Process(rNewNode); 1104 1105 break; 1106 1107 case XmlNodeType.XmlDeclaration: 1108 if (_rXmlReader is XmlTextReader) 1109 { 1110 _eEncoding = ((XmlTextReader)_rXmlReader).Encoding; 1111 } 1112 #pragma warning disable 0618 1113 else if (_rXmlReader is XmlValidatingReader) 1114 { 1115 _eEncoding = ((XmlValidatingReader)_rXmlReader).Encoding; 1116 } 1117 #pragma warning restore 0618 1118 else 1119 { 1120 string strValue = rNewNode.NodeValue; 1121 int nPos = strValue.IndexOf("encoding"); 1122 if (nPos != -1) 1123 { 1124 int nEnd; 1125 1126 nPos = strValue.IndexOf("=", nPos); //Find the = sign 1127 nEnd = strValue.IndexOf("\"", nPos) + 1; //Find the next " character 1128 nPos = strValue.IndexOf("'", nPos) + 1; //Find the next ' character 1129 if (nEnd == 0 || (nPos < nEnd && nPos > 0)) //Pick the one that's closer to the = sign 1130 { 1131 nEnd = strValue.IndexOf("'", nPos); 1132 } 1133 else 1134 { 1135 nPos = nEnd; 1136 nEnd = strValue.IndexOf("\"", nPos); 1137 } 1138 string sEncodeName = strValue.Substring(nPos, nEnd - nPos); 1139 DebugTrace("XMLDecl contains encoding " + sEncodeName); 1140 if (sEncodeName.ToUpper() == "UCS-2") 1141 { 1142 sEncodeName = "unicode"; 1143 } 1144 _eEncoding = System.Text.Encoding.GetEncoding(sEncodeName); 1145 } 1146 } 1147 break; 1148 1149 case XmlNodeType.ProcessingInstruction: 1150 break; 1151 1152 case XmlNodeType.Text: 1153 if (!_fReadNode) 1154 { 1155 rNewNode._eFlags = _eDefaultFlags | NodeFlags.AttributeTextNode; 1156 } 1157 rNewNode._eFlags |= NodeFlags.MixedContent; // turn on Mixed Content for current node 1158 rNewNode._eFlags &= ~NodeFlags.Indent; // turn off Indent for current node 1159 rParentNode._eFlags |= NodeFlags.MixedContent; // turn on Mixed Content for Parent Node 1160 break; 1161 1162 case XmlNodeType.Whitespace: 1163 case XmlNodeType.SignificantWhitespace: 1164 case XmlNodeType.CDATA: 1165 rNewNode._eFlags |= NodeFlags.MixedContent; // turn on Mixed Content for current node 1166 rNewNode._eFlags &= ~NodeFlags.Indent; // turn off Indent for current node 1167 rParentNode._eFlags |= NodeFlags.MixedContent; // turn on Mixed Content for Parent Node 1168 break; 1169 1170 case XmlNodeType.Comment: 1171 case XmlNodeType.Notation: 1172 break; 1173 1174 case XmlNodeType.DocumentType: 1175 if (_rXmlReader.MoveToFirstAttribute()) 1176 { 1177 do 1178 { 1179 CXmlAttribute rNewAttribute = new CXmlAttribute(_rXmlReader); 1180 rNewNode.AddAttribute(rNewAttribute); 1181 1182 CXmlNode rValueNode = new CXmlNode(_rXmlReader); 1183 rValueNode._strValue = _rXmlReader.Value; 1184 rNewAttribute.InsertNode(rValueNode); 1185 } while (_rXmlReader.MoveToNextAttribute()); 1186 } 1187 1188 break; 1189 1190 default: 1191 _output.WriteLine("UNHANDLED TYPE, " + _rXmlReader.NodeType.ToString() + " IN Process()!"); 1192 break; 1193 } 1194 } 1195 } 1196 GetNewNode(XmlReader rXmlReader)1197 protected virtual CXmlNode GetNewNode(XmlReader rXmlReader) 1198 { 1199 return new CXmlNode(rXmlReader); 1200 } 1201 ValidationCallback(object sender, ValidationEventArgs args)1202 private void ValidationCallback(object sender, ValidationEventArgs args) 1203 { 1204 // commented by ROCHOA -- don't know where ValidationEventArgs comes from 1205 // _hr = Convert.ToInt16(args.ErrorCode); 1206 throw (new Exception("[" + Convert.ToString(_hr) + "] " + args.Message)); 1207 } 1208 } 1209 1210 public class ChecksumWriter : TextWriter 1211 { 1212 private int _nPosition = 0; 1213 private Decimal _dResult = 0; 1214 private Encoding _encoding; 1215 1216 // -------------------------------------------------------------------------------------------------- 1217 // Constructor 1218 // -------------------------------------------------------------------------------------------------- ChecksumWriter()1219 public ChecksumWriter() 1220 { 1221 _encoding = Encoding.UTF8; 1222 } 1223 1224 // -------------------------------------------------------------------------------------------------- 1225 // Properties 1226 // -------------------------------------------------------------------------------------------------- 1227 public Decimal CheckSum 1228 { 1229 get { return _dResult; } 1230 } 1231 1232 public override Encoding Encoding 1233 { 1234 get { return _encoding; } 1235 } 1236 1237 // -------------------------------------------------------------------------------------------------- 1238 // Public methods 1239 // -------------------------------------------------------------------------------------------------- Write(String str)1240 override public void Write(String str) 1241 { 1242 int i; 1243 int m; 1244 1245 m = str.Length; 1246 for (i = 0; i < m; i++) 1247 { 1248 Write(str[i]); 1249 } 1250 } 1251 Write(Char[] rgch)1252 override public void Write(Char[] rgch) 1253 { 1254 int i; 1255 int m; 1256 1257 m = rgch.Length; 1258 for (i = 0; i < m; i++) 1259 { 1260 Write(rgch[i]); 1261 } 1262 } 1263 Write(Char[] rgch, Int32 iOffset, Int32 iCount)1264 override public void Write(Char[] rgch, Int32 iOffset, Int32 iCount) 1265 { 1266 int i; 1267 int m; 1268 1269 m = iOffset + iCount; 1270 for (i = iOffset; i < m; i++) 1271 { 1272 Write(rgch[i]); 1273 } 1274 } 1275 Write(Char ch)1276 override public void Write(Char ch) 1277 { 1278 _dResult += Math.Round((Decimal)(ch / (_nPosition + 1.0)), 10); 1279 _nPosition++; 1280 } 1281 Close()1282 override public void Close() 1283 { 1284 _nPosition = 0; 1285 _dResult = 0; 1286 } 1287 } 1288