Reader/Writer implementations changed to use static factories
diff --git a/src/ProtocolBuffers/Serialization/DictionaryReader.cs b/src/ProtocolBuffers/Serialization/DictionaryReader.cs
index f8ef1ed..d6e5c18 100644
--- a/src/ProtocolBuffers/Serialization/DictionaryReader.cs
+++ b/src/ProtocolBuffers/Serialization/DictionaryReader.cs
@@ -64,7 +64,7 @@
try
{
if (obj is IConvertible)
- value = (T)Convert.ChangeType(obj, typeof(T));
+ value = (T)Convert.ChangeType(obj, typeof(T), System.Globalization.CultureInfo.InvariantCulture);
else
value = (T)obj;
}
@@ -186,8 +186,17 @@
object[] array = null;
if (GetValue(ref array))
{
- foreach (T item in array)
- items.Add(item);
+ if (typeof(T) == typeof(ByteString))
+ {
+ ICollection<ByteString> output = (ICollection<ByteString>)items;
+ foreach (byte[] item in array)
+ output.Add(ByteString.CopyFrom(item));
+ }
+ else
+ {
+ foreach (T item in array)
+ items.Add(item);
+ }
return true;
}
return false;
diff --git a/src/ProtocolBuffers/Serialization/JsonFormatReader.cs b/src/ProtocolBuffers/Serialization/JsonFormatReader.cs
index e9df913..2808ff5 100644
--- a/src/ProtocolBuffers/Serialization/JsonFormatReader.cs
+++ b/src/ProtocolBuffers/Serialization/JsonFormatReader.cs
@@ -10,7 +10,7 @@
/// </summary>
public class JsonFormatReader : AbstractTextReader
{
- private readonly JsonTextCursor _input;
+ private readonly JsonCursor _input;
private readonly Stack<int> _stopChar;
enum ReaderState { Start, BeginValue, EndValue, BeginObject, BeginArray }
@@ -18,27 +18,43 @@
ReaderState _state;
/// <summary>
- /// Constructs a JsonFormatReader to parse Json into a message
+ /// Constructs a JsonFormatReader to parse Json into a message, this method does not use text encoding, all bytes MUST
+ /// represent ASCII character values.
/// </summary>
- public JsonFormatReader(string jsonText)
- {
- _input = new JsonTextCursor(jsonText.ToCharArray());
- _stopChar = new Stack<int>();
- _stopChar.Push(-1);
- _state = ReaderState.Start;
- }
+ public static JsonFormatReader CreateInstance(Stream stream) { return new JsonFormatReader(JsonCursor.CreateInstance(stream)); }
+ /// <summary>
+ /// Constructs a JsonFormatReader to parse Json into a message, this method does not use text encoding, all bytes MUST
+ /// represent ASCII character values.
+ /// </summary>
+ public static JsonFormatReader CreateInstance(byte[] bytes) { return new JsonFormatReader(JsonCursor.CreateInstance(bytes)); }
/// <summary>
/// Constructs a JsonFormatReader to parse Json into a message
/// </summary>
- public JsonFormatReader(TextReader input)
+ public static JsonFormatReader CreateInstance(string jsonText) { return new JsonFormatReader(JsonCursor.CreateInstance(jsonText)); }
+ /// <summary>
+ /// Constructs a JsonFormatReader to parse Json into a message
+ /// </summary>
+ public static JsonFormatReader CreateInstance(TextReader input) { return new JsonFormatReader(JsonCursor.CreateInstance(input)); }
+
+ /// <summary>
+ /// Constructs a JsonFormatReader to parse Json into a message
+ /// </summary>
+ internal JsonFormatReader(JsonCursor input)
{
- _input = new JsonTextCursor(input);
+ _input = input;
_stopChar = new Stack<int>();
_stopChar.Push(-1);
_state = ReaderState.Start;
}
/// <summary>
+ /// Constructs a JsonFormatReader to parse Json into a message
+ /// </summary>
+ protected JsonFormatReader(TextReader input)
+ : this(JsonCursor.CreateInstance(input))
+ { }
+
+ /// <summary>
/// Returns true if the reader is currently on an array element
/// </summary>
public bool IsArrayMessage { get { return _input.NextChar == '['; } }
@@ -115,18 +131,18 @@
protected override bool ReadAsText(ref string value, Type typeInfo)
{
object temp;
- JsonTextCursor.JsType type = _input.ReadVariant(out temp);
+ JsonCursor.JsType type = _input.ReadVariant(out temp);
_state = ReaderState.EndValue;
- _input.Assert(type != JsonTextCursor.JsType.Array && type != JsonTextCursor.JsType.Object, "Encountered {0} while expecting {1}", type, typeInfo);
- if (type == JsonTextCursor.JsType.Null)
+ _input.Assert(type != JsonCursor.JsType.Array && type != JsonCursor.JsType.Object, "Encountered {0} while expecting {1}", type, typeInfo);
+ if (type == JsonCursor.JsType.Null)
return false;
- if (type == JsonTextCursor.JsType.True) value = "1";
- else if (type == JsonTextCursor.JsType.False) value = "0";
+ if (type == JsonCursor.JsType.True) value = "1";
+ else if (type == JsonCursor.JsType.False) value = "0";
else value = temp as string;
//exponent representation of integer number:
- if (value != null && type == JsonTextCursor.JsType.Number &&
+ if (value != null && type == JsonCursor.JsType.Number &&
(typeInfo != typeof(double) && typeInfo != typeof(float)) &&
value.IndexOf("e", StringComparison.OrdinalIgnoreCase) > 0)
{
diff --git a/src/ProtocolBuffers/Serialization/JsonFormatWriter.cs b/src/ProtocolBuffers/Serialization/JsonFormatWriter.cs
index 0baf6ca..b205752 100644
--- a/src/ProtocolBuffers/Serialization/JsonFormatWriter.cs
+++ b/src/ProtocolBuffers/Serialization/JsonFormatWriter.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Text;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.Serialization
@@ -10,81 +11,178 @@
/// you may also use the XmlFormatWriter with an XmlWriter created by the
/// <see cref="System.Runtime.Serialization.Json.JsonReaderWriterFactory">JsonReaderWriterFactory</see>.
/// </summary>
- public class JsonFormatWriter : AbstractTextWriter
+ public abstract class JsonFormatWriter : AbstractTextWriter
{
- private readonly char[] _buffer;
- private readonly TextWriter _output;
- private readonly List<int> _counter;
- private bool _isArray;
- int _bufferPos;
- /// <summary>
- /// Constructs a JsonFormatWriter to output to a new instance of a StringWriter, use
- /// the ToString() member to extract the final Json on completion.
- /// </summary>
- public JsonFormatWriter() : this(new StringWriter()) { }
- /// <summary>
- /// Constructs a JsonFormatWriter to output to the given text writer
- /// </summary>
- public JsonFormatWriter(TextWriter output)
+ #region buffering implementations
+ private class JsonTextWriter : JsonFormatWriter
{
- _buffer = new char[4096];
- _bufferPos = 0;
- _output = output;
- _counter = new List<int>();
- _counter.Add(0);
- }
+ private readonly char[] _buffer;
+ private TextWriter _output;
+ int _bufferPos;
-
- private void WriteToOutput(string format, params object[] args)
- { WriteToOutput(String.Format(format, args)); }
-
- private void WriteToOutput(string text)
- { WriteToOutput(text.ToCharArray(), 0, text.Length); }
-
- private void WriteToOutput(char[] chars, int offset, int len)
- {
- if (_bufferPos + len >= _buffer.Length)
- Flush();
- if (len < _buffer.Length)
+ public JsonTextWriter(TextWriter output)
{
- if (len <= 12)
+ _buffer = new char[4096];
+ _bufferPos = 0;
+ _output = output;
+ _counter.Add(0);
+ }
+
+ /// <summary>
+ /// Returns the output of TextWriter.ToString() where TextWriter is the ctor argument.
+ /// </summary>
+ public override string ToString()
+ {
+ Flush();
+
+ if (_output != null)
+ return _output.ToString();
+
+ return new String(_buffer, 0, _bufferPos);
+ }
+
+ protected override void WriteToOutput(char[] chars, int offset, int len)
+ {
+ if (_bufferPos + len >= _buffer.Length)
{
- int stop = offset + len;
- for (int i = offset; i < stop; i++)
- _buffer[_bufferPos++] = chars[i];
+ if (_output == null)
+ _output = new StringWriter(new System.Text.StringBuilder(_buffer.Length * 2 + len));
+ Flush();
+ }
+
+ if (len < _buffer.Length)
+ {
+ if (len <= 12)
+ {
+ int stop = offset + len;
+ for (int i = offset; i < stop; i++)
+ _buffer[_bufferPos++] = chars[i];
+ }
+ else
+ {
+ Buffer.BlockCopy(chars, offset << 1, _buffer, _bufferPos << 1, len << 1);
+ _bufferPos += len;
+ }
+ }
+ else
+ _output.Write(chars, offset, len);
+ }
+
+ protected override void WriteToOutput(char ch)
+ {
+ if (_bufferPos >= _buffer.Length)
+ Flush();
+ _buffer[_bufferPos++] = ch;
+ }
+
+ public override void Flush()
+ {
+ if (_bufferPos > 0 && _output != null)
+ {
+ _output.Write(_buffer, 0, _bufferPos);
+ _bufferPos = 0;
+ }
+ base.Flush();
+ }
+ }
+ private class JsonStreamWriter : JsonFormatWriter
+ {
+#if SILVERLIGHT2 || COMPACT_FRAMEWORK_35
+ static readonly Encoding Encoding = Encoding.UTF8;
+#else
+ static readonly Encoding Encoding = Encoding.ASCII;
+#endif
+ private readonly byte[] _buffer;
+ private Stream _output;
+ int _bufferPos;
+
+ public JsonStreamWriter(Stream output)
+ {
+ _buffer = new byte[8192];
+ _bufferPos = 0;
+ _output = output;
+ _counter.Add(0);
+ }
+
+ protected override void WriteToOutput(char[] chars, int offset, int len)
+ {
+ if (_bufferPos + len >= _buffer.Length)
+ Flush();
+
+ if (len < _buffer.Length)
+ {
+ if (len <= 12)
+ {
+ int stop = offset + len;
+ for (int i = offset; i < stop; i++)
+ _buffer[_bufferPos++] = (byte)chars[i];
+ }
+ else
+ {
+ _bufferPos += Encoding.GetBytes(chars, offset, len, _buffer, _bufferPos);
+ }
}
else
{
- Buffer.BlockCopy(chars, offset << 1, _buffer, _bufferPos << 1, len << 1);
- _bufferPos += len;
+ byte[] temp = Encoding.GetBytes(chars, offset, len);
+ _output.Write(temp, 0, temp.Length);
}
}
- else
- _output.Write(chars, offset, len);
- }
- private void WriteToOutput(char ch)
- {
- if (_bufferPos >= _buffer.Length)
- Flush();
- _buffer[_bufferPos++] = ch;
- }
-
- public override void Flush()
- {
- if (_bufferPos > 0)
+ protected override void WriteToOutput(char ch)
{
- _output.Write(_buffer, 0, _bufferPos);
- _bufferPos = 0;
+ if (_bufferPos >= _buffer.Length)
+ Flush();
+ _buffer[_bufferPos++] = (byte)ch;
}
- base.Flush();
+
+ public override void Flush()
+ {
+ if (_bufferPos > 0 && _output != null)
+ {
+ _output.Write(_buffer, 0, _bufferPos);
+ _bufferPos = 0;
+ }
+ base.Flush();
+ }
+ }
+ #endregion
+
+ private readonly List<int> _counter;
+ private bool _isArray;
+ /// <summary>
+ /// Constructs a JsonFormatWriter, use the ToString() member to extract the final Json on completion.
+ /// </summary>
+ protected JsonFormatWriter()
+ {
+ _counter = new List<int>();
}
/// <summary>
- /// Returns the output of TextWriter.ToString() where TextWriter is the ctor argument.
+ /// Constructs a JsonFormatWriter, use ToString() to extract the final output
/// </summary>
- public override string ToString()
- { Flush(); return _output.ToString(); }
+ public static JsonFormatWriter CreateInstance() { return new JsonTextWriter(null); }
+
+ /// <summary>
+ /// Constructs a JsonFormatWriter to output to the given text writer
+ /// </summary>
+ public static JsonFormatWriter CreateInstance(TextWriter output) { return new JsonTextWriter(output); }
+
+ /// <summary>
+ /// Constructs a JsonFormatWriter to output to the given stream
+ /// </summary>
+ public static JsonFormatWriter CreateInstance(Stream output) { return new JsonStreamWriter(output); }
+
+ /// <summary> Write to the output stream </summary>
+ protected void WriteToOutput(string format, params object[] args)
+ { WriteToOutput(String.Format(format, args)); }
+ /// <summary> Write to the output stream </summary>
+ protected void WriteToOutput(string text)
+ { WriteToOutput(text.ToCharArray(), 0, text.Length); }
+ /// <summary> Write to the output stream </summary>
+ protected abstract void WriteToOutput(char ch);
+ /// <summary> Write to the output stream </summary>
+ protected abstract void WriteToOutput(char[] chars, int offset, int len);
/// <summary> Sets the output formatting to use Environment.NewLine with 4-character indentions </summary>
public JsonFormatWriter Formatted()
diff --git a/src/ProtocolBuffers/Serialization/JsonTextCursor.cs b/src/ProtocolBuffers/Serialization/JsonTextCursor.cs
index 6a8652c..a0b468f 100644
--- a/src/ProtocolBuffers/Serialization/JsonTextCursor.cs
+++ b/src/ProtocolBuffers/Serialization/JsonTextCursor.cs
@@ -9,52 +9,115 @@
/// <summary>
/// JSon Tokenizer used by JsonFormatReader
/// </summary>
- class JsonTextCursor
+ abstract class JsonCursor
{
public enum JsType { String, Number, Object, Array, True, False, Null }
- private readonly char[] _buffer;
- private int _bufferPos;
- private readonly TextReader _input;
+ #region Buffering implementations
+ class JsonStreamCursor : JsonCursor
+ {
+ private readonly byte[] _buffer;
+ private int _bufferPos;
+ private readonly Stream _input;
+
+ public JsonStreamCursor(Stream input)
+ {
+ _input = input;
+ _next = _input.ReadByte();
+ }
+ public JsonStreamCursor(byte[] input)
+ {
+ _input = null;
+ _buffer = input;
+ _next = _buffer[_bufferPos];
+ }
+
+ protected override int Peek()
+ {
+ if (_input != null)
+ return _next;
+ else if (_bufferPos < _buffer.Length)
+ return _buffer[_bufferPos];
+ else
+ return -1;
+ }
+
+ protected override int Read()
+ {
+ if (_input != null)
+ {
+ int result = _next;
+ _next = _input.ReadByte();
+ return result;
+ }
+ else if (_bufferPos < _buffer.Length)
+ return _buffer[_bufferPos++];
+ else
+ return -1;
+ }
+ }
+
+ class JsonTextCursor : JsonCursor
+ {
+ private readonly char[] _buffer;
+ private int _bufferPos;
+ private readonly TextReader _input;
+
+ public JsonTextCursor(char[] input)
+ {
+ _input = null;
+ _buffer = input;
+ _bufferPos = 0;
+ _next = Peek();
+ }
+
+ public JsonTextCursor(TextReader input)
+ {
+ _input = input;
+ _next = Peek();
+ }
+
+ protected override int Peek()
+ {
+ if (_input != null)
+ return _input.Peek();
+ else if (_bufferPos < _buffer.Length)
+ return _buffer[_bufferPos];
+ else
+ return -1;
+ }
+
+ protected override int Read()
+ {
+ if (_input != null)
+ return _input.Read();
+ else if (_bufferPos < _buffer.Length)
+ return _buffer[_bufferPos++];
+ else
+ return -1;
+ }
+ }
+ #endregion
+
+ protected int _next;
private int _lineNo, _linePos;
- public JsonTextCursor(char[] input)
+ public static JsonCursor CreateInstance(byte[] input) { return new JsonStreamCursor(input); }
+ public static JsonCursor CreateInstance(Stream input) { return new JsonStreamCursor(input); }
+ public static JsonCursor CreateInstance(string input) { return new JsonTextCursor(input.ToCharArray()); }
+ public static JsonCursor CreateInstance(TextReader input) { return new JsonTextCursor(input); }
+
+ protected JsonCursor()
{
- _input = null;
- _buffer = input;
- _bufferPos = 0;
- _next = Peek();
_lineNo = 1;
+ _linePos = 0;
}
+
+ /// <summary>Returns the next character without actually 'reading' it</summary>
+ protected abstract int Peek();
+ /// <summary>Reads the next character in the input</summary>
+ protected abstract int Read();
- public JsonTextCursor(TextReader input)
- {
- _input = input;
- _next = Peek();
- _lineNo = 1;
- }
-
- private int Peek()
- {
- if (_input != null)
- return _input.Peek();
- else if (_bufferPos < _buffer.Length)
- return _buffer[_bufferPos];
- else
- return -1;
- }
-
- private int Read()
- {
- if (_input != null)
- return _input.Read();
- else if (_bufferPos < _buffer.Length)
- return _buffer[_bufferPos++];
- else
- return -1;
- }
-
- int _next;
public Char NextChar { get { SkipWhitespace(); return (char)_next; } }
#region Assert(...)
@@ -62,8 +125,8 @@
private string CharDisplay(int ch)
{
return ch == -1 ? "EOF" :
- (ch > 32 && ch < 127) ? String.Format("'{0}'", (char)ch) :
- String.Format("'\\u{0:x4}'", ch);
+ (ch > 32 && ch < 127) ? String.Format("'{0}'", (char)ch) :
+ String.Format("'\\u{0:x4}'", ch);
}
[System.Diagnostics.DebuggerNonUserCode]
private void Assert(bool cond, char expected)
diff --git a/src/ProtocolBuffers/Serialization/XmlFormatReader.cs b/src/ProtocolBuffers/Serialization/XmlFormatReader.cs
index 671490e..241c554 100644
--- a/src/ProtocolBuffers/Serialization/XmlFormatReader.cs
+++ b/src/ProtocolBuffers/Serialization/XmlFormatReader.cs
@@ -25,33 +25,41 @@
/// <summary>
/// Constructs the XmlFormatReader using the stream provided as the xml
/// </summary>
- public XmlFormatReader(Stream input) : this(XmlReader.Create(input, DefaultSettings)) { }
+ 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 XmlFormatReader(String input) : this(XmlReader.Create(new StringReader(input))) { }
+ 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 XmlFormatReader(TextReader input) : this(XmlReader.Create(input)) { }
+ public static XmlFormatReader CreateInstance(TextReader input) { return new XmlFormatReader(XmlReader.Create(input, DefaultSettings)); }
/// <summary>
/// Constructs the XmlFormatReader with the XmlReader
/// </summary>
- public XmlFormatReader(XmlReader input) : this(input, XmlReaderOptions.None) { }
+ public static XmlFormatReader CreateInstance(XmlReader input) { return new XmlFormatReader(input); }
/// <summary>
/// Constructs the XmlFormatReader with the XmlReader and options
/// </summary>
- public XmlFormatReader(XmlReader input, XmlReaderOptions options)
+ protected XmlFormatReader(XmlReader input)
{
_input = input;
_rootElementName = DefaultRootElementName;
- Options = options;
+ Options = XmlReaderOptions.None;
}
/// <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>()
@@ -64,7 +72,7 @@
private XmlFormatReader CloneWith(XmlReader rdr)
{
- return new XmlFormatReader(rdr, Options);
+ return new XmlFormatReader(rdr).SetOptions(Options);
}
private void NextElement()
{
diff --git a/src/ProtocolBuffers/Serialization/XmlFormatWriter.cs b/src/ProtocolBuffers/Serialization/XmlFormatWriter.cs
index b5dbf5f..2bb4f15 100644
--- a/src/ProtocolBuffers/Serialization/XmlFormatWriter.cs
+++ b/src/ProtocolBuffers/Serialization/XmlFormatWriter.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
+using System.Text;
using System.Xml;
using Google.ProtocolBuffers.Descriptors;
@@ -17,23 +18,29 @@
private readonly XmlWriter _output;
private string _rootElementName;
- static XmlWriterSettings DefaultSettings
+ static XmlWriterSettings DefaultSettings(Encoding encoding)
{
- get { return new XmlWriterSettings() {CheckCharacters = false, NewLineHandling = NewLineHandling.Entitize}; }
+ return new XmlWriterSettings() { CheckCharacters = false, NewLineHandling = NewLineHandling.Entitize, Encoding = encoding };
}
/// <summary>
/// Constructs the XmlFormatWriter to write to the given TextWriter
/// </summary>
- public XmlFormatWriter(TextWriter output) : this(XmlWriter.Create(output, DefaultSettings)) { }
+ public static XmlFormatWriter CreateInstance(TextWriter output) { return new XmlFormatWriter(XmlWriter.Create(output, DefaultSettings(output.Encoding))); }
/// <summary>
/// Constructs the XmlFormatWriter to write to the given stream
/// </summary>
- public XmlFormatWriter(Stream output) : this(XmlWriter.Create(output, DefaultSettings)) { }
+ public static XmlFormatWriter CreateInstance(Stream output) { return new XmlFormatWriter(XmlWriter.Create(output, DefaultSettings(Encoding.UTF8))); }
+ /// <summary>
+ /// Constructs the XmlFormatWriter to write to the given stream
+ /// </summary>
+ public static XmlFormatWriter CreateInstance(Stream output, Encoding encoding) { return new XmlFormatWriter(XmlWriter.Create(output, DefaultSettings(encoding))); }
/// <summary>
/// Constructs the XmlFormatWriter to write to the given XmlWriter
/// </summary>
- public XmlFormatWriter(XmlWriter output)
+ public static XmlFormatWriter CreateInstance(XmlWriter output) { return new XmlFormatWriter(output); }
+
+ protected XmlFormatWriter(XmlWriter output)
{
_output = output;
_rootElementName = DefaultRootElementName;
@@ -61,6 +68,10 @@
/// Gets or sets the options to use while generating the XML
/// </summary>
public XmlWriterOptions Options { get; set; }
+ /// <summary>
+ /// Sets the options to use while generating the XML
+ /// </summary>
+ public XmlFormatWriter SetOptions(XmlWriterOptions options) { Options = options; return this; }
private bool TestOption(XmlWriterOptions option) { return (Options & option) != 0; }