Bläddra i källkod

Reader/Writer implementations changed to use static factories

csharptest 14 år sedan
förälder
incheckning
7fc785c1d4

+ 29 - 20
src/ProtoBench/Program.cs

@@ -131,30 +131,40 @@ namespace Google.ProtocolBuffers.ProtoBench
                 MemoryStream inputStream = new MemoryStream(inputData);
                 MemoryStream inputStream = new MemoryStream(inputData);
                 ByteString inputString = ByteString.CopyFrom(inputData);
                 ByteString inputString = ByteString.CopyFrom(inputData);
                 IMessage sampleMessage = defaultMessage.WeakCreateBuilderForType().WeakMergeFrom(inputString, registry).WeakBuild();
                 IMessage sampleMessage = defaultMessage.WeakCreateBuilderForType().WeakMergeFrom(inputString, registry).WeakBuild();
-                
-                StringWriter temp = new StringWriter();
-                new XmlFormatWriter(temp).WriteMessage(sampleMessage);
-                string xmlMessageText = temp.ToString();
-                temp = new StringWriter();
-                new JsonFormatWriter(temp).WriteMessage(sampleMessage);
-                string jsonMessageText = temp.ToString();
-                byte[] jsonBytes /*no pun intended*/ = Encoding.UTF8.GetBytes(jsonMessageText);
 
 
+                byte[] jsonBytes, xmlBytes;/*no pun intended, well... maybe for xml*/
+                using (MemoryStream temp = new MemoryStream())
+                {
+                    XmlFormatWriter.CreateInstance(temp).WriteMessage(sampleMessage);
+                    xmlBytes = temp.ToArray();
+                }
+                using (MemoryStream temp = new MemoryStream())
+                {
+                    JsonFormatWriter.CreateInstance(temp).WriteMessage(sampleMessage);
+                    jsonBytes = temp.ToArray();
+                }
                 IDictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
                 IDictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
                 new DictionaryWriter(dictionary).WriteMessage(sampleMessage);
                 new DictionaryWriter(dictionary).WriteMessage(sampleMessage);
 
 
-
                 //Serializers
                 //Serializers
                 if(!FastTest) RunBenchmark("Serialize to byte string", inputData.Length, () => sampleMessage.ToByteString());
                 if(!FastTest) RunBenchmark("Serialize to byte string", inputData.Length, () => sampleMessage.ToByteString());
                 RunBenchmark("Serialize to byte array", inputData.Length, () => sampleMessage.ToByteArray());
                 RunBenchmark("Serialize to byte array", inputData.Length, () => sampleMessage.ToByteArray());
                 if (!FastTest) RunBenchmark("Serialize to memory stream", inputData.Length,
                 if (!FastTest) RunBenchmark("Serialize to memory stream", inputData.Length,
                           () => sampleMessage.WriteTo(new MemoryStream()));
                           () => sampleMessage.WriteTo(new MemoryStream()));
 
 
-                RunBenchmark("Serialize to xml", xmlMessageText.Length, () => new XmlFormatWriter(new StringWriter()).WriteMessage(sampleMessage));
-                RunBenchmark("Serialize to json", jsonMessageText.Length, () => new JsonFormatWriter(new StringWriter()).WriteMessage(sampleMessage));
-                RunBenchmark("Serialize to json via xml", jsonMessageText.Length,
-                    () => new XmlFormatWriter(JsonReaderWriterFactory.CreateJsonWriter(new MemoryStream(), Encoding.UTF8)) 
-                    { Options = XmlWriterOptions.OutputJsonTypes }.WriteMessage(sampleMessage)
+                RunBenchmark("Serialize to xml", xmlBytes.Length, () =>
+                {
+                    XmlFormatWriter.CreateInstance(new MemoryStream(), Encoding.UTF8).WriteMessage(sampleMessage);
+                } );
+                RunBenchmark("Serialize to json", jsonBytes.Length, () => 
+                {
+                    JsonFormatWriter.CreateInstance(new MemoryStream()).WriteMessage(sampleMessage); 
+                });
+                RunBenchmark("Serialize to json via xml", jsonBytes.Length,
+                    () =>
+                        XmlFormatWriter.CreateInstance(JsonReaderWriterFactory.CreateJsonWriter(new MemoryStream(), Encoding.UTF8))
+                            .SetOptions(XmlWriterOptions.OutputJsonTypes)
+                            .WriteMessage(sampleMessage)
                 );
                 );
 
 
                 RunBenchmark("Serialize to dictionary", sampleMessage.SerializedSize, () => new DictionaryWriter().WriteMessage(sampleMessage));
                 RunBenchmark("Serialize to dictionary", sampleMessage.SerializedSize, () => new DictionaryWriter().WriteMessage(sampleMessage));
@@ -179,12 +189,11 @@ namespace Google.ProtocolBuffers.ProtoBench
                           .WeakBuild();
                           .WeakBuild();
                   });
                   });
 
 
-                RunBenchmark("Deserialize from xml", xmlMessageText.Length, () => new XmlFormatReader(xmlMessageText).Merge(defaultMessage.WeakCreateBuilderForType()).WeakBuild());
-                RunBenchmark("Deserialize from json", jsonMessageText.Length, () => new JsonFormatReader(jsonMessageText).Merge(defaultMessage.WeakCreateBuilderForType()).WeakBuild());
-                RunBenchmark("Deserialize from json via xml", jsonMessageText.Length,
-                    () => new XmlFormatReader(JsonReaderWriterFactory.CreateJsonReader(jsonBytes, System.Xml.XmlDictionaryReaderQuotas.Max)) 
-                    { Options = XmlReaderOptions.ReadNestedArrays }
-                    .Merge(defaultMessage.WeakCreateBuilderForType()).WeakBuild());
+                RunBenchmark("Deserialize from xml", xmlBytes.Length, () => XmlFormatReader.CreateInstance(xmlBytes).Merge(defaultMessage.WeakCreateBuilderForType()).WeakBuild());
+                RunBenchmark("Deserialize from json", jsonBytes.Length, () => JsonFormatReader.CreateInstance(jsonBytes).Merge(defaultMessage.WeakCreateBuilderForType()).WeakBuild());
+                RunBenchmark("Deserialize from json via xml", jsonBytes.Length,
+                    () => XmlFormatReader.CreateInstance(JsonReaderWriterFactory.CreateJsonReader(jsonBytes, System.Xml.XmlDictionaryReaderQuotas.Max))
+                        .SetOptions(XmlReaderOptions.ReadNestedArrays).Merge(defaultMessage.WeakCreateBuilderForType()).WeakBuild());
 
 
                 RunBenchmark("Deserialize from dictionary", sampleMessage.SerializedSize, () => new DictionaryReader(dictionary).Merge(defaultMessage.WeakCreateBuilderForType()).WeakBuild());
                 RunBenchmark("Deserialize from dictionary", sampleMessage.SerializedSize, () => new DictionaryReader(dictionary).Merge(defaultMessage.WeakCreateBuilderForType()).WeakBuild());
 
 

+ 9 - 15
src/ProtoBench/ProtoBench.csproj

@@ -56,15 +56,9 @@
   <ItemGroup>
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System" />
     <Reference Include="System.Data" />
     <Reference Include="System.Data" />
-    <Reference Include="System.Runtime.Serialization, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
-      <RequiredTargetFramework>3.0</RequiredTargetFramework>
-    </Reference>
-    <Reference Include="System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
-      <RequiredTargetFramework>3.0</RequiredTargetFramework>
-    </Reference>
-    <Reference Include="System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
-      <RequiredTargetFramework>3.5</RequiredTargetFramework>
-    </Reference>
+    <Reference Include="System.Runtime.Serialization" />
+    <Reference Include="System.ServiceModel" />
+    <Reference Include="System.ServiceModel.Web" />
     <Reference Include="System.Xml" />
     <Reference Include="System.Xml" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
@@ -105,11 +99,11 @@
     </BootstrapperPackage>
     </BootstrapperPackage>
   </ItemGroup>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
   -->
   -->
 </Project>
 </Project>

+ 112 - 0
src/ProtocolBuffers.Test/CompatTests/CompatibilityTests.cs

@@ -71,5 +71,117 @@ namespace Google.ProtocolBuffers.CompatTests
             Assert.AreEqual(TestResources.google_message2, copy.ToByteArray());
             Assert.AreEqual(TestResources.google_message2, copy.ToByteArray());
         }
         }
 
 
+        #region Test message builders
+
+        private static TestAllTypes.Builder AddAllTypes(TestAllTypes.Builder builder)
+        {
+            return builder.SetOptionalInt32(1001)
+                .SetOptionalInt64(1001)
+                .SetOptionalUint32(1001)
+                .SetOptionalUint64(1001)
+                .SetOptionalSint32(-1001)
+                .SetOptionalSint64(-1001)
+                .SetOptionalFixed32(1001)
+                .SetOptionalFixed64(1001)
+                .SetOptionalSfixed32(-1001)
+                .SetOptionalSfixed64(-1001)
+                .SetOptionalFloat(1001.1001f)
+                .SetOptionalDouble(1001.1001)
+                .SetOptionalBool(true)
+                .SetOptionalString("this is a string value")
+                .SetOptionalBytes(ByteString.CopyFromUtf8("this is an array of bytes"))
+                .SetOptionalGroup(new TestAllTypes.Types.OptionalGroup.Builder().SetA(1001))
+                .SetOptionalNestedMessage(new TestAllTypes.Types.NestedMessage.Builder().SetBb(1001))
+                .SetOptionalNestedEnum(TestAllTypes.Types.NestedEnum.FOO)
+            ;
+        }
+
+        private static TestAllTypes.Builder AddRepeatedTypes(TestAllTypes.Builder builder, int size)
+        {
+            //repeated values
+            for (int i = 0; i < size; i++)
+                builder.AddRepeatedInt32(1001 + i)
+                .AddRepeatedInt64(1001)
+                .AddRepeatedUint32(1001)
+                .AddRepeatedUint64(1001)
+                .AddRepeatedSint32(-1001)
+                .AddRepeatedSint64(-1001)
+                .AddRepeatedFixed32(1001)
+                .AddRepeatedFixed64(1001)
+                .AddRepeatedSfixed32(-1001)
+                .AddRepeatedSfixed64(-1001)
+                .AddRepeatedFloat(1001.1001f)
+                .AddRepeatedDouble(1001.1001)
+                .AddRepeatedBool(true)
+                .AddRepeatedString("this is a string value")
+                .AddRepeatedBytes(ByteString.CopyFromUtf8("this is an array of bytes"))
+                .AddRepeatedGroup(new TestAllTypes.Types.RepeatedGroup.Builder().SetA(1001))
+                .AddRepeatedNestedMessage(new TestAllTypes.Types.NestedMessage.Builder().SetBb(1001))
+                .AddRepeatedNestedEnum(TestAllTypes.Types.NestedEnum.FOO)
+            ;
+            return builder;
+        }
+
+        private static TestPackedTypes.Builder AddPackedTypes(TestPackedTypes.Builder builder, int size)
+        {
+            for(int i=0; i < size; i++ )
+                builder.AddPackedInt32(1001)
+                .AddPackedInt64(1001)
+                .AddPackedUint32(1001)
+                .AddPackedUint64(1001)
+                .AddPackedSint32(-1001)
+                .AddPackedSint64(-1001)
+                .AddPackedFixed32(1001)
+                .AddPackedFixed64(1001)
+                .AddPackedSfixed32(-1001)
+                .AddPackedSfixed64(-1001)
+                .AddPackedFloat(1001.1001f)
+                .AddPackedDouble(1001.1001)
+                .AddPackedBool(true)
+                .AddPackedEnum(ForeignEnum.FOREIGN_FOO)
+            ;
+            return builder;
+        }
+
+        #endregion
+
+        [Test]
+        public void TestRoundTripAllTypes()
+        {
+            TestAllTypes msg = AddAllTypes(new TestAllTypes.Builder()).Build();
+            object content = SerializeMessage<TestAllTypes, TestAllTypes.Builder>(msg);
+
+            TestAllTypes copy = DeerializeMessage<TestAllTypes, TestAllTypes.Builder>(content, TestAllTypes.CreateBuilder(), ExtensionRegistry.Empty).Build();
+
+            Assert.AreEqual(msg, copy);
+            AssertOutputEquals(content, SerializeMessage<TestAllTypes, TestAllTypes.Builder>(copy));
+            Assert.AreEqual(msg.ToByteArray(), copy.ToByteArray());
+        }
+
+        [Test]
+        public void TestRoundTripRepeatedTypes()
+        {
+            TestAllTypes msg = AddRepeatedTypes(new TestAllTypes.Builder(), 5).Build();
+            object content = SerializeMessage<TestAllTypes, TestAllTypes.Builder>(msg);
+
+            TestAllTypes copy = DeerializeMessage<TestAllTypes, TestAllTypes.Builder>(content, TestAllTypes.CreateBuilder(), ExtensionRegistry.Empty).Build();
+
+            Assert.AreEqual(msg, copy);
+            AssertOutputEquals(content, SerializeMessage<TestAllTypes, TestAllTypes.Builder>(copy));
+            Assert.AreEqual(msg.ToByteArray(), copy.ToByteArray());
+        }
+
+        [Test]
+        public void TestRoundTripPackedTypes()
+        {
+            TestPackedTypes msg = AddPackedTypes(new TestPackedTypes.Builder(), 5).Build();
+            object content = SerializeMessage<TestPackedTypes, TestPackedTypes.Builder>(msg);
+
+            TestPackedTypes copy = DeerializeMessage<TestPackedTypes, TestPackedTypes.Builder>(content, TestPackedTypes.CreateBuilder(), ExtensionRegistry.Empty).Build();
+
+            Assert.AreEqual(msg, copy);
+            AssertOutputEquals(content, SerializeMessage<TestPackedTypes, TestPackedTypes.Builder>(copy));
+            Assert.AreEqual(msg.ToByteArray(), copy.ToByteArray());
+        }
     }
     }
 }
 }

+ 2 - 2
src/ProtocolBuffers.Test/CompatTests/JsonCompatibilityTests.cs

@@ -11,7 +11,7 @@ namespace Google.ProtocolBuffers.CompatTests
         protected override object SerializeMessage<TMessage, TBuilder>(TMessage message)
         protected override object SerializeMessage<TMessage, TBuilder>(TMessage message)
         {
         {
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new JsonFormatWriter(sw)
+            JsonFormatWriter.CreateInstance(sw)
                 .Formatted()
                 .Formatted()
                 .WriteMessage(message);
                 .WriteMessage(message);
             return sw.ToString();
             return sw.ToString();
@@ -19,7 +19,7 @@ namespace Google.ProtocolBuffers.CompatTests
 
 
         protected override TBuilder DeerializeMessage<TMessage, TBuilder>(object message, TBuilder builder, ExtensionRegistry registry)
         protected override TBuilder DeerializeMessage<TMessage, TBuilder>(object message, TBuilder builder, ExtensionRegistry registry)
         {
         {
-            new JsonFormatReader((string)message).Merge(builder);
+            JsonFormatReader.CreateInstance((string)message).Merge(builder);
             return builder;
             return builder;
         }
         }
     }
     }

+ 2 - 2
src/ProtocolBuffers.Test/CompatTests/XmlCompatibilityTests.cs

@@ -10,14 +10,14 @@ namespace Google.ProtocolBuffers.CompatTests
         protected override object SerializeMessage<TMessage, TBuilder>(TMessage message)
         protected override object SerializeMessage<TMessage, TBuilder>(TMessage message)
         {
         {
             StringWriter text = new StringWriter();
             StringWriter text = new StringWriter();
-            XmlFormatWriter writer = new XmlFormatWriter(text);
+            XmlFormatWriter writer = XmlFormatWriter.CreateInstance(text);
             writer.WriteMessage("root", message);
             writer.WriteMessage("root", message);
             return text.ToString();
             return text.ToString();
         }
         }
 
 
         protected override TBuilder DeerializeMessage<TMessage, TBuilder>(object message, TBuilder builder, ExtensionRegistry registry)
         protected override TBuilder DeerializeMessage<TMessage, TBuilder>(object message, TBuilder builder, ExtensionRegistry registry)
         {
         {
-            XmlFormatReader reader = new XmlFormatReader((string)message);
+            XmlFormatReader reader = XmlFormatReader.CreateInstance((string)message);
             return reader.Merge("root", builder, registry);
             return reader.Merge("root", builder, registry);
         }
         }
     }
     }

+ 16 - 16
src/ProtocolBuffers.Test/TestWriterFormatJson.cs

@@ -14,7 +14,7 @@ namespace Google.ProtocolBuffers
         protected void FormatterAssert<TMessage>(TMessage message, params string[] expecting) where TMessage : IMessageLite
         protected void FormatterAssert<TMessage>(TMessage message, params string[] expecting) where TMessage : IMessageLite
         {
         {
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new JsonFormatWriter(sw).WriteMessage(message);
+            JsonFormatWriter.CreateInstance(sw).WriteMessage(message);
             
             
             Content = sw.ToString();
             Content = sw.ToString();
 
 
@@ -22,7 +22,7 @@ namespace Google.ProtocolBuffers
             UnitTestXmlSerializerTestProtoFile.RegisterAllExtensions(registry);
             UnitTestXmlSerializerTestProtoFile.RegisterAllExtensions(registry);
 
 
             IMessageLite copy = 
             IMessageLite copy = 
-                new JsonFormatReader(Content)
+                JsonFormatReader.CreateInstance(Content)
                 .Merge(message.WeakCreateBuilderForType(), registry).WeakBuild();
                 .Merge(message.WeakCreateBuilderForType(), registry).WeakBuild();
 
 
             Assert.AreEqual(typeof(TMessage), copy.GetType());
             Assert.AreEqual(typeof(TMessage), copy.GetType());
@@ -44,12 +44,12 @@ namespace Google.ProtocolBuffers
                 .Build();
                 .Build();
 
 
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new JsonFormatWriter(sw).Formatted()
+            JsonFormatWriter.CreateInstance(sw).Formatted()
                 .WriteMessage(message);
                 .WriteMessage(message);
 
 
             string json = sw.ToString();
             string json = sw.ToString();
 
 
-            TestXmlMessage copy = new JsonFormatReader(json)
+            TestXmlMessage copy = JsonFormatReader.CreateInstance(json)
                 .Merge(TestXmlMessage.CreateBuilder()).Build();
                 .Merge(TestXmlMessage.CreateBuilder()).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
         }
         }
@@ -240,11 +240,11 @@ namespace Google.ProtocolBuffers
                 .ClearExtension(UnitTestXmlSerializerTestProtoFile.ExtensionEnum)
                 .ClearExtension(UnitTestXmlSerializerTestProtoFile.ExtensionEnum)
                 .Build();
                 .Build();
 
 
-            JsonFormatWriter writer = new JsonFormatWriter();
+            JsonFormatWriter writer = JsonFormatWriter.CreateInstance();
             writer.WriteMessage(original);
             writer.WriteMessage(original);
             Content = writer.ToString();
             Content = writer.ToString();
 
 
-            IMessageLite copy = new JsonFormatReader(Content)
+            IMessageLite copy = JsonFormatReader.CreateInstance(Content)
                 .Merge(message.CreateBuilderForType()).Build();
                 .Merge(message.CreateBuilderForType()).Build();
 
 
             Assert.AreNotEqual(original, message);
             Assert.AreNotEqual(original, message);
@@ -255,8 +255,8 @@ namespace Google.ProtocolBuffers
         public void TestMergeFields()
         public void TestMergeFields()
         {
         {
             TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder();
             TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder();
-            builder.MergeFrom(new JsonFormatReader("\"valid\": true"));
-            builder.MergeFrom(new JsonFormatReader("\"text\": \"text\", \"number\": \"411\""));
+            builder.MergeFrom(JsonFormatReader.CreateInstance("\"valid\": true"));
+            builder.MergeFrom(JsonFormatReader.CreateInstance("\"text\": \"text\", \"number\": \"411\""));
             Assert.AreEqual(true, builder.Valid);
             Assert.AreEqual(true, builder.Valid);
             Assert.AreEqual("text", builder.Text);
             Assert.AreEqual("text", builder.Text);
             Assert.AreEqual(411, builder.Number);
             Assert.AreEqual(411, builder.Number);
@@ -264,7 +264,7 @@ namespace Google.ProtocolBuffers
         [Test]
         [Test]
         public void TestMessageArray()
         public void TestMessageArray()
         {
         {
-            JsonFormatWriter writer = new JsonFormatWriter().Formatted();
+            JsonFormatWriter writer = JsonFormatWriter.CreateInstance().Formatted();
             using (writer.StartArray())
             using (writer.StartArray())
             {
             {
                 writer.WriteMessage(TestXmlMessage.CreateBuilder().SetNumber(1).AddTextlines("a").Build());
                 writer.WriteMessage(TestXmlMessage.CreateBuilder().SetNumber(1).AddTextlines("a").Build());
@@ -272,7 +272,7 @@ namespace Google.ProtocolBuffers
                 writer.WriteMessage(TestXmlMessage.CreateBuilder().SetNumber(3).AddTextlines("c").Build());
                 writer.WriteMessage(TestXmlMessage.CreateBuilder().SetNumber(3).AddTextlines("c").Build());
             }
             }
             string json = writer.ToString();
             string json = writer.ToString();
-            JsonFormatReader reader = new JsonFormatReader(json);
+            JsonFormatReader reader = JsonFormatReader.CreateInstance(json);
             
             
             TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder();
             TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder();
             int ordinal = 0;
             int ordinal = 0;
@@ -288,7 +288,7 @@ namespace Google.ProtocolBuffers
         [Test]
         [Test]
         public void TestNestedMessageArray()
         public void TestNestedMessageArray()
         {
         {
-            JsonFormatWriter writer = new JsonFormatWriter();
+            JsonFormatWriter writer = JsonFormatWriter.CreateInstance();
             using (writer.StartArray())
             using (writer.StartArray())
             {
             {
                 using (writer.StartArray())
                 using (writer.StartArray())
@@ -300,7 +300,7 @@ namespace Google.ProtocolBuffers
                     writer.WriteMessage(TestXmlMessage.CreateBuilder().SetNumber(3).AddTextlines("c").Build());
                     writer.WriteMessage(TestXmlMessage.CreateBuilder().SetNumber(3).AddTextlines("c").Build());
             }
             }
             string json = writer.ToString();
             string json = writer.ToString();
-            JsonFormatReader reader = new JsonFormatReader(json);
+            JsonFormatReader reader = JsonFormatReader.CreateInstance(json);
 
 
             TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder();
             TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder();
             int ordinal = 0;
             int ordinal = 0;
@@ -317,25 +317,25 @@ namespace Google.ProtocolBuffers
         [Test, ExpectedException(typeof(FormatException))]
         [Test, ExpectedException(typeof(FormatException))]
         public void FailWithEmptyText()
         public void FailWithEmptyText()
         {
         {
-            new JsonFormatReader("")
+            JsonFormatReader.CreateInstance("")
                 .Merge(TestXmlMessage.CreateBuilder());
                 .Merge(TestXmlMessage.CreateBuilder());
         }
         }
         [Test, ExpectedException(typeof(FormatException))]
         [Test, ExpectedException(typeof(FormatException))]
         public void FailWithUnexpectedValue()
         public void FailWithUnexpectedValue()
         {
         {
-            new JsonFormatReader("{{}}")
+            JsonFormatReader.CreateInstance("{{}}")
                 .Merge(TestXmlMessage.CreateBuilder());
                 .Merge(TestXmlMessage.CreateBuilder());
         }
         }
         [Test, ExpectedException(typeof(FormatException))]
         [Test, ExpectedException(typeof(FormatException))]
         public void FailWithUnQuotedName()
         public void FailWithUnQuotedName()
         {
         {
-            new JsonFormatReader("{name:{}}")
+            JsonFormatReader.CreateInstance("{name:{}}")
                 .Merge(TestXmlMessage.CreateBuilder());
                 .Merge(TestXmlMessage.CreateBuilder());
         }
         }
         [Test, ExpectedException(typeof(FormatException))]
         [Test, ExpectedException(typeof(FormatException))]
         public void FailWithUnexpectedType()
         public void FailWithUnexpectedType()
         {
         {
-            new JsonFormatReader("{\"valid\":{}}")
+            JsonFormatReader.CreateInstance("{\"valid\":{}}")
                 .Merge(TestXmlMessage.CreateBuilder());
                 .Merge(TestXmlMessage.CreateBuilder());
         }
         }
     }
     }

+ 32 - 34
src/ProtocolBuffers.Test/TestWriterFormatXml.cs

@@ -23,12 +23,12 @@ namespace Google.ProtocolBuffers
 
 
             //When we call message.WriteTo, we are responsible for the root element
             //When we call message.WriteTo, we are responsible for the root element
             xw.WriteStartElement("root");
             xw.WriteStartElement("root");
-            message.WriteTo(new XmlFormatWriter(xw));
+            message.WriteTo(XmlFormatWriter.CreateInstance(xw));
             xw.WriteEndElement();
             xw.WriteEndElement();
             xw.Flush();
             xw.Flush();
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             TestXmlChild copy = rdr.Merge(TestXmlChild.CreateBuilder()).Build();
             TestXmlChild copy = rdr.Merge(TestXmlChild.CreateBuilder()).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
         }
         }
@@ -42,10 +42,10 @@ namespace Google.ProtocolBuffers
 
 
             //Allow the writer to write the root element
             //Allow the writer to write the root element
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new XmlFormatWriter(sw).WriteMessage("root", message);
+            XmlFormatWriter.CreateInstance(sw).WriteMessage("root", message);
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             TestXmlChild copy = rdr.Merge(TestXmlChild.CreateBuilder()).Build();
             TestXmlChild copy = rdr.Merge(TestXmlChild.CreateBuilder()).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
         }
         }
@@ -57,10 +57,10 @@ namespace Google.ProtocolBuffers
                 .Build();
                 .Build();
 
 
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new XmlFormatWriter(sw).WriteMessage("root", message);
+            XmlFormatWriter.CreateInstance(sw).WriteMessage("root", message);
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
         }
         }
@@ -72,10 +72,10 @@ namespace Google.ProtocolBuffers
                 .Build();
                 .Build();
 
 
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new XmlFormatWriter(sw).WriteMessage("root", message);
+            XmlFormatWriter.CreateInstance(sw).WriteMessage("root", message);
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
         }
         }
@@ -87,10 +87,10 @@ namespace Google.ProtocolBuffers
                 .Build();
                 .Build();
 
 
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new XmlFormatWriter(sw).WriteMessage("root", message);
+            XmlFormatWriter.CreateInstance(sw).WriteMessage("root", message);
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
         }
         }
@@ -113,11 +113,11 @@ namespace Google.ProtocolBuffers
                 .Build();
                 .Build();
 
 
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new XmlFormatWriter(sw).WriteMessage("root", message);
+            XmlFormatWriter.CreateInstance(sw).WriteMessage("root", message);
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
 
 
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
         }
         }
@@ -140,14 +140,13 @@ namespace Google.ProtocolBuffers
                 .Build();
                 .Build();
 
 
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new XmlFormatWriter(sw) 
-            {
-                Options = XmlWriterOptions.OutputNestedArrays | XmlWriterOptions.OutputEnumValues
-            }.WriteMessage("root", message);
+            XmlFormatWriter.CreateInstance(sw)
+                .SetOptions(XmlWriterOptions.OutputNestedArrays | XmlWriterOptions.OutputEnumValues)
+                .WriteMessage("root", message);
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
 
 
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             rdr.Options = XmlReaderOptions.ReadNestedArrays;
             rdr.Options = XmlReaderOptions.ReadNestedArrays;
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
@@ -174,10 +173,9 @@ namespace Google.ProtocolBuffers
             Assert.AreEqual(0, message.AllFields.Count);
             Assert.AreEqual(0, message.AllFields.Count);
 
 
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new XmlFormatWriter(sw)
-            {
-                Options = XmlWriterOptions.OutputNestedArrays | XmlWriterOptions.OutputEnumValues
-            }.WriteMessage("root", message);
+            XmlFormatWriter.CreateInstance(sw)
+                .SetOptions(XmlWriterOptions.OutputNestedArrays | XmlWriterOptions.OutputEnumValues)
+                .WriteMessage("root", message);
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
 
 
@@ -191,7 +189,7 @@ namespace Google.ProtocolBuffers
                     );
                     );
             }
             }
 
 
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             rdr.Options = XmlReaderOptions.ReadNestedArrays;
             rdr.Options = XmlReaderOptions.ReadNestedArrays;
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             Assert.AreEqual(TestXmlMessage.DefaultInstance, copy);
             Assert.AreEqual(TestXmlMessage.DefaultInstance, copy);
@@ -203,11 +201,11 @@ namespace Google.ProtocolBuffers
                 .SetText("<text>").Build();
                 .SetText("<text>").Build();
 
 
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new XmlFormatWriter(sw).WriteMessage("root", message);
+            XmlFormatWriter.CreateInstance(sw).WriteMessage("root", message);
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
 
 
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
         }
         }
@@ -218,11 +216,11 @@ namespace Google.ProtocolBuffers
                 .SetText(" \t <- leading space and trailing -> \r\n\t").Build();
                 .SetText(" \t <- leading space and trailing -> \r\n\t").Build();
 
 
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new XmlFormatWriter(sw).WriteMessage("root", message);
+            XmlFormatWriter.CreateInstance(sw).WriteMessage("root", message);
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
 
 
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder()).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
         }
         }
@@ -234,14 +232,14 @@ namespace Google.ProtocolBuffers
                 .Build();
                 .Build();
 
 
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new XmlFormatWriter(sw).WriteMessage("root", message);
+            XmlFormatWriter.CreateInstance(sw).WriteMessage("root", message);
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
 
 
             ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
             ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
             UnitTestXmlSerializerTestProtoFile.RegisterAllExtensions(registry);
             UnitTestXmlSerializerTestProtoFile.RegisterAllExtensions(registry);
 
 
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder(), registry).Build();
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder(), registry).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
         }
         }
@@ -253,14 +251,14 @@ namespace Google.ProtocolBuffers
                 new TestXmlExtension.Builder().SetNumber(42).Build()).Build();
                 new TestXmlExtension.Builder().SetNumber(42).Build()).Build();
 
 
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new XmlFormatWriter(sw).WriteMessage("root", message);
+            XmlFormatWriter.CreateInstance(sw).WriteMessage("root", message);
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
 
 
             ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
             ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
             UnitTestXmlSerializerTestProtoFile.RegisterAllExtensions(registry);
             UnitTestXmlSerializerTestProtoFile.RegisterAllExtensions(registry);
 
 
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder(), registry).Build();
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder(), registry).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
         }
         }
@@ -274,14 +272,14 @@ namespace Google.ProtocolBuffers
                 .Build();
                 .Build();
 
 
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new XmlFormatWriter(sw).WriteMessage("root", message);
+            XmlFormatWriter.CreateInstance(sw).WriteMessage("root", message);
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
 
 
             ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
             ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
             UnitTestXmlSerializerTestProtoFile.RegisterAllExtensions(registry);
             UnitTestXmlSerializerTestProtoFile.RegisterAllExtensions(registry);
 
 
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder(), registry).Build();
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder(), registry).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
         }
         }
@@ -293,14 +291,14 @@ namespace Google.ProtocolBuffers
                 .Build();
                 .Build();
 
 
             StringWriter sw = new StringWriter();
             StringWriter sw = new StringWriter();
-            new XmlFormatWriter(sw).WriteMessage("root", message);
+            XmlFormatWriter.CreateInstance(sw).WriteMessage("root", message);
 
 
             string xml = sw.ToString();
             string xml = sw.ToString();
 
 
             ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
             ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
             UnitTestXmlSerializerTestProtoFile.RegisterAllExtensions(registry);
             UnitTestXmlSerializerTestProtoFile.RegisterAllExtensions(registry);
 
 
-            XmlFormatReader rdr = new XmlFormatReader(xml);
+            XmlFormatReader rdr = XmlFormatReader.CreateInstance(xml);
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder(), registry).Build();
             TestXmlMessage copy = rdr.Merge(TestXmlMessage.CreateBuilder(), registry).Build();
             Assert.AreEqual(message, copy);
             Assert.AreEqual(message, copy);
         }
         }

+ 12 - 3
src/ProtocolBuffers/Serialization/DictionaryReader.cs

@@ -64,7 +64,7 @@ namespace Google.ProtocolBuffers.Serialization
                 try 
                 try 
                 {
                 {
                     if (obj is IConvertible)
                     if (obj is IConvertible)
-                        value = (T)Convert.ChangeType(obj, typeof(T));
+                        value = (T)Convert.ChangeType(obj, typeof(T), System.Globalization.CultureInfo.InvariantCulture);
                     else
                     else
                         value = (T)obj;
                         value = (T)obj;
                 }
                 }
@@ -186,8 +186,17 @@ namespace Google.ProtocolBuffers.Serialization
             object[] array = null;
             object[] array = null;
             if (GetValue(ref array))
             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 true;
             }
             }
             return false;
             return false;

+ 32 - 16
src/ProtocolBuffers/Serialization/JsonFormatReader.cs

@@ -10,34 +10,50 @@ namespace Google.ProtocolBuffers.Serialization
     /// </summary>
     /// </summary>
     public class JsonFormatReader : AbstractTextReader
     public class JsonFormatReader : AbstractTextReader
     {
     {
-        private readonly JsonTextCursor _input;
+        private readonly JsonCursor _input;
         private readonly Stack<int> _stopChar;
         private readonly Stack<int> _stopChar;
 
 
         enum ReaderState { Start, BeginValue, EndValue, BeginObject, BeginArray }
         enum ReaderState { Start, BeginValue, EndValue, BeginObject, BeginArray }
         string _current;
         string _current;
         ReaderState _state;
         ReaderState _state;
 
 
+        /// <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(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>
         /// <summary>
         /// Constructs a JsonFormatReader to parse Json into a message
         /// Constructs a JsonFormatReader to parse Json into a message
         /// </summary>
         /// </summary>
-        public JsonFormatReader(string jsonText)
-        {
-            _input = new JsonTextCursor(jsonText.ToCharArray());
-            _stopChar = new Stack<int>();
-            _stopChar.Push(-1);
-            _state = ReaderState.Start;
-        }
+        public static JsonFormatReader CreateInstance(string jsonText) { return new JsonFormatReader(JsonCursor.CreateInstance(jsonText)); }
         /// <summary>
         /// <summary>
         /// Constructs a JsonFormatReader to parse Json into a message
         /// Constructs a JsonFormatReader to parse Json into a message
         /// </summary>
         /// </summary>
-        public JsonFormatReader(TextReader input)
+        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 = new Stack<int>();
             _stopChar.Push(-1);
             _stopChar.Push(-1);
             _state = ReaderState.Start;
             _state = ReaderState.Start;
         }
         }
 
 
+        /// <summary>
+        /// Constructs a JsonFormatReader to parse Json into a message
+        /// </summary>
+        protected JsonFormatReader(TextReader input)
+            : this(JsonCursor.CreateInstance(input))
+        { }
+
         /// <summary>
         /// <summary>
         /// Returns true if the reader is currently on an array element
         /// Returns true if the reader is currently on an array element
         /// </summary>
         /// </summary>
@@ -115,18 +131,18 @@ namespace Google.ProtocolBuffers.Serialization
         protected override bool ReadAsText(ref string value, Type typeInfo)
         protected override bool ReadAsText(ref string value, Type typeInfo)
         {
         {
             object temp;
             object temp;
-            JsonTextCursor.JsType type = _input.ReadVariant(out temp);
+            JsonCursor.JsType type = _input.ReadVariant(out temp);
             _state = ReaderState.EndValue;
             _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;
                 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;
             else value = temp as string;
 
 
             //exponent representation of integer number:
             //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)) &&
                 (typeInfo != typeof(double) && typeInfo != typeof(float)) &&
                 value.IndexOf("e", StringComparison.OrdinalIgnoreCase) > 0)
                 value.IndexOf("e", StringComparison.OrdinalIgnoreCase) > 0)
             {
             {

+ 150 - 52
src/ProtocolBuffers/Serialization/JsonFormatWriter.cs

@@ -1,6 +1,7 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.IO;
 using System.IO;
+using System.Text;
 using Google.ProtocolBuffers.Descriptors;
 using Google.ProtocolBuffers.Descriptors;
 
 
 namespace Google.ProtocolBuffers.Serialization
 namespace Google.ProtocolBuffers.Serialization
@@ -10,81 +11,178 @@ namespace Google.ProtocolBuffers.Serialization
     /// you may also use the XmlFormatWriter with an XmlWriter created by the
     /// you may also use the XmlFormatWriter with an XmlWriter created by the
     /// <see cref="System.Runtime.Serialization.Json.JsonReaderWriterFactory">JsonReaderWriterFactory</see>.
     /// <see cref="System.Runtime.Serialization.Json.JsonReaderWriterFactory">JsonReaderWriterFactory</see>.
     /// </summary>
     /// </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;
 
 
+            public JsonTextWriter(TextWriter output)
+            {
+                _buffer = new char[4096];
+                _bufferPos = 0;
+                _output = output;
+                _counter.Add(0);
+            }
 
 
-        private void WriteToOutput(string format, params object[] args)
-        { WriteToOutput(String.Format(format, args)); }
+            /// <summary>
+            /// Returns the output of TextWriter.ToString() where TextWriter is the ctor argument.
+            /// </summary>
+            public override string ToString()
+            {
+                Flush();
 
 
-        private void WriteToOutput(string text)
-        { WriteToOutput(text.ToCharArray(), 0, text.Length); }
+                if (_output != null)
+                    return _output.ToString();
 
 
-        private void WriteToOutput(char[] chars, int offset, int len)
-        {
-            if (_bufferPos + len >= _buffer.Length)
-                Flush();
-            if (len < _buffer.Length)
+                return new String(_buffer, 0, _bufferPos);
+            }
+
+            protected override void WriteToOutput(char[] chars, int offset, int len)
             {
             {
-                if (len <= 12)
+                if (_bufferPos + len >= _buffer.Length)
+                {
+                    if (_output == null)
+                        _output = new StringWriter(new System.Text.StringBuilder(_buffer.Length * 2 + len));
+                    Flush();
+                }
+
+                if (len < _buffer.Length)
                 {
                 {
-                    int stop = offset + len;
-                    for (int i = offset; i < stop; i++)
-                        _buffer[_bufferPos++] = chars[i];
+                    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
                 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)
                 {
                 {
-                    Buffer.BlockCopy(chars, offset << 1, _buffer, _bufferPos << 1, len << 1);
-                    _bufferPos += len;
+                    _output.Write(_buffer, 0, _bufferPos);
+                    _bufferPos = 0;
                 }
                 }
+                base.Flush();
             }
             }
-            else
-                _output.Write(chars, offset, len);
         }
         }
-
-        private void WriteToOutput(char ch)
+        private class JsonStreamWriter : JsonFormatWriter
         {
         {
-            if (_bufferPos >= _buffer.Length)
-                Flush();
-            _buffer[_bufferPos++] = ch;
-        }
+#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 override void Flush()
-        {
-            if (_bufferPos > 0)
+            public JsonStreamWriter(Stream output)
             {
             {
-                _output.Write(_buffer, 0, _bufferPos);
+                _buffer = new byte[8192];
                 _bufferPos = 0;
                 _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
+                {
+                    byte[] temp = Encoding.GetBytes(chars, offset, len);
+                    _output.Write(temp, 0, temp.Length);
+                }
+            }
+
+            protected override void WriteToOutput(char ch)
+            {
+                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>
         /// <summary>
-        /// Returns the output of TextWriter.ToString() where TextWriter is the ctor argument.
+        /// Constructs a JsonFormatWriter, use ToString() to extract the final output
         /// </summary>
         /// </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>
         /// <summary> Sets the output formatting to use Environment.NewLine with 4-character indentions </summary>
         public JsonFormatWriter Formatted()
         public JsonFormatWriter Formatted()

+ 98 - 35
src/ProtocolBuffers/Serialization/JsonTextCursor.cs

@@ -9,52 +9,115 @@ namespace Google.ProtocolBuffers.Serialization
     /// <summary>
     /// <summary>
     /// JSon Tokenizer used by JsonFormatReader
     /// JSon Tokenizer used by JsonFormatReader
     /// </summary>
     /// </summary>
-    class JsonTextCursor
+    abstract class JsonCursor
     {
     {
         public enum JsType { String, Number, Object, Array, True, False, Null }
         public enum JsType { String, Number, Object, Array, True, False, Null }
 
 
-        private readonly char[] _buffer;
-        private int _bufferPos;
-        private readonly TextReader _input;
-        private int _lineNo, _linePos;
-
-        public JsonTextCursor(char[] input)
+        #region Buffering implementations
+        class JsonStreamCursor : JsonCursor
         {
         {
-            _input = null;
-            _buffer = input;
-            _bufferPos = 0;
-            _next = Peek();
-            _lineNo = 1;
-        }
+            private readonly byte[] _buffer;
+            private int _bufferPos;
+            private readonly Stream _input;
 
 
-        public JsonTextCursor(TextReader input)
-        {
-            _input = input;
-            _next = Peek();
-            _lineNo = 1;
+            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;
+            }
         }
         }
 
 
-        private int Peek()
+        class JsonTextCursor : JsonCursor
         {
         {
-            if (_input != null)
-                return _input.Peek();
-            else if (_bufferPos < _buffer.Length)
-                return _buffer[_bufferPos];
-            else
-                return -1;
+            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;
 
 
-        private int Read()
+        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()
         {
         {
-            if (_input != null)
-                return _input.Read();
-            else if (_bufferPos < _buffer.Length)
-                return _buffer[_bufferPos++];
-            else
-                return -1;
+            _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();
 
 
-        int _next;
         public Char NextChar { get { SkipWhitespace(); return (char)_next; } }
         public Char NextChar { get { SkipWhitespace(); return (char)_next; } }
 
 
         #region Assert(...)
         #region Assert(...)
@@ -62,8 +125,8 @@ namespace Google.ProtocolBuffers.Serialization
         private string CharDisplay(int ch)
         private string CharDisplay(int ch)
         {
         {
             return ch == -1 ? "EOF" :
             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]
         [System.Diagnostics.DebuggerNonUserCode]
         private void Assert(bool cond, char expected)
         private void Assert(bool cond, char expected)

+ 15 - 7
src/ProtocolBuffers/Serialization/XmlFormatReader.cs

@@ -25,33 +25,41 @@ namespace Google.ProtocolBuffers.Serialization
         /// <summary>
         /// <summary>
         /// Constructs the XmlFormatReader using the stream provided as the xml
         /// Constructs the XmlFormatReader using the stream provided as the xml
         /// </summary>
         /// </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>
         /// <summary>
         /// Constructs the XmlFormatReader using the string provided as the xml to be read
         /// Constructs the XmlFormatReader using the string provided as the xml to be read
         /// </summary>
         /// </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>
         /// <summary>
         /// Constructs the XmlFormatReader using the xml in the TextReader
         /// Constructs the XmlFormatReader using the xml in the TextReader
         /// </summary>
         /// </summary>
-        public XmlFormatReader(TextReader input) : this(XmlReader.Create(input)) { }
+        public static XmlFormatReader CreateInstance(TextReader input) { return new XmlFormatReader(XmlReader.Create(input, DefaultSettings)); }
         /// <summary>
         /// <summary>
         /// Constructs the XmlFormatReader with the XmlReader
         /// Constructs the XmlFormatReader with the XmlReader
         /// </summary>
         /// </summary>
-        public XmlFormatReader(XmlReader input) : this(input, XmlReaderOptions.None) { }
+        public static XmlFormatReader CreateInstance(XmlReader input) { return new XmlFormatReader(input); }
         /// <summary>
         /// <summary>
         /// Constructs the XmlFormatReader with the XmlReader and options
         /// Constructs the XmlFormatReader with the XmlReader and options
         /// </summary>
         /// </summary>
-        public XmlFormatReader(XmlReader input, XmlReaderOptions options)
+        protected XmlFormatReader(XmlReader input)
         {
         {
             _input = input;
             _input = input;
             _rootElementName = DefaultRootElementName;
             _rootElementName = DefaultRootElementName;
-            Options = options;
+            Options = XmlReaderOptions.None;
         }
         }
         
         
         /// <summary>
         /// <summary>
         /// Gets or sets the options to use when reading the xml
         /// Gets or sets the options to use when reading the xml
         /// </summary>
         /// </summary>
         public XmlReaderOptions Options { get; set; }
         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>
         /// <summary>
         /// Gets or sets the default element name to use when using the Merge&lt;TBuilder>()
         /// Gets or sets the default element name to use when using the Merge&lt;TBuilder>()
@@ -64,7 +72,7 @@ namespace Google.ProtocolBuffers.Serialization
 
 
         private XmlFormatReader CloneWith(XmlReader rdr)
         private XmlFormatReader CloneWith(XmlReader rdr)
         {
         {
-            return new XmlFormatReader(rdr, Options);
+            return new XmlFormatReader(rdr).SetOptions(Options);
         }
         }
         private void NextElement()
         private void NextElement()
         {
         {

+ 16 - 5
src/ProtocolBuffers/Serialization/XmlFormatWriter.cs

@@ -1,5 +1,6 @@
 using System;
 using System;
 using System.IO;
 using System.IO;
+using System.Text;
 using System.Xml;
 using System.Xml;
 using Google.ProtocolBuffers.Descriptors;
 using Google.ProtocolBuffers.Descriptors;
 
 
@@ -17,23 +18,29 @@ namespace Google.ProtocolBuffers.Serialization
         private readonly XmlWriter _output;
         private readonly XmlWriter _output;
         private string _rootElementName;
         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>
         /// <summary>
         /// Constructs the XmlFormatWriter to write to the given TextWriter
         /// Constructs the XmlFormatWriter to write to the given TextWriter
         /// </summary>
         /// </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>
         /// <summary>
         /// Constructs the XmlFormatWriter to write to the given stream
         /// Constructs the XmlFormatWriter to write to the given stream
         /// </summary>
         /// </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>
         /// <summary>
         /// Constructs the XmlFormatWriter to write to the given XmlWriter
         /// Constructs the XmlFormatWriter to write to the given XmlWriter
         /// </summary>
         /// </summary>
-        public XmlFormatWriter(XmlWriter output)
+        public static XmlFormatWriter CreateInstance(XmlWriter output) { return new XmlFormatWriter(output); }
+
+        protected XmlFormatWriter(XmlWriter output)
         {
         {
             _output = output;
             _output = output;
             _rootElementName = DefaultRootElementName;
             _rootElementName = DefaultRootElementName;
@@ -61,6 +68,10 @@ namespace Google.ProtocolBuffers.Serialization
         /// Gets or sets the options to use while generating the XML
         /// Gets or sets the options to use while generating the XML
         /// </summary>
         /// </summary>
         public XmlWriterOptions Options { get; set; }
         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; }
         private bool TestOption(XmlWriterOptions option) { return (Options & option) != 0; }