The Labs \ Source Viewer \ SSCLI \ System.Xml \ XmlCharCheckingReader

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XmlCharCheckingReader.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System;
  16. using System.Xml;
  17. using System.Xml.XPath;
  18. using System.Diagnostics;
  19. using System.Collections;
  20. using System.Collections.Generic;
  21. namespace System.Xml
  22. {
  23.    
  24.     //
  25.     // XmlCharCheckingReaderWithNS
  26.     //
  27.     internal class XmlCharCheckingReader : XmlWrappingReader
  28.     {
  29.         //
  30.         // Private types
  31.         //
  32.         enum State
  33.         {
  34.             Initial,
  35.             InReadBinary,
  36.             Error,
  37.             Interactive
  38.             // Interactive means other than ReadState.Initial and ReadState.Error; still needs to call
  39.             // underlying XmlReader to find out if the reported ReadState should be Interactive, EndOfFile or Closed
  40.         }
  41.        
  42.         //
  43.         // Fields
  44.         //
  45.         State state;
  46.        
  47.         // settings
  48.         bool checkCharacters;
  49.         bool ignoreWhitespace;
  50.         bool ignoreComments;
  51.         bool ignorePis;
  52.         bool prohibitDtd;
  53.        
  54.         XmlNodeType lastNodeType;
  55.         XmlCharType xmlCharType;
  56.        
  57.         ReadContentAsBinaryHelper readBinaryHelper;
  58.        
  59.         //
  60.         // Constructor
  61.         //
  62.         internal XmlCharCheckingReader(XmlReader reader, bool checkCharacters, bool ignoreWhitespace, bool ignoreComments, bool ignorePis, bool prohibitDtd) : base(reader)
  63.         {
  64.            
  65.             Debug.Assert(checkCharacters || ignoreWhitespace || ignoreComments || ignorePis || prohibitDtd);
  66.            
  67.             state = State.Initial;
  68.            
  69.             this.checkCharacters = checkCharacters;
  70.             this.ignoreWhitespace = ignoreWhitespace;
  71.             this.ignoreComments = ignoreComments;
  72.             this.ignorePis = ignorePis;
  73.             this.prohibitDtd = prohibitDtd;
  74.            
  75.             lastNodeType = XmlNodeType.None;
  76.            
  77.             if (checkCharacters) {
  78.                 xmlCharType = XmlCharType.Instance;
  79.             }
  80.         }
  81.        
  82.         //
  83.         // XmlReader implementation
  84.         //
  85.         public override XmlReaderSettings Settings {
  86.             get {
  87.                 XmlReaderSettings settings = reader.Settings;
  88.                 if (settings == null) {
  89.                     settings = new XmlReaderSettings();
  90.                 }
  91.                 else {
  92.                     settings = settings.Clone();
  93.                 }
  94.                
  95.                 if (checkCharacters) {
  96.                     settings.CheckCharacters = true;
  97.                 }
  98.                 if (ignoreWhitespace) {
  99.                     settings.IgnoreWhitespace = true;
  100.                 }
  101.                 if (ignoreComments) {
  102.                     settings.IgnoreComments = true;
  103.                 }
  104.                 if (ignorePis) {
  105.                     settings.IgnoreProcessingInstructions = true;
  106.                 }
  107.                 if (prohibitDtd) {
  108.                     settings.ProhibitDtd = true;
  109.                 }
  110.                 settings.ReadOnly = true;
  111.                 return settings;
  112.             }
  113.         }
  114.        
  115.         public override bool MoveToAttribute(string name)
  116.         {
  117.             if (state == State.InReadBinary) {
  118.                 FinishReadBinary();
  119.             }
  120.             return base.reader.MoveToAttribute(name);
  121.         }
  122.        
  123.         public override bool MoveToAttribute(string name, string ns)
  124.         {
  125.             if (state == State.InReadBinary) {
  126.                 FinishReadBinary();
  127.             }
  128.             return base.reader.MoveToAttribute(name, ns);
  129.         }
  130.        
  131.         public override void MoveToAttribute(int i)
  132.         {
  133.             if (state == State.InReadBinary) {
  134.                 FinishReadBinary();
  135.             }
  136.             base.reader.MoveToAttribute(i);
  137.         }
  138.        
  139.         public override bool MoveToFirstAttribute()
  140.         {
  141.             if (state == State.InReadBinary) {
  142.                 FinishReadBinary();
  143.             }
  144.             return base.reader.MoveToFirstAttribute();
  145.         }
  146.        
  147.         public override bool MoveToNextAttribute()
  148.         {
  149.             if (state == State.InReadBinary) {
  150.                 FinishReadBinary();
  151.             }
  152.             return base.reader.MoveToNextAttribute();
  153.         }
  154.        
  155.         public override bool MoveToElement()
  156.         {
  157.             if (state == State.InReadBinary) {
  158.                 FinishReadBinary();
  159.             }
  160.             return base.reader.MoveToElement();
  161.         }
  162.        
  163.         public override bool Read()
  164.         {
  165.            
  166.             switch (state) {
  167.                 case State.Initial:
  168.                     state = State.Interactive;
  169.                     if (base.reader.ReadState == ReadState.Initial) {
  170.                         goto case State.Interactive;
  171.                     }
  172.                     break;
  173.                 case State.Error:
  174.                    
  175.                     return false;
  176.                 case State.InReadBinary:
  177.                    
  178.                     FinishReadBinary();
  179.                     state = State.Interactive;
  180.                     goto case State.Interactive;
  181.                     break;
  182.                 case State.Interactive:
  183.                    
  184.                     if (!base.reader.Read()) {
  185.                         return false;
  186.                     }
  187.                     break;
  188.                 default:
  189.                    
  190.                     Debug.Assert(false);
  191.                     return false;
  192.             }
  193.            
  194.             XmlNodeType nodeType = base.reader.NodeType;
  195.            
  196.             if (!checkCharacters) {
  197.                 switch (nodeType) {
  198.                     case XmlNodeType.Comment:
  199.                         if (ignoreComments) {
  200.                             return Read();
  201.                         }
  202.                         break;
  203.                     case XmlNodeType.Whitespace:
  204.                         if (ignoreWhitespace) {
  205.                             return Read();
  206.                         }
  207.                         break;
  208.                     case XmlNodeType.ProcessingInstruction:
  209.                         if (ignorePis) {
  210.                             return Read();
  211.                         }
  212.                         break;
  213.                     case XmlNodeType.DocumentType:
  214.                         if (prohibitDtd) {
  215.                             Throw(Res.Xml_DtdIsProhibited, string.Empty);
  216.                         }
  217.                         break;
  218.                 }
  219.                 return true;
  220.             }
  221.             else {
  222.                 switch (nodeType) {
  223.                     case XmlNodeType.Element:
  224.                         if (checkCharacters) {
  225.                             // check element name
  226.                             ValidateQName(base.reader.Prefix, base.reader.LocalName);
  227.                            
  228.                             // check values of attributes
  229.                             if (base.reader.MoveToFirstAttribute()) {
  230.                                 do {
  231.                                     ValidateQName(base.reader.Prefix, base.reader.LocalName);
  232.                                     CheckCharacters(base.reader.Value);
  233.                                 }
  234.                                 while (base.reader.MoveToNextAttribute());
  235.                                
  236.                                 base.reader.MoveToElement();
  237.                             }
  238.                         }
  239.                         break;
  240.                     case XmlNodeType.Text:
  241.                     case XmlNodeType.CDATA:
  242.                        
  243.                         if (checkCharacters) {
  244.                             CheckCharacters(base.reader.Value);
  245.                         }
  246.                         break;
  247.                     case XmlNodeType.EntityReference:
  248.                        
  249.                         if (checkCharacters) {
  250.                             // check name
  251.                             ValidateQName(base.reader.Name);
  252.                         }
  253.                         break;
  254.                     case XmlNodeType.ProcessingInstruction:
  255.                        
  256.                         if (ignorePis) {
  257.                             return Read();
  258.                         }
  259.                         if (checkCharacters) {
  260.                             ValidateQName(base.reader.Name);
  261.                             CheckCharacters(base.reader.Value);
  262.                         }
  263.                         break;
  264.                     case XmlNodeType.Comment:
  265.                        
  266.                         if (ignoreComments) {
  267.                             return Read();
  268.                         }
  269.                         if (checkCharacters) {
  270.                             CheckCharacters(base.reader.Value);
  271.                         }
  272.                         break;
  273.                     case XmlNodeType.DocumentType:
  274.                        
  275.                         if (prohibitDtd) {
  276.                             Throw(Res.Xml_DtdIsProhibited, string.Empty);
  277.                         }
  278.                         if (checkCharacters) {
  279.                             ValidateQName(base.reader.Name);
  280.                             CheckCharacters(base.reader.Value);
  281.                            
  282.                             string str;
  283.                             str = base.reader.GetAttribute("SYSTEM");
  284.                             if (str != null) {
  285.                                 CheckCharacters(str);
  286.                             }
  287.                            
  288.                             str = base.reader.GetAttribute("PUBLIC");
  289.                             if (str != null) {
  290.                                 int i;
  291.                                 if ((i = xmlCharType.IsPublicId(str)) >= 0) {
  292.                                     Throw(Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionStr(str[i]));
  293.                                 }
  294.                             }
  295.                         }
  296.                         break;
  297.                     case XmlNodeType.Whitespace:
  298.                        
  299.                         if (ignoreWhitespace) {
  300.                             return Read();
  301.                         }
  302.                         if (checkCharacters) {
  303.                             CheckWhitespace(base.reader.Value);
  304.                         }
  305.                         break;
  306.                     case XmlNodeType.SignificantWhitespace:
  307.                        
  308.                         if (checkCharacters) {
  309.                             CheckWhitespace(base.reader.Value);
  310.                         }
  311.                         break;
  312.                     case XmlNodeType.EndElement:
  313.                        
  314.                         if (checkCharacters) {
  315.                             ValidateQName(base.reader.Prefix, base.reader.LocalName);
  316.                         }
  317.                         break;
  318.                     default:
  319.                        
  320.                         break;
  321.                 }
  322.                 lastNodeType = nodeType;
  323.                 return true;
  324.             }
  325.         }
  326.        
  327.         public override ReadState ReadState {
  328.             get {
  329.                 switch (state) {
  330.                     case State.Initial:
  331.                         return ReadState.Initial;
  332.                     case State.Error:
  333.                         return ReadState.Error;
  334.                     case State.InReadBinary:
  335.                     case State.Interactive:
  336.                     default:
  337.                         return base.reader.ReadState;
  338.                 }
  339.             }
  340.         }
  341.        
  342.         public override void ResolveEntity()
  343.         {
  344.             base.reader.ResolveEntity();
  345.         }
  346.        
  347.         public override bool ReadAttributeValue()
  348.         {
  349.             if (state == State.InReadBinary) {
  350.                 FinishReadBinary();
  351.             }
  352.             return base.reader.ReadAttributeValue();
  353.         }
  354.        
  355.         public override bool CanReadBinaryContent {
  356.             get { return true; }
  357.         }
  358.        
  359.         public override int ReadContentAsBase64(byte[] buffer, int index, int count)
  360.         {
  361.             if (ReadState != ReadState.Interactive) {
  362.                 return 0;
  363.             }
  364.            
  365.             if (state != State.InReadBinary) {
  366.                 // forward ReadBase64Chunk calls into the base (wrapped) reader if possible, i.e. if it can read binary and we
  367.                 // should not check characters
  368.                 if (base.CanReadBinaryContent && (!checkCharacters)) {
  369.                     readBinaryHelper = null;
  370.                     state = State.InReadBinary;
  371.                     return base.ReadContentAsBase64(buffer, index, count);
  372.                 }
  373.                 // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore white spaces
  374.                 else {
  375.                     readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(readBinaryHelper, this);
  376.                 }
  377.             }
  378.             else {
  379.                 // forward calls into wrapped reader
  380.                 if (readBinaryHelper == null) {
  381.                     return base.ReadContentAsBase64(buffer, index, count);
  382.                 }
  383.             }
  384.            
  385.             // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
  386.             state = State.Interactive;
  387.            
  388.             // call to the helper
  389.             int readCount = readBinaryHelper.ReadContentAsBase64(buffer, index, count);
  390.            
  391.             // turn on InReadBinary in again and return
  392.             state = State.InReadBinary;
  393.             return readCount;
  394.         }
  395.        
  396.         public override int ReadContentAsBinHex(byte[] buffer, int index, int count)
  397.         {
  398.             if (ReadState != ReadState.Interactive) {
  399.                 return 0;
  400.             }
  401.            
  402.             if (state != State.InReadBinary) {
  403.                 // forward ReadBinHexChunk calls into the base (wrapped) reader if possible, i.e. if it can read chunks and we
  404.                 // should not check characters
  405.                 if (base.CanReadBinaryContent && (!checkCharacters)) {
  406.                     readBinaryHelper = null;
  407.                     state = State.InReadBinary;
  408.                     return base.ReadContentAsBinHex(buffer, index, count);
  409.                 }
  410.                 // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore white spaces
  411.                 else {
  412.                     readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(readBinaryHelper, this);
  413.                 }
  414.             }
  415.             else {
  416.                 // forward calls into wrapped reader
  417.                 if (readBinaryHelper == null) {
  418.                     return base.ReadContentAsBinHex(buffer, index, count);
  419.                 }
  420.             }
  421.            
  422.             // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
  423.             state = State.Interactive;
  424.            
  425.             // call to the helper
  426.             int readCount = readBinaryHelper.ReadContentAsBinHex(buffer, index, count);
  427.            
  428.             // turn on InReadBinary in again and return
  429.             state = State.InReadBinary;
  430.             return readCount;
  431.         }
  432.        
  433.         public override int ReadElementContentAsBase64(byte[] buffer, int index, int count)
  434.         {
  435.             if (ReadState != ReadState.Interactive) {
  436.                 return 0;
  437.             }
  438.            
  439.             if (state != State.InReadBinary) {
  440.                 // forward ReadBase64Chunk calls into the base (wrapped) reader if possible, i.e. if it can read binary and we
  441.                 // should not check characters
  442.                 if (base.CanReadBinaryContent && (!checkCharacters)) {
  443.                     readBinaryHelper = null;
  444.                     state = State.InReadBinary;
  445.                     return base.ReadElementContentAsBase64(buffer, index, count);
  446.                 }
  447.                 // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore white spaces
  448.                 else {
  449.                     readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(readBinaryHelper, this);
  450.                 }
  451.             }
  452.             else {
  453.                 // forward calls into wrapped reader
  454.                 if (readBinaryHelper == null) {
  455.                     return base.ReadElementContentAsBase64(buffer, index, count);
  456.                 }
  457.             }
  458.            
  459.             // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
  460.             state = State.Interactive;
  461.            
  462.             // call to the helper
  463.             int readCount = readBinaryHelper.ReadElementContentAsBase64(buffer, index, count);
  464.            
  465.             // turn on InReadBinary in again and return
  466.             state = State.InReadBinary;
  467.             return readCount;
  468.         }
  469.        
  470.         public override int ReadElementContentAsBinHex(byte[] buffer, int index, int count)
  471.         {
  472.             if (ReadState != ReadState.Interactive) {
  473.                 return 0;
  474.             }
  475.            
  476.             if (state != State.InReadBinary) {
  477.                 // forward ReadBinHexChunk calls into the base (wrapped) reader if possible, i.e. if it can read chunks and we
  478.                 // should not check characters
  479.                 if (base.CanReadBinaryContent && (!checkCharacters)) {
  480.                     readBinaryHelper = null;
  481.                     state = State.InReadBinary;
  482.                     return base.ReadElementContentAsBinHex(buffer, index, count);
  483.                 }
  484.                 // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore white spaces
  485.                 else {
  486.                     readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(readBinaryHelper, this);
  487.                 }
  488.             }
  489.             else {
  490.                 // forward calls into wrapped reader
  491.                 if (readBinaryHelper == null) {
  492.                     return base.ReadElementContentAsBinHex(buffer, index, count);
  493.                 }
  494.             }
  495.            
  496.             // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
  497.             state = State.Interactive;
  498.            
  499.             // call to the helper
  500.             int readCount = readBinaryHelper.ReadElementContentAsBinHex(buffer, index, count);
  501.            
  502.             // turn on InReadBinary in again and return
  503.             state = State.InReadBinary;
  504.             return readCount;
  505.         }
  506.        
  507.         //
  508.         // Private methods and properties
  509.         //
  510.        
  511.         private void Throw(string res, string arg)
  512.         {
  513.             state = State.Error;
  514.             throw new XmlException(res, arg, (IXmlLineInfo)null);
  515.         }
  516.        
  517.         private void Throw(string res, string[] args)
  518.         {
  519.             state = State.Error;
  520.             throw new XmlException(res, args, (IXmlLineInfo)null);
  521.         }
  522.        
  523.         private void CheckWhitespace(string value)
  524.         {
  525.             int i;
  526.             if ((i = xmlCharType.IsOnlyWhitespaceWithPos(value)) != -1) {
  527.                 Throw(Res.Xml_InvalidWhitespaceCharacter, XmlException.BuildCharExceptionStr(base.reader.Value[i]));
  528.             }
  529.         }
  530.        
  531.         private void ValidateQName(string name)
  532.         {
  533.             string prefix;
  534.             string localName;
  535.             ValidateNames.ParseQNameThrow(name, out prefix, out localName);
  536.         }
  537.        
  538.         private void ValidateQName(string prefix, string localName)
  539.         {
  540.             try {
  541.                 if (prefix.Length > 0) {
  542.                     ValidateNames.ParseNCNameThrow(prefix);
  543.                 }
  544.                 ValidateNames.ParseNCNameThrow(localName);
  545.             }
  546.             catch {
  547.                 state = State.Error;
  548.                 throw;
  549.             }
  550.         }
  551.        
  552.         private void CheckCharacters(string value)
  553.         {
  554.             XmlConvert.VerifyCharData(value, ExceptionType.XmlException);
  555.         }
  556.        
  557.         private void FinishReadBinary()
  558.         {
  559.             state = State.Interactive;
  560.             if (readBinaryHelper != null) {
  561.                 readBinaryHelper.Finish();
  562.             }
  563.         }
  564.     }
  565.    
  566.     //
  567.     // XmlCharCheckingReaderWithNS
  568.     //
  569.     internal class XmlCharCheckingReaderWithNS : XmlCharCheckingReader, IXmlNamespaceResolver
  570.     {
  571.        
  572.         internal IXmlNamespaceResolver readerAsNSResolver;
  573.        
  574.         internal XmlCharCheckingReaderWithNS(XmlReader reader, IXmlNamespaceResolver readerAsNSResolver, bool checkCharacters, bool ignoreWhitespace, bool ignoreComments, bool ignorePis, bool prohibitDtd) : base(reader, checkCharacters, ignoreWhitespace, ignoreComments, ignorePis, prohibitDtd)
  575.         {
  576.             Debug.Assert(readerAsNSResolver != null);
  577.             this.readerAsNSResolver = readerAsNSResolver;
  578.         }
  579.         //
  580.         // IXmlNamespaceResolver
  581.         //
  582.         IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope(XmlNamespaceScope scope)
  583.         {
  584.             return readerAsNSResolver.GetNamespacesInScope(scope);
  585.         }
  586.        
  587.         string IXmlNamespaceResolver.LookupNamespace(string prefix)
  588.         {
  589.             return readerAsNSResolver.LookupNamespace(prefix);
  590.         }
  591.        
  592.         string IXmlNamespaceResolver.LookupPrefix(string namespaceName)
  593.         {
  594.             return readerAsNSResolver.LookupPrefix(namespaceName);
  595.         }
  596.     }
  597. }

Developer Fusion