aboutsummaryrefslogtreecommitdiff
path: root/src/ProtocolBuffers.Serialization/XmlFormatReader.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ProtocolBuffers.Serialization/XmlFormatReader.cs')
-rw-r--r--src/ProtocolBuffers.Serialization/XmlFormatReader.cs142
1 files changed, 69 insertions, 73 deletions
diff --git a/src/ProtocolBuffers.Serialization/XmlFormatReader.cs b/src/ProtocolBuffers.Serialization/XmlFormatReader.cs
index 0d3bca67..98b69776 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 @@ namespace Google.ProtocolBuffers.Serialization
{
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 @@ namespace Google.ProtocolBuffers.Serialization
{
_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 @@ namespace Google.ProtocolBuffers.Serialization
}
}
- 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 @@ namespace Google.ProtocolBuffers.Serialization
/// <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 @@ namespace Google.ProtocolBuffers.Serialization
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 @@ namespace Google.ProtocolBuffers.Serialization
/// </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 @@ namespace Google.ProtocolBuffers.Serialization
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 @@ namespace Google.ProtocolBuffers.Serialization
{
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