Completed work and testing for manually reading/writing start/end message
diff --git a/src/ProtocolBuffers.Serialization/XmlFormatReader.cs b/src/ProtocolBuffers.Serialization/XmlFormatReader.cs
index 0d3bca6..98b6977 100644
--- a/src/ProtocolBuffers.Serialization/XmlFormatReader.cs
+++ b/src/ProtocolBuffers.Serialization/XmlFormatReader.cs
@@ -1,4 +1,4 @@
-using System;

+using System;

 using System.Collections.Generic;

 using System.IO;

 using System.Xml;

@@ -14,8 +14,23 @@
     {

         public const string DefaultRootElementName = XmlFormatWriter.DefaultRootElementName;

         private readonly XmlReader _input;

+        private readonly Stack<ElementStack> _elements;

         private string _rootElementName;

 

+        private struct ElementStack

+        {

+            public readonly string LocalName;

+            public readonly int Depth;

+            public readonly bool IsEmpty;

+

+            public ElementStack(string localName, int depth, bool isEmpty) : this()

+            {

+                LocalName = localName;

+                IsEmpty = isEmpty;

+                Depth = depth;

+            }

+        }

+

         private static XmlReaderSettings DefaultSettings

         {

             get

@@ -72,21 +87,11 @@
         {

             _input = input;

             _rootElementName = DefaultRootElementName;

+            _elements = new Stack<ElementStack>();

             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; }

@@ -113,20 +118,6 @@
             }

         }

 

-        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)

@@ -138,36 +129,49 @@
         /// <summary>

         /// Reads the root-message preamble specific to this formatter

         /// </summary>

-        public override AbstractReader ReadStartMessage()

+        public override void ReadMessageStart()

         {

-            return ReadStartMessage(_rootElementName);

+            ReadMessageStart(_rootElementName);

         }

 

-        public AbstractReader ReadStartMessage(string element)

+        /// <summary>

+        /// Reads the root-message preamble specific to this formatter

+        /// </summary>

+        public void ReadMessageStart(string element)

         {

-            string field;

-            Assert(PeekNext(out field) && field == element);

-

-            XmlReader child = _input.ReadSubtree();

-            while (!child.IsStartElement() && child.Read())

+            while (!_input.IsStartElement() && _input.Read())

             {

                 continue;

             }

-            child.Read();

-            return CloneWith(child);

+            Assert(_input.IsStartElement() && _input.LocalName == element);

+            _elements.Push(new ElementStack(element, _input.Depth, _input.IsEmptyElement));

+            _input.Read();

         }

 

         /// <summary>

         /// Reads the root-message close specific to this formatter, MUST be called

-        /// on the reader obtained from ReadStartMessage(string element).

+        /// on the reader obtained from ReadMessageStart(string element).

         /// </summary>

-        public override void ReadEndMessage()

+        public override void ReadMessageEnd()

         {

-            Assert(0 == _input.Depth);

-            if(_input.NodeType == XmlNodeType.EndElement)

+            Assert(_elements.Count > 0);

+

+            ElementStack stop = _elements.Peek();

+            while (_input.NodeType != XmlNodeType.EndElement && _input.NodeType != XmlNodeType.Element

+                   && _input.Depth > stop.Depth && _input.Read())

             {

+                continue;

+            }

+

+            if (!stop.IsEmpty)

+            {

+                Assert(_input.NodeType == XmlNodeType.EndElement

+                       && _input.LocalName == stop.LocalName

+                       && _input.Depth == stop.Depth);

+

                 _input.Read();

             }

+            _elements.Pop();

         }

 

         /// <summary>

@@ -192,9 +196,9 @@
         public TBuilder Merge<TBuilder>(string element, TBuilder builder, ExtensionRegistry registry)

             where TBuilder : IBuilderLite

         {

-            string field;

-            Assert(PeekNext(out field) && field == element);

-            ReadMessage(builder, registry);

+            ReadMessageStart(element);

+            builder.WeakMergeFrom(this, registry);

+            ReadMessageEnd();

             return builder;

         }

 

@@ -207,7 +211,21 @@
         /// </remarks>

         protected override bool PeekNext(out string field)

         {

-            NextElement();

+            ElementStack stopNode;

+            if (_elements.Count == 0)

+            {

+                stopNode = new ElementStack(null, _input.Depth - 1, false);

+            }

+            else

+            {

+                stopNode = _elements.Peek();

+            }

+

+            while (!_input.IsStartElement() && _input.Depth > stopNode.Depth && _input.Read())

+            {

+                continue;

+            }

+

             if (_input.IsStartElement())

             {

                 field = _input.LocalName;

@@ -270,20 +288,9 @@
         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();

+            ReadMessageStart(_input.LocalName);

+            builder.WeakMergeFrom(this, registry);

+            ReadMessageEnd();

             return true;

         }

 

@@ -305,27 +312,16 @@
                 {

                     yield return item;

                 }

-                yield break;

             }

-            if (!_input.IsEmptyElement)

+            else

             {

-                int depth = _input.Depth;

-                XmlReader child = _input.ReadSubtree();

-

-                while (!child.IsStartElement() && child.Read())

-                {

-                    continue;

-                }

-                child.Read();

-

-                foreach (string item in CloneWith(child).NonNestedArrayItems("item"))

+                ReadMessageStart(field);

+                foreach (string item in NonNestedArrayItems("item"))

                 {

                     yield return item;

                 }

-                Assert(depth == _input.Depth && _input.NodeType == XmlNodeType.EndElement);

+                ReadMessageEnd();

             }

-            _input.Read();

-            yield break;

         }

     }

 }
\ No newline at end of file