| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 | using System;using System.Collections.Generic;using System.IO;using System.Xml;namespace Google.ProtocolBuffers.Serialization{    /// <summary>    /// Parses a proto buffer from an XML document or fragment.  .NET 3.5 users may also    /// use this class to process Json by setting the options to support Json and providing    /// an XmlReader obtained from <see cref="System.Runtime.Serialization.Json.JsonReaderWriterFactory"/>.    /// </summary>    public class XmlFormatReader : AbstractTextReader    {        public const string DefaultRootElementName = XmlFormatWriter.DefaultRootElementName;        private readonly XmlReader _input;        private string _rootElementName;        private static XmlReaderSettings DefaultSettings        {            get            {                return new XmlReaderSettings()                           {CheckCharacters = false, IgnoreComments = true, IgnoreProcessingInstructions = true};            }        }        /// <summary>        /// Constructs the XmlFormatReader using the stream provided as the xml        /// </summary>        public static XmlFormatReader CreateInstance(byte[] input)        {            return new XmlFormatReader(XmlReader.Create(new MemoryStream(input, false), DefaultSettings));        }        /// <summary>        /// Constructs the XmlFormatReader using the stream provided as the xml        /// </summary>        public static XmlFormatReader CreateInstance(Stream input)        {            return new XmlFormatReader(XmlReader.Create(input, DefaultSettings));        }        /// <summary>        /// Constructs the XmlFormatReader using the string provided as the xml to be read        /// </summary>        public static XmlFormatReader CreateInstance(String input)        {            return new XmlFormatReader(XmlReader.Create(new StringReader(input), DefaultSettings));        }        /// <summary>        /// Constructs the XmlFormatReader using the xml in the TextReader        /// </summary>        public static XmlFormatReader CreateInstance(TextReader input)        {            return new XmlFormatReader(XmlReader.Create(input, DefaultSettings));        }        /// <summary>        /// Constructs the XmlFormatReader with the XmlReader        /// </summary>        public static XmlFormatReader CreateInstance(XmlReader input)        {            return new XmlFormatReader(input);        }        /// <summary>        /// Constructs the XmlFormatReader with the XmlReader and options        /// </summary>        protected XmlFormatReader(XmlReader input)        {            _input = input;            _rootElementName = DefaultRootElementName;            Options = XmlReaderOptions.None;        }        /// <summary>        /// Constructs the XmlFormatReader with the XmlReader and options        /// </summary>        protected XmlFormatReader(XmlFormatReader copyFrom, XmlReader input)            : base(copyFrom)        {            _input = input;            _rootElementName = copyFrom._rootElementName;            Options = copyFrom.Options;        }        /// <summary>        /// Gets or sets the options to use when reading the xml        /// </summary>        public XmlReaderOptions Options { get; set; }        /// <summary>        /// Sets the options to use while generating the XML        /// </summary>        public XmlFormatReader SetOptions(XmlReaderOptions options)        {            Options = options;            return this;        }        /// <summary>        /// Gets or sets the default element name to use when using the Merge<TBuilder>()        /// </summary>        public string RootElementName        {            get { return _rootElementName; }            set            {                ThrowHelper.ThrowIfNull(value, "RootElementName");                _rootElementName = value;            }        }        private XmlFormatReader CloneWith(XmlReader rdr)        {            XmlFormatReader copy = new XmlFormatReader(this, rdr);            return copy;        }        private void NextElement()        {            while (!_input.IsStartElement() && _input.Read())            {                continue;            }        }        private static void Assert(bool cond)        {            if (!cond)            {                throw new FormatException();            }        }        /// <summary>        /// Reads the root-message preamble specific to this formatter        /// </summary>        public override AbstractReader ReadStartMessage()        {            return ReadStartMessage(_rootElementName);        }        public AbstractReader ReadStartMessage(string element)        {            string field;            Assert(PeekNext(out field) && field == element);            XmlReader child = _input.ReadSubtree();            while (!child.IsStartElement() && child.Read())            {                continue;            }            child.Read();            return CloneWith(child);        }        /// <summary>        /// Reads the root-message close specific to this formatter, MUST be called        /// on the reader obtained from ReadStartMessage(string element).        /// </summary>        public override void ReadEndMessage()        {            Assert(0 == _input.Depth);            if(_input.NodeType == XmlNodeType.EndElement)            {                _input.Read();            }        }        /// <summary>        /// Merge the provided builder as an element named <see cref="RootElementName"/> in the current context        /// </summary>        public override TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)        {            return Merge(_rootElementName, builder, registry);        }        /// <summary>        /// Merge the provided builder as an element of the current context        /// </summary>        public TBuilder Merge<TBuilder>(string element, TBuilder builder) where TBuilder : IBuilderLite        {            return Merge(element, builder, ExtensionRegistry.Empty);        }        /// <summary>        /// Merge the provided builder as an element of the current context        /// </summary>        public TBuilder Merge<TBuilder>(string element, TBuilder builder, ExtensionRegistry registry)            where TBuilder : IBuilderLite        {            string field;            Assert(PeekNext(out field) && field == element);            ReadMessage(builder, registry);            return builder;        }        /// <summary>        /// Peeks at the next field in the input stream and returns what information is available.        /// </summary>        /// <remarks>        /// This may be called multiple times without actually reading the field.  Only after the field        /// is either read, or skipped, should PeekNext return a different value.        /// </remarks>        protected override bool PeekNext(out string field)        {            NextElement();            if (_input.IsStartElement())            {                field = _input.LocalName;                return true;            }            field = null;            return false;        }        /// <summary>        /// Causes the reader to skip past this field        /// </summary>        protected override void Skip()        {            if (_input.IsStartElement())            {                if (!_input.IsEmptyElement)                {                    int depth = _input.Depth;                    while (_input.Depth >= depth && _input.NodeType != XmlNodeType.EndElement)                    {                        Assert(_input.Read());                    }                }                _input.Read();            }        }        /// <summary>        /// returns true if it was able to read a single value into the value reference.  The value        /// stored may be of type System.String, System.Int32, or an IEnumLite from the IEnumLiteMap.        /// </summary>        protected override bool ReadEnum(ref object value)        {            int number;            string temp;            if (null != (temp = _input.GetAttribute("value")) && int.TryParse(temp, out number))            {                Skip();                value = number;                return true;            }            return base.ReadEnum(ref value);        }        /// <summary>        /// Returns true if it was able to read a String from the input        /// </summary>        protected override bool ReadAsText(ref string value, Type type)        {            Assert(_input.NodeType == XmlNodeType.Element);            value = _input.ReadElementContentAsString();            return true;        }        /// <summary>        /// Merges the input stream into the provided IBuilderLite         /// </summary>        protected override bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry)        {            Assert(_input.IsStartElement());            if (!_input.IsEmptyElement)            {                int depth = _input.Depth;                XmlReader child = _input.ReadSubtree();                while (!child.IsStartElement() && child.Read())                {                    continue;                }                child.Read();                builder.WeakMergeFrom(CloneWith(child), registry);                Assert(depth == _input.Depth && _input.NodeType == XmlNodeType.EndElement);            }            _input.Read();            return true;        }        private IEnumerable<string> NonNestedArrayItems(string field)        {            return base.ForeachArrayItem(field);        }        /// <summary>        /// Cursors through the array elements and stops at the end of the array        /// </summary>        protected override IEnumerable<string> ForeachArrayItem(string field)        {            bool isNested = (Options & XmlReaderOptions.ReadNestedArrays) != 0;            if (!isNested)            {                foreach (string item in NonNestedArrayItems(field))                {                    yield return item;                }                yield break;            }            if (!_input.IsEmptyElement)            {                int depth = _input.Depth;                XmlReader child = _input.ReadSubtree();                while (!child.IsStartElement() && child.Read())                {                    continue;                }                child.Read();                foreach (string item in CloneWith(child).NonNestedArrayItems("item"))                {                    yield return item;                }                Assert(depth == _input.Depth && _input.NodeType == XmlNodeType.EndElement);            }            _input.Read();            yield break;        }    }}
 |