Commit 45b70328 authored by Jan Tattermusch's avatar Jan Tattermusch

Merge pull request #515 from jskeet/proto3-only

Proto3 experimental C# fork
parents 5b3a8e76 50a3a809
......@@ -79,8 +79,7 @@ java/target
javanano/target
# Windows native output.
vsprojects/Debug
vsprojects/Release
cmake/build
# NuGet packages: we want the repository configuration, but not the
# packages themselves.
......
......@@ -16,7 +16,6 @@ set(libprotoc_files
${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_string_field.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_enum.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_enum_field.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_extension.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_field_base.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_generator.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_helpers.cc
......@@ -28,7 +27,6 @@ set(libprotoc_files
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_writer.cc
${protobuf_source_dir}/src/google/protobuf/compiler/java/java_context.cc
${protobuf_source_dir}/src/google/protobuf/compiler/java/java_doc_comment.cc
${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum.cc
......
This directory contains the C# Protocol Buffers runtime library.
Warning: experimental!
======================
This code is still under significant churn. Unlike the original port,
it only supports proto3 (but not *all* of proto3 yet) - there are no
unknown fields or extensions, for example. protoc will (eventually)
deliberately fail if it is asked to generate C# code for proto2
messages other than descriptor.proto, which is still required for
reflection. (It's currently exposed publicly, but won't be
eventually.)
Also unlike the original port, the new version embraces mutability -
there are no builder types. We plan to add "freezing" operations as
well as cloning, however.
Usage
=====
The easiest way to use C# protocol buffers in your project is to use the [Google.ProtocolBuffers NuGet package](http://www.nuget.org/packages/Google.ProtocolBuffers/). This package is the legacy package for C# protocol buffers, but it will work fine with C# code generated by `protoc` if you use proto2 syntax (The API of the runtime library haven't changed so far).
*WARNING: If you specify `syntax = "proto3";` in your .proto files, the generated code won't necessarily work with the legacy NuGet package. So before we officially add proto3 support, always use `syntax = "proto2";` (the default) in your protos.*
We will definitely release a new NuGet package for the runtime library in the future. The new runtime library WILL contain significant semantic, backwardly-incompatible changes in proto handling (mostly because we will be adding proto3 support and we will be using that oportunity to make some design changes). So keep in mind that you will need to regenerate your proto files and switch to a new NuGet package once the new version of runtime library becomes available.
Building
......@@ -17,17 +29,6 @@ Open the `src/ProtocolBuffers.sln` solution in Visual Studio. Click "Build solut
Supported Visual Studio versions are VS2013 (update 4) and VS2015. On Linux, you can also use Monodevelop 5.9 (older versions might work fine).
Proto2 & Proto3
===============
*WARNING: Only proto2 is supported for now, proto3 is under construction.*
C# protocol buffers are currently under development and you should expect semantic, backward-incompatible changes in the future.
Also, as of now, only proto2 is supported. Proto3 support for C# is currently in progress
(both design & implementation) and you should not expect any of the proto3 features to work.
In fact, always use `syntax = "proto2";` in your .proto files for now, unless you are feeling like experimenting.
History of C# protobufs
=======================
......
......@@ -23,10 +23,10 @@ cd $(dirname $0)/..
# Windows and Unix.
if [ -z "$PROTOC" ]; then
# TODO(jonskeet): Use an array and a for loop instead?
if [ -x vsprojects/Debug/protoc.exe ]; then
PROTOC=vsprojects/Debug/protoc.exe
elif [ -x vsprojects/Release/protoc.exe ]; then
PROTOC=vsprojects/Release/protoc.exe
if [ -x cmake/build/Debug/protoc.exe ]; then
PROTOC=cmake/build/Debug/protoc.exe
elif [ -x cmake/build/Release/protoc.exe ]; then
PROTOC=cmake/build/Release/protoc.exe
elif [ -x src/protoc ]; then
PROTOC=src/protoc
else
......@@ -42,52 +42,14 @@ $PROTOC -Isrc --csharp_out=csharp/src/ProtocolBuffers/DescriptorProtos \
src/google/protobuf/descriptor_proto_file.proto
rm src/google/protobuf/descriptor_proto_file.proto
# ProtocolBuffers.Test protos
$PROTOC -Isrc --csharp_out=csharp/src/ProtocolBuffers.Test/TestProtos \
src/google/protobuf/unittest.proto \
src/google/protobuf/unittest_custom_options.proto \
src/google/protobuf/unittest_drop_unknown_fields.proto \
src/google/protobuf/unittest_enormous_descriptor.proto \
src/google/protobuf/unittest_import.proto \
src/google/protobuf/unittest_import_public.proto \
src/google/protobuf/unittest_mset.proto \
src/google/protobuf/unittest_optimize_for.proto \
src/google/protobuf/unittest_no_field_presence.proto \
src/google/protobuf/unknown_enum_test.proto
src/google/protobuf/unittest_proto3.proto \
src/google/protobuf/unittest_import_proto3.proto \
src/google/protobuf/unittest_import_public_proto3.proto
$PROTOC -Icsharp/protos/extest --csharp_out=csharp/src/ProtocolBuffers.Test/TestProtos \
csharp/protos/extest/unittest_extras_xmltest.proto \
csharp/protos/extest/unittest_issues.proto
$PROTOC -Ibenchmarks --csharp_out=csharp/src/ProtocolBuffers.Test/TestProtos \
benchmarks/google_size.proto \
benchmarks/google_speed.proto
# ProtocolBuffersLite.Test protos
$PROTOC -Isrc --csharp_out=csharp/src/ProtocolBuffersLite.Test/TestProtos \
src/google/protobuf/unittest.proto \
src/google/protobuf/unittest_import.proto \
src/google/protobuf/unittest_import_lite.proto \
src/google/protobuf/unittest_import_public.proto \
src/google/protobuf/unittest_import_public_lite.proto \
src/google/protobuf/unittest_lite.proto \
src/google/protobuf/unittest_lite_imports_nonlite.proto
$PROTOC -Icsharp/protos/extest --csharp_out=csharp/src/ProtocolBuffersLite.Test/TestProtos \
csharp/protos/extest/unittest_extras_full.proto \
csharp/protos/extest/unittest_extras_lite.proto
# TODO(jonskeet): Remove fixup; see issue #307
sed -i -e 's/RepeatedFieldsGenerator\.Group/RepeatedFieldsGenerator.Types.Group/g' \
csharp/src/ProtocolBuffers.Test/TestProtos/Unittest.cs \
csharp/src/ProtocolBuffersLite.Test/TestProtos/Unittest.cs \
csharp/src/ProtocolBuffersLite.Test/TestProtos/UnittestLite.cs
# TODO(jonskeet): Remove fixup
sed -i -e 's/DescriptorProtos\.Descriptor\./DescriptorProtos.DescriptorProtoFile./g' \
csharp/src/ProtocolBuffers.Test/TestProtos/UnittestCustomOptions.cs
# AddressBook sample protos
$PROTOC -Iexamples --csharp_out=csharp/src/AddressBook \
examples/addressbook.proto
syntax = "proto2";
syntax = "proto3";
// These proto descriptors have at one time been reported as an issue or defect.
// They are kept here to replicate the issue, and continue to verify the fix.
......@@ -9,65 +9,6 @@ option csharp_namespace = "UnitTest.Issues.TestProtos";
package unittest_issues;
option optimize_for = SPEED;
// The following is a representative set of features
/*
enum EnumOptions {
ONE = 0;
TWO = 1;
THREE = 2;
}
message TestBasicChild
{
repeated EnumOptions options = 3;
optional bytes binary = 4;
}
message TestBasicNoFields {
}
message TestBasicRescursive {
optional TestBasicRescursive child = 1;
}
message TestBasicMessage {
optional int64 number = 6;
repeated int32 numbers = 2;
optional string text = 3;
repeated string textlines = 700;
optional bool valid = 5;
optional TestBasicChild child = 1;
repeated group Children = 401
{
repeated EnumOptions options = 3;
optional bytes binary = 4;
}
extensions 100 to 199;
}
message TestBasicExtension {
required int32 number = 1;
}
extend TestBasicMessage {
optional EnumOptions extension_enum = 101;
optional string extension_text = 102;
repeated int32 extension_number = 103 [packed = true];
optional TestBasicExtension extension_message = 199;
}
// Issue for non-qualified type reference in new services generation
option (google.protobuf.csharp_file_options).service_generator_type = IRPCDISPATCH;
service TestGenericService {
rpc Foo(TestBasicNoFields) returns (TestBasicMessage);
rpc Bar(TestBasicNoFields) returns (TestBasicMessage);
}
*/
// Old issue 13: http://code.google.com/p/protobuf-csharp-port/issues/detail?id=13
// New issue 309: https://github.com/google/protobuf/issues/309
......@@ -90,27 +31,17 @@ service TestGenericService {
// optional int32 _01 = 1;
// }
// Issue 28: Circular message dependencies result in null defaults for DefaultInstance
message MyMessageAReferenceB {
required MyMessageBReferenceA value = 1;
}
message MyMessageBReferenceA {
required MyMessageAReferenceB value = 1;
}
// issue 19 - negative enum values
enum NegativeEnum {
NEGATIVE_ENUM_ZERO = 0;
FiveBelow = -5;
MinusOne = -1;
Zero = 0;
}
message NegativeEnumMessage {
optional NegativeEnum value = 1;
repeated NegativeEnum values = 2;
NegativeEnum value = 1;
repeated NegativeEnum values = 2 [packed = false];
repeated NegativeEnum packed_values = 3 [packed=true];
}
......@@ -121,21 +52,22 @@ message DeprecatedChild {
}
enum DeprecatedEnum {
DEPRECATED_ZERO = 0;
one = 1;
}
message DeprecatedFieldsMessage {
optional int32 PrimitiveValue = 1 [deprecated = true];
int32 PrimitiveValue = 1 [deprecated = true];
repeated int32 PrimitiveArray = 2 [deprecated = true];
optional DeprecatedChild MessageValue = 3 [deprecated = true];
DeprecatedChild MessageValue = 3 [deprecated = true];
repeated DeprecatedChild MessageArray = 4 [deprecated = true];
optional DeprecatedEnum EnumValue = 5 [deprecated = true];
DeprecatedEnum EnumValue = 5 [deprecated = true];
repeated DeprecatedEnum EnumArray = 6 [deprecated = true];
}
// Issue 45: http://code.google.com/p/protobuf-csharp-port/issues/detail?id=45
message ItemField {
optional int32 item = 1;
int32 item = 1;
}
......@@ -36,6 +36,7 @@
using System;
using System.IO;
using Google.Protobuf;
namespace Google.ProtocolBuffers.Examples.AddressBook
{
......@@ -46,7 +47,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook
/// </summary>
private static Person PromptForAddress(TextReader input, TextWriter output)
{
Person.Builder person = Person.CreateBuilder();
Person person = new Person();
output.Write("Enter person ID: ");
person.Id = int.Parse(input.ReadLine());
......@@ -70,8 +71,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook
break;
}
Person.Types.PhoneNumber.Builder phoneNumber =
Person.Types.PhoneNumber.CreateBuilder().SetNumber(number);
Person.Types.PhoneNumber phoneNumber = new Person.Types.PhoneNumber { Number = number };
output.Write("Is this a mobile, home, or work phone? ");
String type = input.ReadLine();
......@@ -91,9 +91,9 @@ namespace Google.ProtocolBuffers.Examples.AddressBook
break;
}
person.AddPhone(phoneNumber);
person.Phone.Add(phoneNumber);
}
return person.Build();
return person;
}
/// <summary>
......@@ -108,27 +108,28 @@ namespace Google.ProtocolBuffers.Examples.AddressBook
return -1;
}
AddressBook.Builder addressBook = AddressBook.CreateBuilder();
AddressBook addressBook;
if (File.Exists(args[0]))
{
using (Stream file = File.OpenRead(args[0]))
{
addressBook.MergeFrom(file);
addressBook = AddressBook.Parser.ParseFrom(file);
}
}
else
{
Console.WriteLine("{0}: File not found. Creating a new file.", args[0]);
addressBook = new AddressBook();
}
// Add an address.
addressBook.AddPerson(PromptForAddress(Console.In, Console.Out));
addressBook.Person.Add(PromptForAddress(Console.In, Console.Out));
// Write the new address book back to disk.
using (Stream output = File.OpenWrite(args[0]))
{
addressBook.Build().WriteTo(output);
addressBook.WriteTo(output);
}
return 0;
}
......
This diff is collapsed.
......@@ -46,16 +46,16 @@ namespace Google.ProtocolBuffers.Examples.AddressBook
/// </summary>
private static void Print(AddressBook addressBook)
{
foreach (Person person in addressBook.PersonList)
foreach (Person person in addressBook.Person)
{
Console.WriteLine("Person ID: {0}", person.Id);
Console.WriteLine(" Name: {0}", person.Name);
if (person.HasEmail)
if (person.Email != "")
{
Console.WriteLine(" E-mail address: {0}", person.Email);
}
foreach (Person.Types.PhoneNumber phoneNumber in person.PhoneList)
foreach (Person.Types.PhoneNumber phoneNumber in person.Phone)
{
switch (phoneNumber.Type)
{
......@@ -94,7 +94,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook
// Read the existing address book.
using (Stream stream = File.OpenRead(args[0]))
{
AddressBook addressBook = AddressBook.ParseFrom(stream);
AddressBook addressBook = AddressBook.Parser.ParseFrom(stream);
Print(addressBook);
}
return 0;
......
using System;
using Google.Protobuf;
using System;
using System.IO;
namespace Google.ProtocolBuffers.Examples.AddressBook
......@@ -8,37 +9,31 @@ namespace Google.ProtocolBuffers.Examples.AddressBook
private static void Main()
{
byte[] bytes;
//Create a builder to start building a message
Person.Builder newContact = Person.CreateBuilder();
//Set the primitive properties
newContact.SetId(1)
.SetName("Foo")
.SetEmail("foo@bar");
//Now add an item to a list (repeating) field
newContact.AddPhone(
//Create the child message inline
Person.Types.PhoneNumber.CreateBuilder().SetNumber("555-1212").Build()
);
//Now build the final message:
Person person = newContact.Build();
//The builder is no longer valid (at least not now, scheduled for 2.4):
newContact = null;
// Create a new person
Person person = new Person
{
Id = 1,
Name = "Foo",
Email = "foo@bar",
Phone = { new Person.Types.PhoneNumber { Number = "555-1212" } }
};
using (MemoryStream stream = new MemoryStream())
{
//Save the person to a stream
// Save the person to a stream
person.WriteTo(stream);
bytes = stream.ToArray();
}
//Create another builder, merge the byte[], and build the message:
Person copy = Person.CreateBuilder().MergeFrom(bytes).Build();
Person copy = Person.Parser.ParseFrom(bytes);
//A more streamlined approach might look like this:
bytes = AddressBook.CreateBuilder().AddPerson(copy).Build().ToByteArray();
//And read the address book back again
AddressBook restored = AddressBook.CreateBuilder().MergeFrom(bytes).Build();
//The message performs a deep-comparison on equality:
if (restored.PersonCount != 1 || !person.Equals(restored.PersonList[0]))
// A more streamlined approach might look like this:
bytes = copy.ToByteArray();
// And read the address book back again
AddressBook restored = AddressBook.Parser.ParseFrom(bytes);
// The message performs a deep-comparison on equality:
if (restored.Person.Count != 1 || !person.Equals(restored.Person[0]))
{
throw new ApplicationException("There is a bad person in here!");
}
}
}
}
\ No newline at end of file
......@@ -38,6 +38,8 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Google.Protobuf;
using Google.Protobuf.Descriptors;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.ProtoMunge
......
using System;
using System.Globalization;
using System.Xml;
namespace Google.ProtocolBuffers.Serialization
{
/// <summary>
/// Provides a base class for text-parsing readers
/// </summary>
public abstract class AbstractTextReader : AbstractReader
{
/// <summary> Constructs a new reader </summary>
protected AbstractTextReader() { }
/// <summary>
/// Reads a typed field as a string
/// </summary>
protected abstract bool ReadAsText(ref string textValue, Type type);
/// <summary>
/// Returns true if it was able to read a String from the input
/// </summary>
protected override bool Read(ref string value)
{
string text = null;
if (ReadAsText(ref text, typeof(string)))
{
value = text;
return true;
}
return false;
}
/// <summary>
/// Returns true if it was able to read a Boolean from the input
/// </summary>
protected override bool Read(ref bool value)
{
string text = null;
if (ReadAsText(ref text, typeof(bool)))
{
value = XmlConvert.ToBoolean(text);
return true;
}
return false;
}
/// <summary>
/// Returns true if it was able to read a Int32 from the input
/// </summary>
protected override bool Read(ref int value)
{
string text = null;
if (ReadAsText(ref text, typeof(int)))
{
value = XmlConvert.ToInt32(text);
return true;
}
return false;
}
/// <summary>
/// Returns true if it was able to read a UInt32 from the input
/// </summary>
protected override bool Read(ref uint value)
{
string text = null;
if (ReadAsText(ref text, typeof(uint)))
{
value = XmlConvert.ToUInt32(text);
return true;
}
return false;
}
/// <summary>
/// Returns true if it was able to read a Int64 from the input
/// </summary>
protected override bool Read(ref long value)
{
string text = null;
if (ReadAsText(ref text, typeof(long)))
{
value = XmlConvert.ToInt64(text);
return true;
}
return false;
}
/// <summary>
/// Returns true if it was able to read a UInt64 from the input
/// </summary>
protected override bool Read(ref ulong value)
{
string text = null;
if (ReadAsText(ref text, typeof(ulong)))
{
value = XmlConvert.ToUInt64(text);
return true;
}
return false;
}
/// <summary>
/// Returns true if it was able to read a Single from the input
/// </summary>
protected override bool Read(ref float value)
{
string text = null;
if (ReadAsText(ref text, typeof(float)))
{
value = XmlConvert.ToSingle(text);
return true;
}
return false;
}
/// <summary>
/// Returns true if it was able to read a Double from the input
/// </summary>
protected override bool Read(ref double value)
{
string text = null;
if (ReadAsText(ref text, typeof(double)))
{
value = XmlConvert.ToDouble(text);
return true;
}
return false;
}
/// <summary>
/// Provides decoding of bytes read from the input stream
/// </summary>
protected virtual ByteString DecodeBytes(string bytes)
{
return ByteString.FromBase64(bytes);
}
/// <summary>
/// Returns true if it was able to read a ByteString from the input
/// </summary>
protected override bool Read(ref ByteString value)
{
string text = null;
if (ReadAsText(ref text, typeof(ByteString)))
{
value = DecodeBytes(text);
return true;
}
return false;
}
/// <summary>
/// returns true if it was able to read a single value into the value reference. The value
/// stored may be of type System.String, System.Int32, or an IEnumLite from the IEnumLiteMap.
/// </summary>
protected override bool ReadEnum(ref object value)
{
string text = null;
if (ReadAsText(ref text, typeof(Enum)))
{
int number;
if (FrameworkPortability.TryParseInt32(text, NumberStyles.Integer, FrameworkPortability.InvariantCulture, out number))
{
value = number;
return true;
}
value = text;
return true;
}
return false;
}
}
}
\ No newline at end of file
using System;
using System.Xml;
namespace Google.ProtocolBuffers.Serialization
{
/// <summary>
/// Provides a base class for text writers
/// </summary>
public abstract class AbstractTextWriter : AbstractWriter
{
/// <summary>
/// Encodes raw bytes to be written to the stream
/// </summary>
protected virtual string EncodeBytes(ByteString bytes)
{
return bytes.ToBase64();
}
/// <summary>
/// Writes a typed field as a text value
/// </summary>
protected abstract void WriteAsText(string field, string textValue, object typedValue);
/// <summary>
/// Writes a String value
/// </summary>
protected override void Write(string field, string value)
{
WriteAsText(field, value, value);
}
/// <summary>
/// Writes a Boolean value
/// </summary>
protected override void Write(string field, bool value)
{
WriteAsText(field, XmlConvert.ToString(value), value);
}
/// <summary>
/// Writes a Int32 value
/// </summary>
protected override void Write(string field, int value)
{
WriteAsText(field, XmlConvert.ToString(value), value);
}
/// <summary>
/// Writes a UInt32 value
/// </summary>
protected override void Write(string field, uint value)
{
WriteAsText(field, XmlConvert.ToString(value), value);
}
/// <summary>
/// Writes a Int64 value
/// </summary>
protected override void Write(string field, long value)
{
WriteAsText(field, XmlConvert.ToString(value), value);
}
/// <summary>
/// Writes a UInt64 value
/// </summary>
protected override void Write(string field, ulong value)
{
WriteAsText(field, XmlConvert.ToString(value), value);
}
/// <summary>
/// Writes a Single value
/// </summary>
protected override void Write(string field, float value)
{
WriteAsText(field, XmlConvert.ToString(value), value);
}
/// <summary>
/// Writes a Double value
/// </summary>
protected override void Write(string field, double value)
{
WriteAsText(field, XmlConvert.ToString(value), value);
}
/// <summary>
/// Writes a set of bytes
/// </summary>
protected override void Write(string field, ByteString value)
{
WriteAsText(field, EncodeBytes(value), value);
}
/// <summary>
/// Writes a System.Enum by the numeric and textual value
/// </summary>
protected override void WriteEnum(string field, int number, string name)
{
WriteAsText(field, name, number);
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Globalization;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.Serialization
{
/// <summary>
/// Allows reading messages from a name/value dictionary
/// </summary>
public class DictionaryReader : AbstractReader
{
private readonly IEnumerator<KeyValuePair<string, object>> _input;
private bool _ready;
/// <summary>
/// Creates a dictionary reader from an enumeration of KeyValuePair data, like an IDictionary
/// </summary>
public DictionaryReader(IEnumerable<KeyValuePair<string, object>> input)
{
_input = input.GetEnumerator();
_ready = _input.MoveNext();
}
/// <summary>
/// No-op
/// </summary>
public override void ReadMessageStart()
{ }
/// <summary>
/// No-op
/// </summary>
public override void ReadMessageEnd()
{ }
/// <summary>
/// Merges the contents of stream into the provided message builder
/// </summary>
public override TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)
{
builder.WeakMergeFrom(this, registry);
return builder;
}
/// <summary>
/// Peeks at the next field in the input stream and returns what information is available.
/// </summary>
/// <remarks>
/// This may be called multiple times without actually reading the field. Only after the field
/// is either read, or skipped, should PeekNext return a different value.
/// </remarks>
protected override bool PeekNext(out string field)
{
field = _ready ? _input.Current.Key : null;
return _ready;
}
/// <summary>
/// Causes the reader to skip past this field
/// </summary>
protected override void Skip()
{
_ready = _input.MoveNext();
}
private bool GetValue<T>(ref T value)
{
if (!_ready)
{
return false;
}
object obj = _input.Current.Value;
if (obj is T)
{
value = (T) obj;
}
else
{
try
{
if (obj is IConvertible)
{
value = (T)Convert.ChangeType(obj, typeof(T), FrameworkPortability.InvariantCulture);
}
else
{
value = (T) obj;
}
}
catch
{
_ready = _input.MoveNext();
return false;
}
}
_ready = _input.MoveNext();
return true;
}
/// <summary>
/// Returns true if it was able to read a Boolean from the input
/// </summary>
protected override bool Read(ref bool value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a Int32 from the input
/// </summary>
protected override bool Read(ref int value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a UInt32 from the input
/// </summary>
protected override bool Read(ref uint value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a Int64 from the input
/// </summary>
protected override bool Read(ref long value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a UInt64 from the input
/// </summary>
protected override bool Read(ref ulong value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a Single from the input
/// </summary>
protected override bool Read(ref float value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a Double from the input
/// </summary>
protected override bool Read(ref double value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a String from the input
/// </summary>
protected override bool Read(ref string value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a ByteString from the input
/// </summary>
protected override bool Read(ref ByteString value)
{
byte[] rawbytes = null;
if (GetValue(ref rawbytes))
{
value = ByteString.CopyFrom(rawbytes);
return true;
}
return false;
}
/// <summary>
/// returns true if it was able to read a single value into the value reference. The value
/// stored may be of type System.String, System.Int32, or an IEnumLite from the IEnumLiteMap.
/// </summary>
protected override bool ReadEnum(ref object value)
{
return GetValue(ref value);
}
/// <summary>
/// Merges the input stream into the provided IBuilderLite
/// </summary>
protected override bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry)
{
IDictionary<string, object> values = null;
if (GetValue(ref values))
{
new DictionaryReader(values).Merge(builder, registry);
return true;
}
return false;
}
public override bool ReadArray<T>(FieldType type, string field, ICollection<T> items)
{
object[] array = null;
if (GetValue(ref array))
{
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;
}
public override bool ReadEnumArray(string field, ICollection<object> items)
{
object[] array = null;
if (GetValue(ref array))
{
foreach (object item in array)
{
items.Add(item);
}
return true;
}
return false;
}
public override bool ReadMessageArray<T>(string field, ICollection<T> items, IMessageLite messageType,
ExtensionRegistry registry)
{
object[] array = null;
if (GetValue(ref array))
{
foreach (IDictionary<string, object> item in array)
{
IBuilderLite builder = messageType.WeakCreateBuilderForType();
new DictionaryReader(item).Merge(builder);
items.Add((T) builder.WeakBuild());
}
return true;
}
return false;
}
public override bool ReadGroupArray<T>(string field, ICollection<T> items, IMessageLite messageType,
ExtensionRegistry registry)
{
return ReadMessageArray(field, items, messageType, registry);
}
}
}
\ No newline at end of file
using System;
using System.Collections;
using System.Collections.Generic;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.Serialization
{
/// <summary>
/// Allows writing messages to a name/value dictionary
/// </summary>
public class DictionaryWriter : AbstractWriter
{
private readonly IDictionary<string, object> _output;
/// <summary>
/// Constructs a writer using a new dictionary
/// </summary>
public DictionaryWriter()
: this(new Dictionary<string, object>(StringComparer.Ordinal))
{
}
/// <summary>
/// Constructs a writer using an existing dictionary
/// </summary>
public DictionaryWriter(IDictionary<string, object> output)
{
ThrowHelper.ThrowIfNull(output, "output");
_output = output;
}
/// <summary>
/// Creates the dictionary instance for a child message.
/// </summary>
protected virtual DictionaryWriter Create()
{
return new DictionaryWriter();
}
/// <summary>
/// Accesses the dictionary that is backing this writer
/// </summary>
public IDictionary<string, object> ToDictionary()
{
return _output;
}
/// <summary>
/// Writes the message to the the formatted stream.
/// </summary>
public override void WriteMessage(IMessageLite message)
{
message.WriteTo(this);
}
/// <summary>
/// No-op
/// </summary>
public override void WriteMessageStart()
{ }
/// <summary>
/// No-op
/// </summary>
public override void WriteMessageEnd()
{ }
/// <summary>
/// Writes a Boolean value
/// </summary>
protected override void Write(string field, bool value)
{
_output[field] = value;
}
/// <summary>
/// Writes a Int32 value
/// </summary>
protected override void Write(string field, int value)
{
_output[field] = value;
}
/// <summary>
/// Writes a UInt32 value
/// </summary>
protected override void Write(string field, uint value)
{
_output[field] = value;
}
/// <summary>
/// Writes a Int64 value
/// </summary>
protected override void Write(string field, long value)
{
_output[field] = value;
}
/// <summary>
/// Writes a UInt64 value
/// </summary>
protected override void Write(string field, ulong value)
{
_output[field] = value;
}
/// <summary>
/// Writes a Single value
/// </summary>
protected override void Write(string field, float value)
{
_output[field] = value;
}
/// <summary>
/// Writes a Double value
/// </summary>
protected override void Write(string field, double value)
{
_output[field] = value;
}
/// <summary>
/// Writes a String value
/// </summary>
protected override void Write(string field, string value)
{
_output[field] = value;
}
/// <summary>
/// Writes a set of bytes
/// </summary>
protected override void Write(string field, ByteString value)
{
_output[field] = value.ToByteArray();
}
/// <summary>
/// Writes a message or group as a field
/// </summary>
protected override void WriteMessageOrGroup(string field, IMessageLite message)
{
DictionaryWriter writer = Create();
writer.WriteMessage(message);
_output[field] = writer.ToDictionary();
}
/// <summary>
/// Writes a System.Enum by the numeric and textual value
/// </summary>
protected override void WriteEnum(string field, int number, string name)
{
_output[field] = number;
}
/// <summary>
/// Writes an array of field values
/// </summary>
protected override void WriteArray(FieldType fieldType, string field, IEnumerable items)
{
List<object> objects = new List<object>();
foreach (object o in items)
{
switch (fieldType)
{
case FieldType.Group:
case FieldType.Message:
{
DictionaryWriter writer = Create();
writer.WriteMessage((IMessageLite) o);
objects.Add(writer.ToDictionary());
}
break;
case FieldType.Bytes:
objects.Add(((ByteString) o).ToByteArray());
break;
case FieldType.Enum:
if (o is IEnumLite)
{
objects.Add(((IEnumLite) o).Number);
}
else
{
objects.Add((int) o);
}
break;
default:
objects.Add(o);
break;
}
}
_output[field] = objects.ToArray();
}
}
}
\ No newline at end of file
using System;
using System.Text;
using System.IO;
using System.Xml;
using Google.ProtocolBuffers.Serialization;
using Google.ProtocolBuffers.Serialization.Http;
namespace Google.ProtocolBuffers
{
/// <summary>
/// Extension methods for using serializers on instances of IMessageLite/IBuilderLite
/// </summary>
public static class Extensions
{
#region IMessageLite Extension
/// <summary>
/// Serializes the message to JSON text. This is a trivial wrapper
/// around Serialization.JsonFormatWriter.WriteMessage.
/// </summary>
public static string ToJson(
#if !NOEXTENSIONS
this
#endif
IMessageLite message)
{
JsonFormatWriter w = JsonFormatWriter.CreateInstance();
w.WriteMessage(message);
return w.ToString();
}
/// <summary>
/// Serializes the message to XML text. This is a trivial wrapper
/// around Serialization.XmlFormatWriter.WriteMessage.
/// </summary>
public static string ToXml(
#if !NOEXTENSIONS
this
#endif
IMessageLite message)
{
StringWriter w = new StringWriter(new StringBuilder(4096));
XmlFormatWriter.CreateInstance(w).WriteMessage(message);
return w.ToString();
}
/// <summary>
/// Serializes the message to XML text using the element name provided.
/// This is a trivial wrapper around Serialization.XmlFormatWriter.WriteMessage.
/// </summary>
public static string ToXml(
#if !NOEXTENSIONS
this
#endif
IMessageLite message, string rootElementName)
{
StringWriter w = new StringWriter(new StringBuilder(4096));
XmlFormatWriter.CreateInstance(w).WriteMessage(rootElementName, message);
return w.ToString();
}
/// <summary>
/// Writes the message instance to the stream using the content type provided
/// </summary>
/// <param name="message">An instance of a message</param>
/// <param name="options">Options specific to writing this message and/or content type</param>
/// <param name="contentType">The mime type of the content to be written</param>
/// <param name="output">The stream to write the message to</param>
public static void WriteTo(
#if !NOEXTENSIONS
this
#endif
IMessageLite message, MessageFormatOptions options, string contentType, Stream output)
{
ICodedOutputStream codedOutput = MessageFormatFactory.CreateOutputStream(options, contentType, output);
// Output the appropriate message preamble
codedOutput.WriteMessageStart();
// Write the message content to the output
message.WriteTo(codedOutput);
// Write the closing message fragment
codedOutput.WriteMessageEnd();
codedOutput.Flush();
}
#endregion
#region IBuilderLite Extensions
/// <summary>
/// Merges a JSON object into this builder and returns
/// </summary>
public static TBuilder MergeFromJson<TBuilder>(
#if !NOEXTENSIONS
this
#endif
TBuilder builder, string jsonText) where TBuilder : IBuilderLite
{
return JsonFormatReader.CreateInstance(jsonText)
.Merge(builder);
}
/// <summary>
/// Merges a JSON object into this builder and returns
/// </summary>
public static TBuilder MergeFromJson<TBuilder>(
#if !NOEXTENSIONS
this
#endif
TBuilder builder, TextReader reader) where TBuilder : IBuilderLite
{
return MergeFromJson(builder, reader, ExtensionRegistry.Empty);
}
/// <summary>
/// Merges a JSON object into this builder using the extensions provided and returns
/// </summary>
public static TBuilder MergeFromJson<TBuilder>(
#if !NOEXTENSIONS
this
#endif
TBuilder builder, TextReader reader, ExtensionRegistry extensionRegistry) where TBuilder : IBuilderLite
{
return JsonFormatReader.CreateInstance(reader)
.Merge(builder, extensionRegistry);
}
/// <summary>
/// Merges an XML object into this builder and returns
/// </summary>
public static TBuilder MergeFromXml<TBuilder>(
#if !NOEXTENSIONS
this
#endif
TBuilder builder, XmlReader reader) where TBuilder : IBuilderLite
{
return MergeFromXml(builder, XmlFormatReader.DefaultRootElementName, reader, ExtensionRegistry.Empty);
}
/// <summary>
/// Merges an XML object into this builder and returns
/// </summary>
public static TBuilder MergeFromXml<TBuilder>(
#if !NOEXTENSIONS
this
#endif
TBuilder builder, string rootElementName, XmlReader reader) where TBuilder : IBuilderLite
{
return MergeFromXml(builder, rootElementName, reader, ExtensionRegistry.Empty);
}
/// <summary>
/// Merges an XML object into this builder using the extensions provided and returns
/// </summary>
public static TBuilder MergeFromXml<TBuilder>(
#if !NOEXTENSIONS
this
#endif
TBuilder builder, string rootElementName, XmlReader reader,
ExtensionRegistry extensionRegistry) where TBuilder : IBuilderLite
{
return XmlFormatReader.CreateInstance(reader)
.Merge(rootElementName, builder, extensionRegistry);
}
/// <summary>
/// Merges the message from the input stream based on the contentType provided
/// </summary>
/// <typeparam name="TBuilder">A type derived from IBuilderLite</typeparam>
/// <param name="builder">An instance of a message builder</param>
/// <param name="options">Options specific to reading this message and/or content type</param>
/// <param name="contentType">The mime type of the input stream content</param>
/// <param name="input">The stream to read the message from</param>
/// <returns>The same builder instance that was supplied in the builder parameter</returns>
public static TBuilder MergeFrom<TBuilder>(
#if !NOEXTENSIONS
this
#endif
TBuilder builder, MessageFormatOptions options, string contentType, Stream input) where TBuilder : IBuilderLite
{
ICodedInputStream codedInput = MessageFormatFactory.CreateInputStream(options, contentType, input);
codedInput.ReadMessageStart();
builder.WeakMergeFrom(codedInput, options.ExtensionRegistry);
codedInput.ReadMessageEnd();
return builder;
}
#endregion
}
}
using System;
using System.IO;
using System.Text;
namespace Google.ProtocolBuffers.Serialization.Http
{
/// <summary>
/// Allows reading messages from a name/value dictionary
/// </summary>
public class FormUrlEncodedReader : AbstractTextReader
{
private readonly TextReader _input;
private string _fieldName, _fieldValue;
private bool _ready;
/// <summary>
/// Creates a dictionary reader from an enumeration of KeyValuePair data, like an IDictionary
/// </summary>
FormUrlEncodedReader(TextReader input)
{
_input = input;
int ch = input.Peek();
if (ch == '?')
{
input.Read();
}
_ready = ReadNext();
}
#region CreateInstance overloads
/// <summary>
/// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message.
/// </summary>
public static FormUrlEncodedReader CreateInstance(Stream stream)
{
return new FormUrlEncodedReader(new StreamReader(stream, Encoding.UTF8, false));
}
/// <summary>
/// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message.
/// </summary>
public static FormUrlEncodedReader CreateInstance(byte[] bytes)
{
return new FormUrlEncodedReader(new StreamReader(new MemoryStream(bytes, false), Encoding.UTF8, false));
}
/// <summary>
/// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message.
/// </summary>
public static FormUrlEncodedReader CreateInstance(string text)
{
return new FormUrlEncodedReader(new StringReader(text));
}
/// <summary>
/// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message.
/// </summary>
public static FormUrlEncodedReader CreateInstance(TextReader input)
{
return new FormUrlEncodedReader(input);
}
#endregion
private bool ReadNext()
{
StringBuilder field = new StringBuilder(32);
StringBuilder value = new StringBuilder(64);
int ch;
while (-1 != (ch = _input.Read()) && ch != '=' && ch != '&')
{
field.Append((char)ch);
}
if (ch != -1 && ch != '&')
{
while (-1 != (ch = _input.Read()) && ch != '&')
{
value.Append((char)ch);
}
}
_fieldName = field.ToString();
_fieldValue = Uri.UnescapeDataString(value.Replace('+', ' ').ToString());
return !String.IsNullOrEmpty(_fieldName);
}
/// <summary>
/// No-op
/// </summary>
public override void ReadMessageStart()
{ }
/// <summary>
/// No-op
/// </summary>
public override void ReadMessageEnd()
{ }
/// <summary>
/// Merges the contents of stream into the provided message builder
/// </summary>
public override TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)
{
builder.WeakMergeFrom(this, registry);
return builder;
}
/// <summary>
/// Causes the reader to skip past this field
/// </summary>
protected override void Skip()
{
_ready = ReadNext();
}
/// <summary>
/// Peeks at the next field in the input stream and returns what information is available.
/// </summary>
/// <remarks>
/// This may be called multiple times without actually reading the field. Only after the field
/// is either read, or skipped, should PeekNext return a different value.
/// </remarks>
protected override bool PeekNext(out string field)
{
field = _ready ? _fieldName : null;
return field != null;
}
/// <summary>
/// Returns true if it was able to read a String from the input
/// </summary>
protected override bool ReadAsText(ref string value, Type typeInfo)
{
if (_ready)
{
value = _fieldValue;
_ready = ReadNext();
return true;
}
return false;
}
/// <summary>
/// It's unlikely this will work for anything but text data as bytes UTF8 are transformed to text and back to bytes
/// </summary>
protected override ByteString DecodeBytes(string bytes)
{ return ByteString.CopyFromUtf8(bytes); }
/// <summary>
/// Not Supported
/// </summary>
public override bool ReadGroup(IBuilderLite value, ExtensionRegistry registry)
{ throw new NotSupportedException(); }
/// <summary>
/// Not Supported
/// </summary>
protected override bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry)
{ throw new NotSupportedException(); }
}
}
\ No newline at end of file
using System;
using System.IO;
using System.Xml;
using System.Text;
namespace Google.ProtocolBuffers.Serialization.Http
{
/// <summary>
/// Extensions and helpers to abstract the reading/writing of messages by a client-specified content type.
/// </summary>
public static class MessageFormatFactory
{
/// <summary>
/// Constructs an ICodedInputStream from the input stream based on the contentType provided
/// </summary>
/// <param name="options">Options specific to reading this message and/or content type</param>
/// <param name="contentType">The mime type of the input stream content</param>
/// <param name="input">The stream to read the message from</param>
/// <returns>The ICodedInputStream that can be given to the IBuilder.MergeFrom(...) method</returns>
public static ICodedInputStream CreateInputStream(MessageFormatOptions options, string contentType, Stream input)
{
ICodedInputStream codedInput = ContentTypeToInputStream(contentType, options, input);
if (codedInput is XmlFormatReader)
{
XmlFormatReader reader = (XmlFormatReader)codedInput;
reader.RootElementName = options.XmlReaderRootElementName;
reader.Options = options.XmlReaderOptions;
}
return codedInput;
}
/// <summary>
/// Writes the message instance to the stream using the content type provided
/// </summary>
/// <param name="options">Options specific to writing this message and/or content type</param>
/// <param name="contentType">The mime type of the content to be written</param>
/// <param name="output">The stream to write the message to</param>
/// <remarks> If you do not dispose of ICodedOutputStream some formats may yield incomplete output </remarks>
public static ICodedOutputStream CreateOutputStream(MessageFormatOptions options, string contentType, Stream output)
{
ICodedOutputStream codedOutput = ContentTypeToOutputStream(contentType, options, output);
if (codedOutput is JsonFormatWriter)
{
JsonFormatWriter writer = (JsonFormatWriter)codedOutput;
if (options.FormattedOutput)
{
writer.Formatted();
}
}
else if (codedOutput is XmlFormatWriter)
{
XmlFormatWriter writer = (XmlFormatWriter)codedOutput;
if (options.FormattedOutput)
{
XmlWriterSettings settings = new XmlWriterSettings()
{
CheckCharacters = false,
NewLineHandling = NewLineHandling.Entitize,
OmitXmlDeclaration = true,
Encoding = new UTF8Encoding(false),
Indent = true,
IndentChars = " ",
};
// Don't know how else to change xml writer options?
codedOutput = writer = XmlFormatWriter.CreateInstance(XmlWriter.Create(output, settings));
}
writer.RootElementName = options.XmlWriterRootElementName;
writer.Options = options.XmlWriterOptions;
}
return codedOutput;
}
private static ICodedInputStream ContentTypeToInputStream(string contentType, MessageFormatOptions options, Stream input)
{
contentType = (contentType ?? String.Empty).Split(';')[0].Trim();
CodedInputBuilder factory;
if(!options.MimeInputTypesReadOnly.TryGetValue(contentType, out factory) || factory == null)
{
if(String.IsNullOrEmpty(options.DefaultContentType) ||
!options.MimeInputTypesReadOnly.TryGetValue(options.DefaultContentType, out factory) || factory == null)
{
throw new ArgumentOutOfRangeException("contentType");
}
}
return factory(input);
}
private static ICodedOutputStream ContentTypeToOutputStream(string contentType, MessageFormatOptions options, Stream output)
{
contentType = (contentType ?? String.Empty).Split(';')[0].Trim();
CodedOutputBuilder factory;
if (!options.MimeOutputTypesReadOnly.TryGetValue(contentType, out factory) || factory == null)
{
if (String.IsNullOrEmpty(options.DefaultContentType) ||
!options.MimeOutputTypesReadOnly.TryGetValue(options.DefaultContentType, out factory) || factory == null)
{
throw new ArgumentOutOfRangeException("contentType");
}
}
return factory(output);
}
}
}
\ No newline at end of file
using System;
using System.IO;
using System.Collections.Generic;
using Google.ProtocolBuffers.Collections;
namespace Google.ProtocolBuffers.Serialization.Http
{
/// <summary>
/// A delegate used to specify a method that constructs an ICodedInputStream from a .NET Stream.
/// </summary>
public delegate ICodedInputStream CodedInputBuilder(Stream stream);
/// <summary>
/// A delegate used to specify a method that constructs an ICodedOutputStream from a .NET Stream.
/// </summary>
public delegate ICodedOutputStream CodedOutputBuilder(Stream stream);
/// <summary>
/// Defines control information for the various formatting used with HTTP services
/// </summary>
public class MessageFormatOptions
{
/// <summary>The mime type for xml content</summary>
/// <remarks>Other valid xml mime types include: application/binary, application/x-protobuf</remarks>
public const string ContentTypeProtoBuffer = "application/vnd.google.protobuf";
/// <summary>The mime type for xml content</summary>
/// <remarks>Other valid xml mime types include: text/xml</remarks>
public const string ContentTypeXml = "application/xml";
/// <summary>The mime type for json content</summary>
/// <remarks>
/// Other valid json mime types include: application/json, application/x-json,
/// application/x-javascript, text/javascript, text/x-javascript, text/x-json, text/json
/// </remarks>
public const string ContentTypeJson = "application/json";
/// <summary>The mime type for query strings and x-www-form-urlencoded content</summary>
/// <remarks>This mime type is input-only</remarks>
public const string ContentFormUrlEncoded = "application/x-www-form-urlencoded";
/// <summary>
/// Default mime-type handling for input
/// </summary>
private static readonly IDictionary<string, CodedInputBuilder> MimeInputDefaults =
new ReadOnlyDictionary<string, CodedInputBuilder>(
new Dictionary<string, CodedInputBuilder>(StringComparer.OrdinalIgnoreCase)
{
{"application/json", JsonFormatReader.CreateInstance},
{"application/x-json", JsonFormatReader.CreateInstance},
{"application/x-javascript", JsonFormatReader.CreateInstance},
{"text/javascript", JsonFormatReader.CreateInstance},
{"text/x-javascript", JsonFormatReader.CreateInstance},
{"text/x-json", JsonFormatReader.CreateInstance},
{"text/json", JsonFormatReader.CreateInstance},
{"text/xml", XmlFormatReader.CreateInstance},
{"application/xml", XmlFormatReader.CreateInstance},
{"application/binary", CodedInputStream.CreateInstance},
{"application/x-protobuf", CodedInputStream.CreateInstance},
{"application/vnd.google.protobuf", CodedInputStream.CreateInstance},
{"application/x-www-form-urlencoded", FormUrlEncodedReader.CreateInstance},
}
);
/// <summary>
/// Default mime-type handling for output
/// </summary>
private static readonly IDictionary<string, CodedOutputBuilder> MimeOutputDefaults =
new ReadOnlyDictionary<string, CodedOutputBuilder>(
new Dictionary<string, CodedOutputBuilder>(StringComparer.OrdinalIgnoreCase)
{
{"application/json", JsonFormatWriter.CreateInstance},
{"application/x-json", JsonFormatWriter.CreateInstance},
{"application/x-javascript", JsonFormatWriter.CreateInstance},
{"text/javascript", JsonFormatWriter.CreateInstance},
{"text/x-javascript", JsonFormatWriter.CreateInstance},
{"text/x-json", JsonFormatWriter.CreateInstance},
{"text/json", JsonFormatWriter.CreateInstance},
{"text/xml", XmlFormatWriter.CreateInstance},
{"application/xml", XmlFormatWriter.CreateInstance},
{"application/binary", CodedOutputStream.CreateInstance},
{"application/x-protobuf", CodedOutputStream.CreateInstance},
{"application/vnd.google.protobuf", CodedOutputStream.CreateInstance},
}
);
private string _defaultContentType;
private string _xmlReaderRootElementName;
private string _xmlWriterRootElementName;
private ExtensionRegistry _extensionRegistry;
private Dictionary<string, CodedInputBuilder> _mimeInputTypes;
private Dictionary<string, CodedOutputBuilder> _mimeOutputTypes;
/// <summary> Provides access to modify the mime-type input stream construction </summary>
public IDictionary<string, CodedInputBuilder> MimeInputTypes
{
get
{
return _mimeInputTypes ??
(_mimeInputTypes = new Dictionary<string, CodedInputBuilder>(
MimeInputDefaults, StringComparer.OrdinalIgnoreCase));
}
}
/// <summary> Provides access to modify the mime-type input stream construction </summary>
public IDictionary<string, CodedOutputBuilder> MimeOutputTypes
{
get
{
return _mimeOutputTypes ??
(_mimeOutputTypes = new Dictionary<string, CodedOutputBuilder>(
MimeOutputDefaults, StringComparer.OrdinalIgnoreCase));
}
}
internal IDictionary<string, CodedInputBuilder> MimeInputTypesReadOnly
{ get { return _mimeInputTypes ?? MimeInputDefaults; } }
internal IDictionary<string, CodedOutputBuilder> MimeOutputTypesReadOnly
{ get { return _mimeOutputTypes ?? MimeOutputDefaults; } }
/// <summary>
/// The default content type to use if the input type is null or empty. If this
/// value is not supplied an ArgumentOutOfRangeException exception will be raised.
/// </summary>
public string DefaultContentType
{
get { return _defaultContentType ?? String.Empty; }
set { _defaultContentType = value; }
}
/// <summary>
/// The extension registry to use when reading messages
/// </summary>
public ExtensionRegistry ExtensionRegistry
{
get { return _extensionRegistry ?? ExtensionRegistry.Empty; }
set { _extensionRegistry = value; }
}
/// <summary>
/// The name of the xml root element when reading messages
/// </summary>
public string XmlReaderRootElementName
{
get { return _xmlReaderRootElementName ?? XmlFormatReader.DefaultRootElementName; }
set { _xmlReaderRootElementName = value; }
}
/// <summary>
/// Xml reader options
/// </summary>
public XmlReaderOptions XmlReaderOptions { get; set; }
/// <summary>
/// True to use formatted output including new-lines and default indentation
/// </summary>
public bool FormattedOutput { get; set; }
/// <summary>
/// The name of the xml root element when writing messages
/// </summary>
public string XmlWriterRootElementName
{
get { return _xmlWriterRootElementName ?? XmlFormatWriter.DefaultRootElementName; }
set { _xmlWriterRootElementName = value; }
}
/// <summary>
/// Xml writer options
/// </summary>
public XmlWriterOptions XmlWriterOptions { get; set; }
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
namespace Google.ProtocolBuffers.Serialization
{
/// <summary>
/// JsonFormatReader is used to parse Json into a message or an array of messages
/// </summary>
public class JsonFormatReader : AbstractTextReader
{
private readonly JsonCursor _input;
// The expected token that ends the current item, either ']' or '}'
private readonly Stack<int> _stopChar;
private enum ReaderState
{
Start,
BeginValue,
EndValue,
BeginObject,
BeginArray
}
private string _current;
private 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>
/// Constructs a JsonFormatReader to parse Json into a message
/// </summary>
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 = 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 == '['; }
}
/// <summary>
/// Returns an enumerator that is used to cursor over an array of messages
/// </summary>
/// <remarks>
/// This is generally used when receiving an array of messages rather than a single root message
/// </remarks>
public IEnumerable<JsonFormatReader> EnumerateArray()
{
foreach (string ignored in ForeachArrayItem(_current))
{
yield return this;
}
}
/// <summary>
/// Reads the root-message preamble specific to this formatter
/// </summary>
public override void ReadMessageStart()
{
_input.Consume('{');
_stopChar.Push('}');
_state = ReaderState.BeginObject;
}
/// <summary>
/// Reads the root-message close specific to this formatter
/// </summary>
public override void ReadMessageEnd()
{
_input.Consume((char)_stopChar.Pop());
_state = ReaderState.EndValue;
}
/// <summary>
/// Merges the contents of stream into the provided message builder
/// </summary>
public override TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)
{
ReadMessageStart();
builder.WeakMergeFrom(this, registry);
ReadMessageEnd();
return builder;
}
/// <summary>
/// Causes the reader to skip past this field
/// </summary>
protected override void Skip()
{
object temp;
_input.ReadVariant(out temp);
_state = ReaderState.EndValue;
}
/// <summary>
/// Peeks at the next field in the input stream and returns what information is available.
/// </summary>
/// <remarks>
/// This may be called multiple times without actually reading the field. Only after the field
/// is either read, or skipped, should PeekNext return a different value.
/// </remarks>
protected override bool PeekNext(out string field)
{
field = _current;
if (_state == ReaderState.BeginValue)
{
return true;
}
int next = _input.NextChar;
if (next == _stopChar.Peek())
{
return false;
}
_input.Assert(next != -1, "Unexpected end of file.");
//not sure about this yet, it will allow {, "a":true }
if (_state == ReaderState.EndValue && !_input.TryConsume(','))
{
return false;
}
field = _current = _input.ReadString();
_input.Consume(':');
_state = ReaderState.BeginValue;
return true;
}
/// <summary>
/// Returns true if it was able to read a String from the input
/// </summary>
protected override bool ReadAsText(ref string value, Type typeInfo)
{
object temp;
JsonCursor.JsType type = _input.ReadVariant(out temp);
_state = ReaderState.EndValue;
_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 == 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 == JsonCursor.JsType.Number &&
(typeInfo != typeof(double) && typeInfo != typeof(float)) &&
value.IndexOf("e", StringComparison.OrdinalIgnoreCase) > 0)
{
value = XmlConvert.ToString((long) Math.Round(XmlConvert.ToDouble(value), 0));
}
return value != null;
}
/// <summary>
/// Returns true if it was able to read a ByteString from the input
/// </summary>
protected override bool Read(ref ByteString value)
{
string bytes = null;
if (Read(ref bytes))
{
value = ByteString.FromBase64(bytes);
return true;
}
return false;
}
/// <summary>
/// Cursors through the array elements and stops at the end of the array
/// </summary>
protected override IEnumerable<string> ForeachArrayItem(string field)
{
_input.Consume('[');
_stopChar.Push(']');
_state = ReaderState.BeginArray;
while (_input.NextChar != ']')
{
_current = field;
yield return field;
if (!_input.TryConsume(','))
{
break;
}
}
_input.Consume((char) _stopChar.Pop());
_state = ReaderState.EndValue;
}
/// <summary>
/// Merges the input stream into the provided IBuilderLite
/// </summary>
protected override bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry)
{
Merge(builder, registry);
return true;
}
}
}
\ No newline at end of file
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://github.com/jskeet/dotnet-protobufs/
// Original C++/Java/Python code:
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ProtocolBuffers")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ProtocolBuffers")]
[assembly: AssemblyCopyright("Copyright © 2008")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("2.4.1.555")]
[assembly: AssemblyVersion("2.4.1.555")]
#if !NOFILEVERSION
[assembly: AssemblyFileVersion("2.4.1.555")]
#endif
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{231391AF-449C-4A39-986C-AD7F270F4750}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Google.ProtocolBuffers.Serialization</RootNamespace>
<AssemblyName>Google.ProtocolBuffers.Serialization</AssemblyName>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile92</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\keys\Google.ProtocolBuffers.snk</AssemblyOriginatorKeyFile>
<OldToolsVersion>3.5</OldToolsVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>
<DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
<NoWarn>1591, 1570, 1571, 1572, 1573, 1574</NoWarn>
<DefineConstants>DEBUG;TRACE;$(EnvironmentFlavor);$(EnvironmentTemplate)</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoStdLib>true</NoStdLib>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<IntermediateOutputPath>obj\Release\</IntermediateOutputPath>
<DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
<NoWarn>1591, 1570, 1571, 1572, 1573, 1574</NoWarn>
<DefineConstants>TRACE;$(EnvironmentFlavor);$(EnvironmentTemplate)</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoStdLib>true</NoStdLib>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" Condition="'$(TargetFrameworkVersion)' != 'v2.0'" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\ProtocolBuffers\FrameworkPortability.cs">
<Link>FrameworkPortability.cs</Link>
</Compile>
<Compile Include="Extensions.cs" />
<Compile Include="Http\FormUrlEncodedReader.cs" />
<Compile Include="Http\MessageFormatFactory.cs" />
<Compile Include="Http\MessageFormatOptions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="AbstractReader.cs" />
<Compile Include="AbstractTextReader.cs" />
<Compile Include="AbstractTextWriter.cs" />
<Compile Include="AbstractWriter.cs" />
<Compile Include="DictionaryReader.cs" />
<Compile Include="DictionaryWriter.cs" />
<Compile Include="JsonFormatReader.cs" />
<Compile Include="JsonFormatWriter.cs" />
<Compile Include="JsonTextCursor.cs" />
<Compile Include="RecursionLimitExceeded.cs" />
<Compile Include="XmlFormatReader.cs" />
<Compile Include="XmlFormatWriter.cs" />
<Compile Include="XmlReaderOptions.cs" />
<Compile Include="XmlWriterOptions.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ProtocolBuffers\ProtocolBuffers.csproj">
<Project>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</Project>
<Name>ProtocolBuffers</Name>
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.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>
-->
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{E067A59D-9D0A-4A1F-92B1-38E4457241D1}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Google.ProtocolBuffers.Serialization</RootNamespace>
<AssemblyName>Google.ProtocolBuffersLite.Serialization</AssemblyName>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile92</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\keys\Google.ProtocolBuffers.snk</AssemblyOriginatorKeyFile>
<OldToolsVersion>3.5</OldToolsVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>
<DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
<NoWarn>1591, 1570, 1571, 1572, 1573, 1574</NoWarn>
<DefineConstants>DEBUG;TRACE;LITE;$(EnvironmentFlavor);$(EnvironmentTemplate)</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoStdLib>true</NoStdLib>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<IntermediateOutputPath>obj\Release\</IntermediateOutputPath>
<DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
<NoWarn>1591, 1570, 1571, 1572, 1573, 1574</NoWarn>
<DefineConstants>TRACE;LITE;$(EnvironmentFlavor);$(EnvironmentTemplate)</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoStdLib>true</NoStdLib>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" Condition="'$(TargetFrameworkVersion)' != 'v2.0'" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\ProtocolBuffers\FrameworkPortability.cs">
<Link>FrameworkPortability.cs</Link>
</Compile>
<Compile Include="Extensions.cs" />
<Compile Include="Http\FormUrlEncodedReader.cs" />
<Compile Include="Http\MessageFormatFactory.cs" />
<Compile Include="Http\MessageFormatOptions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="AbstractReader.cs" />
<Compile Include="AbstractTextReader.cs" />
<Compile Include="AbstractTextWriter.cs" />
<Compile Include="AbstractWriter.cs" />
<Compile Include="DictionaryReader.cs" />
<Compile Include="DictionaryWriter.cs" />
<Compile Include="JsonFormatReader.cs" />
<Compile Include="JsonFormatWriter.cs" />
<Compile Include="JsonTextCursor.cs" />
<Compile Include="RecursionLimitExceeded.cs" />
<Compile Include="XmlFormatReader.cs" />
<Compile Include="XmlFormatWriter.cs" />
<Compile Include="XmlReaderOptions.cs" />
<Compile Include="XmlWriterOptions.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ProtocolBuffers\ProtocolBuffersLite.csproj">
<Project>{6969BDCE-D925-43F3-94AC-A531E6DF2591}</Project>
<Name>ProtocolBuffersLite</Name>
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.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>
-->
</Project>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
namespace Google.ProtocolBuffers.Serialization
{
/// <summary>
/// The exception raised when a recursion limit is reached while parsing input.
/// </summary>
public sealed class RecursionLimitExceededException : FormatException
{
const string message = "Possible malicious message had too many levels of nesting.";
internal RecursionLimitExceededException() : base(message)
{
}
}
}
using System;
namespace Google.ProtocolBuffers.Serialization
{
/// <summary>
/// Options available for the xml reader output
/// </summary>
[Flags]
public enum XmlReaderOptions
{
/// <summary> Simple xml formatting with no attributes </summary>
None,
/// <summary> Requires that arrays items are nested in an &lt;item> element </summary>
ReadNestedArrays = 1,
}
}
\ No newline at end of file
using System;
namespace Google.ProtocolBuffers.Serialization
{
/// <summary>
/// Options available for the xml writer output
/// </summary>
[Flags]
public enum XmlWriterOptions
{
/// <summary> Simple xml formatting with no attributes </summary>
None,
/// <summary> Writes the 'value' attribute on all enumerations with the numeric identifier </summary>
OutputEnumValues = 0x1,
/// <summary> Embeds array items into child &lt;item> elements </summary>
OutputNestedArrays = 0x4,
/// <summary> Outputs the 'type' attribute for compatibility with the <see cref="System.Runtime.Serialization.Json.JsonReaderWriterFactory">JsonReaderWriterFactory</see> </summary>
/// <remarks> This option must, by nessessity, also enable NestedArrayItems </remarks>
OutputJsonTypes = 0x8,
}
}
\ No newline at end of file
This diff is collapsed.
......@@ -38,7 +38,7 @@ using System;
using System.Text;
using NUnit.Framework;
namespace Google.ProtocolBuffers
namespace Google.Protobuf
{
public class ByteStringTest
{
......
using System;
namespace Google.ProtocolBuffers.Compatibility
{
public class BinaryCompatibilityTests : CompatibilityTests
{
protected override object SerializeMessage<TMessage, TBuilder>(TMessage message)
{
byte[] bresult = message.ToByteArray();
return Convert.ToBase64String(bresult);
}
protected override TBuilder DeserializeMessage<TMessage, TBuilder>(object message, TBuilder builder, ExtensionRegistry registry)
{
return builder.MergeFrom((byte[])Convert.FromBase64String((string)message), registry);
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using Google.ProtocolBuffers.Serialization;
using NUnit.Framework;
namespace Google.ProtocolBuffers.Compatibility
{
[TestFixture]
public class DictionaryCompatibilityTests : CompatibilityTests
{
protected override object SerializeMessage<TMessage, TBuilder>(TMessage message)
{
DictionaryWriter writer = new DictionaryWriter();
writer.WriteMessage(message);
return writer.ToDictionary();
}
protected override TBuilder DeserializeMessage<TMessage, TBuilder>(object message, TBuilder builder, ExtensionRegistry registry)
{
new DictionaryReader((IDictionary<string, object>)message).Merge(builder);
return builder;
}
protected override void AssertOutputEquals(object lhs, object rhs)
{
IDictionary<string, object> left = (IDictionary<string, object>)lhs;
IDictionary<string, object> right = (IDictionary<string, object>)rhs;
Assert.AreEqual(
String.Join(",", new List<string>(left.Keys).ToArray()),
String.Join(",", new List<string>(right.Keys).ToArray())
);
}
}
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment