Added the XmlFormatWriter/Reader
diff --git a/src/ProtocolBuffers/Serialization/AbstractReader.cs b/src/ProtocolBuffers/Serialization/AbstractReader.cs
new file mode 100644
index 0000000..8e4030e
--- /dev/null
+++ b/src/ProtocolBuffers/Serialization/AbstractReader.cs
@@ -0,0 +1,508 @@
+using System;

+using System.Collections.Generic;

+using Google.ProtocolBuffers.Descriptors;

+

+//Disable CS3011: only CLS-compliant members can be abstract

+#pragma warning disable 3011

+

+namespace Google.ProtocolBuffers.Serialization

+{

+    /// <summary>

+    /// Provides a base-class that provides some basic functionality for handling type dispatching

+    /// </summary>

+    public abstract class AbstractReader : ICodedInputStream

+    {

+        /// <summary>

+        /// Merges the contents of stream into the provided message builder

+        /// </summary>

+        public TBuilder Merge<TBuilder>(TBuilder builder) where TBuilder : IBuilderLite

+        { return Merge(builder, ExtensionRegistry.Empty); }

+

+        /// <summary>

+        /// Merges the contents of stream into the provided message builder

+        /// </summary>

+        public abstract TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry) where TBuilder : IBuilderLite;

+

+        /// <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 abstract bool PeekNext(out string field);

+

+        /// <summary>

+        /// Causes the reader to skip past this field

+        /// </summary>

+        protected abstract void Skip();

+

+        /// <summary>

+        /// Returns true if it was able to read a Boolean from the input

+        /// </summary>

+        protected abstract bool Read(ref bool value);

+

+        /// <summary>

+        /// Returns true if it was able to read a Int32 from the input

+        /// </summary>

+        protected abstract bool Read(ref int value);

+

+        /// <summary>

+        /// Returns true if it was able to read a UInt32 from the input

+        /// </summary>

+        [CLSCompliant(false)]

+        protected abstract bool Read(ref uint value);

+

+        /// <summary>

+        /// Returns true if it was able to read a Int64 from the input

+        /// </summary>

+        protected abstract bool Read(ref long value);

+

+        /// <summary>

+        /// Returns true if it was able to read a UInt64 from the input

+        /// </summary>

+        [CLSCompliant(false)]

+        protected abstract bool Read(ref ulong value);

+

+        /// <summary>

+        /// Returns true if it was able to read a Single from the input

+        /// </summary>

+        protected abstract bool Read(ref float value);

+

+        /// <summary>

+        /// Returns true if it was able to read a Double from the input

+        /// </summary>

+        protected abstract bool Read(ref double value);

+

+        /// <summary>

+        /// Returns true if it was able to read a String from the input

+        /// </summary>

+        protected abstract bool Read(ref string value);

+

+        /// <summary>

+        /// Returns true if it was able to read a ByteString from the input

+        /// </summary>

+        protected abstract bool Read(ref ByteString value);

+

+        /// <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 abstract bool ReadEnum(ref object value);

+

+        /// <summary>

+        /// Merges the input stream into the provided IBuilderLite 

+        /// </summary>

+        protected abstract bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry);

+

+        /// <summary>

+        /// Merges the input stream into the provided IBuilderLite 

+        /// </summary>

+        public virtual bool ReadGroup(IBuilderLite value, ExtensionRegistry registry)

+        {

+            return ReadMessage(value, registry);

+        }

+

+        /// <summary>

+        /// Cursors through the array elements and stops at the end of the array

+        /// </summary>

+        protected virtual IEnumerable<string> ForeachArrayItem(string field)

+        {

+            string next = field;

+            while (true)

+            {

+                yield return next;

+

+                if (!PeekNext(out next) || next != field)

+                    break;

+            }

+        }

+

+        /// <summary>

+        /// Reads an array of T messages

+        /// </summary>

+        public virtual bool ReadMessageArray<T>(string field, ICollection<T> items, IMessageLite messageType, ExtensionRegistry registry)

+        {

+            bool success = false;

+            foreach (string next in ForeachArrayItem(field))

+            {

+                IBuilderLite builder = messageType.WeakCreateBuilderForType();

+                if (ReadMessage(builder, registry))

+                {

+                    items.Add((T)builder.WeakBuild());

+                    success |= true;

+                }

+            }

+            return success;

+        }

+

+        /// <summary>

+        /// Reads an array of T messages as a proto-buffer group

+        /// </summary>

+        public virtual bool ReadGroupArray<T>(string field, ICollection<T> items, IMessageLite messageType, ExtensionRegistry registry)

+        {

+            bool success = false;

+            foreach (string next in ForeachArrayItem(field))

+            {

+                IBuilderLite builder = messageType.WeakCreateBuilderForType();

+                if (ReadGroup(builder, registry))

+                {

+                    items.Add((T)builder.WeakBuild());

+                    success |= true;

+                }

+            }

+            return success;

+        }

+

+        /// <summary>

+        /// Reads an array of System.Enum type T and adds them to the collection

+        /// </summary>

+        public virtual bool ReadEnumArray(string field, ICollection<object> items)

+        {

+            bool success = false;

+            foreach (string next in ForeachArrayItem(field))

+            {

+                object temp = null;

+                if (ReadEnum(ref temp))

+                {

+                    items.Add(temp);

+                    success |= true;

+                }

+            }

+            return success;

+        }

+

+        /// <summary>

+        /// Reads an array of T, where T is a primitive type defined by FieldType

+        /// </summary>

+        public virtual bool ReadArray<T>(FieldType type, string field, ICollection<T> items)

+        {

+            bool success = false;

+            foreach (string next in ForeachArrayItem(field))

+            {

+                object temp = null;

+                if (ReadField(type, ref temp))

+                {

+                    items.Add((T)temp);

+                    success |= true;

+                }

+            }

+            return success;

+        }

+

+        /// <summary>

+        /// returns true if it was able to read a single primitive value of FieldType into the value reference

+        /// </summary>

+        public virtual bool ReadField(FieldType type, ref object value)

+        {

+            switch (type)

+            {

+                case FieldType.Bool:

+                    {

+                        bool temp = false;

+                        if (Read(ref temp))

+                            value = temp;

+                        else

+                            return false;

+                        break;

+                    }

+                case FieldType.Int64:

+                case FieldType.SInt64:

+                case FieldType.SFixed64:

+                    {

+                        long temp = 0;

+                        if (Read(ref temp))

+                            value = temp;

+                        else

+                            return false;

+                        break;

+                    }

+                case FieldType.UInt64:

+                case FieldType.Fixed64:

+                    {

+                        ulong temp = 0;

+                        if (Read(ref temp))

+                            value = temp;

+                        else

+                            return false;

+                        break;

+                    }

+                case FieldType.Int32:

+                case FieldType.SInt32:

+                case FieldType.SFixed32:

+                    {

+                        int temp = 0;

+                        if (Read(ref temp))

+                            value = temp;

+                        else

+                            return false;

+                        break;

+                    }

+                case FieldType.UInt32:

+                case FieldType.Fixed32:

+                    {

+                        uint temp = 0;

+                        if (Read(ref temp))

+                            value = temp;

+                        else

+                            return false;

+                        break;

+                    }

+                case FieldType.Float:

+                    {

+                        float temp = float.NaN;

+                        if (Read(ref temp))

+                            value = temp;

+                        else

+                            return false;

+                        break;

+                    }

+                case FieldType.Double:

+                    {

+                        double temp = float.NaN;

+                        if (Read(ref temp))

+                            value = temp;

+                        else

+                            return false;

+                        break;

+                    }

+                case FieldType.String:

+                    {

+                        string temp = null;

+                        if (Read(ref temp))

+                            value = temp;

+                        else

+                            return false;

+                        break;

+                    }

+                case FieldType.Bytes:

+                    {

+                        ByteString temp = null;

+                        if (Read(ref temp))

+                            value = temp;

+                        else

+                            return false;

+                        break;

+                    }

+                default:

+                    throw InvalidProtocolBufferException.InvalidTag();

+            }

+            return true;

+        }

+

+        #region ICodedInputStream Members

+

+        bool ICodedInputStream.ReadTag(out uint fieldTag, out string fieldName)

+        {

+            fieldTag = 0;

+            if (PeekNext(out fieldName))

+            {

+                return true;

+            }

+            return false;

+        }

+

+        bool ICodedInputStream.ReadDouble(ref double value)

+        { return Read(ref value); }

+

+        bool ICodedInputStream.ReadFloat(ref float value)

+        { return Read(ref value); }

+

+        bool ICodedInputStream.ReadUInt64(ref ulong value)

+        { return Read(ref value); }

+

+        bool ICodedInputStream.ReadInt64(ref long value)

+        { return Read(ref value); }

+

+        bool ICodedInputStream.ReadInt32(ref int value)

+        { return Read(ref value); }

+

+        bool ICodedInputStream.ReadFixed64(ref ulong value)

+        { return Read(ref value); }

+

+        bool ICodedInputStream.ReadFixed32(ref uint value)

+        { return Read(ref value); }

+

+        bool ICodedInputStream.ReadBool(ref bool value)

+        { return Read(ref value); }

+

+        bool ICodedInputStream.ReadString(ref string value)

+        { return Read(ref value); }

+

+        void ICodedInputStream.ReadGroup(int fieldNumber, IBuilderLite builder, ExtensionRegistry extensionRegistry)

+        { ReadGroup(builder, extensionRegistry); }

+

+        void ICodedInputStream.ReadUnknownGroup(int fieldNumber, IBuilderLite builder)

+        { throw new NotSupportedException(); }

+

+        void ICodedInputStream.ReadMessage(IBuilderLite builder, ExtensionRegistry extensionRegistry)

+        { ReadMessage(builder, extensionRegistry); }

+

+        bool ICodedInputStream.ReadBytes(ref ByteString value)

+        { return Read(ref value); }

+

+        bool ICodedInputStream.ReadUInt32(ref uint value)

+        { return Read(ref value); }

+

+        bool ICodedInputStream.ReadEnum(ref IEnumLite value, out object unknown, IEnumLiteMap mapping)

+        {

+            value = null;

+            unknown = null;

+            if(ReadEnum(ref unknown))

+            {

+                if (unknown is int) value = mapping.FindValueByNumber((int)unknown);

+                else if (unknown is string) value = mapping.FindValueByName((string)unknown);

+                return value != null;

+            }

+            return false;

+        }

+

+        bool ICodedInputStream.ReadEnum<T>(ref T value, out object rawValue)

+        {

+            rawValue = null;

+            if (ReadEnum(ref rawValue))

+            {

+                if (Enum.IsDefined(typeof(T), rawValue))

+                {

+                    if (rawValue is int)

+                        value = (T)rawValue;

+                    else if (rawValue is string)

+                        value = (T)Enum.Parse(typeof(T), (string)rawValue, false);

+                    else

+                    {

+                        value = default(T);

+                        return false;

+                    }

+                    return true;

+                }

+            }

+            return false;

+        }

+

+        bool ICodedInputStream.ReadSFixed32(ref int value)

+        { return Read(ref value); }

+

+        bool ICodedInputStream.ReadSFixed64(ref long value)

+        { return Read(ref value); }

+

+        bool ICodedInputStream.ReadSInt32(ref int value)

+        { return Read(ref value); }

+

+        bool ICodedInputStream.ReadSInt64(ref long value)

+        { return Read(ref value); }

+

+        void ICodedInputStream.ReadPrimitiveArray(FieldType fieldType, uint fieldTag, string fieldName, ICollection<object> list)

+        { ReadArray(fieldType, fieldName, list); }

+

+        void ICodedInputStream.ReadEnumArray(uint fieldTag, string fieldName, ICollection<IEnumLite> list, out ICollection<object> unknown, IEnumLiteMap mapping)

+        {

+            unknown = null;

+            List<object> array = new List<object>();

+            if (ReadEnumArray(fieldName, array))

+            {

+                foreach (object rawValue in array)

+                {

+                    IEnumLite item = null;

+                    if (rawValue is int) item = mapping.FindValueByNumber((int)rawValue);

+                    else if (rawValue is string) item = mapping.FindValueByName((string)rawValue);

+

+                    if (item != null)

+                        list.Add(item);

+                    else

+                    {

+                        if (unknown == null) unknown = new List<object>();

+                        unknown.Add(rawValue);

+                    }

+                }

+            }

+        }

+

+        void ICodedInputStream.ReadEnumArray<T>(uint fieldTag, string fieldName, ICollection<T> list, out ICollection<object> unknown)

+        {

+            unknown = null;

+            List<object> array = new List<object>();

+            if (ReadEnumArray(fieldName, array))

+            {

+                foreach (object rawValue in array)

+                {

+                    if (rawValue is int)

+                        list.Add((T)rawValue);

+                    else if (rawValue is string)

+                        list.Add((T)Enum.Parse(typeof(T), (string)rawValue, false));

+                    else

+                    {

+                        if (unknown == null) unknown = new List<object>();

+                        unknown.Add(rawValue);

+                    }

+                }

+            }

+        }

+

+        void ICodedInputStream.ReadMessageArray<T>(uint fieldTag, string fieldName, ICollection<T> list, T messageType, ExtensionRegistry registry)

+        { ReadMessageArray(fieldName, list, messageType, registry); }

+

+        void ICodedInputStream.ReadGroupArray<T>(uint fieldTag, string fieldName, ICollection<T> list, T messageType, ExtensionRegistry registry)

+        { ReadGroupArray(fieldName, list, messageType, registry); }

+

+        bool ICodedInputStream.ReadPrimitiveField(FieldType fieldType, ref object value)

+        { return ReadField(fieldType, ref value); }

+

+        bool ICodedInputStream.IsAtEnd

+        {

+            get { string next; return PeekNext(out next) == false; }

+        }

+

+        bool ICodedInputStream.SkipField()

+        {

+            Skip();

+            return true;

+        }

+

+        void ICodedInputStream.ReadStringArray(uint fieldTag, string fieldName, ICollection<string> list)

+        { ReadArray(FieldType.String, fieldName, list); }

+

+        void ICodedInputStream.ReadBytesArray(uint fieldTag, string fieldName, ICollection<ByteString> list)

+        { ReadArray(FieldType.Bytes, fieldName, list); }

+

+        void ICodedInputStream.ReadBoolArray(uint fieldTag, string fieldName, ICollection<bool> list)

+        { ReadArray(FieldType.Bool, fieldName, list); }

+

+        void ICodedInputStream.ReadInt32Array(uint fieldTag, string fieldName, ICollection<int> list)

+        { ReadArray(FieldType.Int32, fieldName, list); }

+

+        void ICodedInputStream.ReadSInt32Array(uint fieldTag, string fieldName, ICollection<int> list)

+        { ReadArray(FieldType.SInt32, fieldName, list); }

+

+        void ICodedInputStream.ReadUInt32Array(uint fieldTag, string fieldName, ICollection<uint> list)

+        { ReadArray(FieldType.UInt32, fieldName, list); }

+

+        void ICodedInputStream.ReadFixed32Array(uint fieldTag, string fieldName, ICollection<uint> list)

+        { ReadArray(FieldType.Fixed32, fieldName, list); }

+

+        void ICodedInputStream.ReadSFixed32Array(uint fieldTag, string fieldName, ICollection<int> list)

+        { ReadArray(FieldType.SFixed32, fieldName, list); }

+

+        void ICodedInputStream.ReadInt64Array(uint fieldTag, string fieldName, ICollection<long> list)

+        { ReadArray(FieldType.Int64, fieldName, list); }

+

+        void ICodedInputStream.ReadSInt64Array(uint fieldTag, string fieldName, ICollection<long> list)

+        { ReadArray(FieldType.SInt64, fieldName, list); }

+

+        void ICodedInputStream.ReadUInt64Array(uint fieldTag, string fieldName, ICollection<ulong> list)

+        { ReadArray(FieldType.UInt64, fieldName, list); }

+

+        void ICodedInputStream.ReadFixed64Array(uint fieldTag, string fieldName, ICollection<ulong> list)

+        { ReadArray(FieldType.Fixed64, fieldName, list); }

+

+        void ICodedInputStream.ReadSFixed64Array(uint fieldTag, string fieldName, ICollection<long> list)

+        { ReadArray(FieldType.SFixed64, fieldName, list); }

+

+        void ICodedInputStream.ReadDoubleArray(uint fieldTag, string fieldName, ICollection<double> list)

+        { ReadArray(FieldType.Double, fieldName, list); }

+

+        void ICodedInputStream.ReadFloatArray(uint fieldTag, string fieldName, ICollection<float> list)

+        { ReadArray(FieldType.Float, fieldName, list); }

+

+        #endregion

+    }

+}

diff --git a/src/ProtocolBuffers/Serialization/AbstractTextReader.cs b/src/ProtocolBuffers/Serialization/AbstractTextReader.cs
new file mode 100644
index 0000000..2f07ac7
--- /dev/null
+++ b/src/ProtocolBuffers/Serialization/AbstractTextReader.cs
@@ -0,0 +1,171 @@
+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>

+        /// 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>

+        [CLSCompliant(false)]

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

+        [CLSCompliant(false)]

+        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 (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out number))

+                {

+                    value = number;

+                    return true;

+                }

+                value = text;

+                return true;

+            }

+            return false;

+        }

+    }

+}
\ No newline at end of file
diff --git a/src/ProtocolBuffers/Serialization/AbstractTextWriter.cs b/src/ProtocolBuffers/Serialization/AbstractTextWriter.cs
new file mode 100644
index 0000000..75acc0f
--- /dev/null
+++ b/src/ProtocolBuffers/Serialization/AbstractTextWriter.cs
@@ -0,0 +1,73 @@
+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>

+        [CLSCompliant(false)]

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

+        [CLSCompliant(false)]

+        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
diff --git a/src/ProtocolBuffers/Serialization/AbstractWriter.cs b/src/ProtocolBuffers/Serialization/AbstractWriter.cs
new file mode 100644
index 0000000..d8a0c0a
--- /dev/null
+++ b/src/ProtocolBuffers/Serialization/AbstractWriter.cs
@@ -0,0 +1,345 @@
+using System;

+using System.Collections;

+using System.Globalization;

+using Google.ProtocolBuffers.Descriptors;

+

+//Disable CS3011: only CLS-compliant members can be abstract

+#pragma warning disable 3011

+

+namespace Google.ProtocolBuffers.Serialization

+{

+    /// <summary>

+    /// Provides a base class for writers that performs some basic type dispatching

+    /// </summary>

+    public abstract class AbstractWriter : ICodedOutputStream, IDisposable

+    {

+        /// <summary>

+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

+        /// </summary>

+        public void Dispose()

+        {

+            GC.SuppressFinalize(this);

+            Flush();

+            Dispose(true);

+        }

+

+        /// <summary>

+        /// Completes any pending write operations

+        /// </summary>

+        public virtual void Flush()

+        { }

+

+        /// <summary>

+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

+        /// </summary>

+        protected virtual void Dispose(bool disposing)

+        {

+        }

+

+        /// <summary>

+        /// Writes the message to the the formatted stream.

+        /// </summary>

+        public abstract void WriteMessage(IMessageLite message);

+

+        /// <summary>

+        /// Writes a message

+        /// </summary>

+        public abstract void WriteMessage(string field, IMessageLite message);

+

+

+

+        /// <summary>

+        /// Writes a Boolean value

+        /// </summary>

+        protected abstract void Write(string field, Boolean value);

+

+        /// <summary>

+        /// Writes a Int32 value

+        /// </summary>

+        protected abstract void Write(string field, Int32 value);

+

+        /// <summary>

+        /// Writes a UInt32 value

+        /// </summary>

+        [CLSCompliant(false)]

+        protected abstract void Write(string field, UInt32 value);

+

+        /// <summary>

+        /// Writes a Int64 value

+        /// </summary>

+        protected abstract void Write(string field, Int64 value);

+

+        /// <summary>

+        /// Writes a UInt64 value

+        /// </summary>

+        [CLSCompliant(false)]

+        protected abstract void Write(string field, UInt64 value);

+

+        /// <summary>

+        /// Writes a Single value

+        /// </summary>

+        protected abstract void Write(string field, Single value);

+

+        /// <summary>

+        /// Writes a Double value

+        /// </summary>

+        protected abstract void Write(string field, Double value);

+

+        /// <summary>

+        /// Writes a String value

+        /// </summary>

+        protected abstract void Write(string field, String value);

+

+        /// <summary>

+        /// Writes a set of bytes

+        /// </summary>

+        protected abstract void Write(string field, ByteString value);

+

+        /// <summary>

+        /// Writes a message or group as a field

+        /// </summary>

+        protected abstract void WriteMessageOrGroup(string field, IMessageLite message);

+

+        /// <summary>

+        /// Writes a System.Enum by the numeric and textual value

+        /// </summary>

+        protected abstract void WriteEnum(string field, int number, string name);

+

+        /// <summary>

+        /// Writes a field of the type determined by field.FieldType

+        /// </summary>

+        protected virtual void WriteField(FieldType fieldType, string field, object value)

+        {

+            switch (fieldType)

+            {

+                case FieldType.Bool: Write(field, (bool)value); break;

+                case FieldType.Int64:

+                case FieldType.SInt64:

+                case FieldType.SFixed64: Write(field, (long)value); break;

+                case FieldType.UInt64:

+                case FieldType.Fixed64: Write(field, (ulong)value); break;

+                case FieldType.Int32:

+                case FieldType.SInt32:

+                case FieldType.SFixed32: Write(field, (int)value); break;

+                case FieldType.UInt32:

+                case FieldType.Fixed32: Write(field, (uint)value); break;

+                case FieldType.Float: Write(field, (float)value); break;

+                case FieldType.Double: Write(field, (double)value); break;

+                case FieldType.String: Write(field, (string)value); break;

+                case FieldType.Bytes: Write(field, (ByteString)value); break;

+                case FieldType.Group: WriteMessageOrGroup(field, (IMessageLite)value); break;

+                case FieldType.Message: WriteMessageOrGroup(field, (IMessageLite)value); break;

+                case FieldType.Enum:

+                    {

+                        if (value is IEnumLite) WriteEnum(field, ((IEnumLite)value).Number, ((IEnumLite)value).Name);

+                        else if (value is IConvertible) WriteEnum(field, ((IConvertible)value).ToInt32(CultureInfo.InvariantCulture), ((IConvertible)value).ToString(CultureInfo.InvariantCulture));

+                        else throw new ArgumentException("Expected an Enum type for field " + field);

+                        break;

+                    }

+                default:

+                    throw InvalidProtocolBufferException.InvalidTag();

+            }

+        }

+

+        /// <summary>

+        /// Writes an array of field values

+        /// </summary>

+        protected virtual void WriteArray(FieldType fieldType, string field, IEnumerable items)

+        {

+            foreach (object obj in items)

+                WriteField(fieldType, field, obj);

+        }

+

+        /// <summary>

+        /// Writes a numeric unknown field of wire type: Fixed32, Fixed64, or Variant

+        /// </summary>

+        [CLSCompliant(false)]

+        protected virtual void WriteUnknown(WireFormat.WireType wireType, int fieldNumber, ulong value)

+        { }

+

+        /// <summary>

+        /// Writes an unknown field, Expect WireType of GroupStart or LengthPrefix

+        /// </summary>

+        [CLSCompliant(false)]

+        protected virtual void WriteUnknown(WireFormat.WireType wireType, int fieldNumber, ByteString value)

+        { }

+

+        #region ICodedOutputStream Members

+

+        void ICodedOutputStream.WriteUnknownGroup(int fieldNumber, IMessageLite value)

+        { }

+        void ICodedOutputStream.WriteUnknownBytes(int fieldNumber, ByteString value)

+        { }

+        void ICodedOutputStream.WriteUnknownField(int fieldNumber, WireFormat.WireType type, ulong value)

+        { }

+

+        void ICodedOutputStream.WriteMessageSetExtension(int fieldNumber, string fieldName, IMessageLite value)

+        { }

+

+        void ICodedOutputStream.WriteMessageSetExtension(int fieldNumber, string fieldName, ByteString value)

+        { }

+

+        void ICodedOutputStream.WriteField(FieldType fieldType, int fieldNumber, string fieldName, object value)

+        { WriteField(fieldType, fieldName, value); }

+

+        void ICodedOutputStream.WriteDouble(int fieldNumber, string fieldName, double value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteFloat(int fieldNumber, string fieldName, float value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteUInt64(int fieldNumber, string fieldName, ulong value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteInt64(int fieldNumber, string fieldName, long value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteInt32(int fieldNumber, string fieldName, int value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteFixed64(int fieldNumber, string fieldName, ulong value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteFixed32(int fieldNumber, string fieldName, uint value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteBool(int fieldNumber, string fieldName, bool value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteString(int fieldNumber, string fieldName, string value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteGroup(int fieldNumber, string fieldName, IMessageLite value)

+        { WriteMessageOrGroup(fieldName, value); }

+

+        void ICodedOutputStream.WriteMessage(int fieldNumber, string fieldName, IMessageLite value)

+        { WriteMessageOrGroup(fieldName, value); }

+

+        void ICodedOutputStream.WriteBytes(int fieldNumber, string fieldName, ByteString value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteUInt32(int fieldNumber, string fieldName, uint value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteEnum(int fieldNumber, string fieldName, int value, object rawValue)

+        { WriteEnum(fieldName, value, rawValue.ToString()); }

+

+        void ICodedOutputStream.WriteSFixed32(int fieldNumber, string fieldName, int value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteSFixed64(int fieldNumber, string fieldName, long value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteSInt32(int fieldNumber, string fieldName, int value)

+        { Write(fieldName, value); }

+

+        void ICodedOutputStream.WriteSInt64(int fieldNumber, string fieldName, long value)

+        { Write(fieldName, value); }

+

+

+        void ICodedOutputStream.WriteArray(FieldType fieldType, int fieldNumber, string fieldName, IEnumerable list)

+        { WriteArray(fieldType, fieldName, list); }

+

+        void ICodedOutputStream.WriteGroupArray<T>(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<T> list)

+        { WriteArray(FieldType.Group, fieldName, list); }

+

+        void ICodedOutputStream.WriteMessageArray<T>(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<T> list)

+        { WriteArray(FieldType.Message, fieldName, list); }

+

+        void ICodedOutputStream.WriteStringArray(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<string> list)

+        { WriteArray(FieldType.String, fieldName, list); }

+

+        void ICodedOutputStream.WriteBytesArray(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<ByteString> list)

+        { WriteArray(FieldType.Bytes, fieldName, list); }

+

+        void ICodedOutputStream.WriteBoolArray(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<bool> list)

+        { WriteArray(FieldType.Bool, fieldName, list); }

+

+        void ICodedOutputStream.WriteInt32Array(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<int> list)

+        { WriteArray(FieldType.Int32, fieldName, list); }

+

+        void ICodedOutputStream.WriteSInt32Array(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<int> list)

+        { WriteArray(FieldType.SInt32, fieldName, list); }

+

+        void ICodedOutputStream.WriteUInt32Array(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<uint> list)

+        { WriteArray(FieldType.UInt32, fieldName, list); }

+

+        void ICodedOutputStream.WriteFixed32Array(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<uint> list)

+        { WriteArray(FieldType.Fixed32, fieldName, list); }

+

+        void ICodedOutputStream.WriteSFixed32Array(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<int> list)

+        { WriteArray(FieldType.SFixed32, fieldName, list); }

+

+        void ICodedOutputStream.WriteInt64Array(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<long> list)

+        { WriteArray(FieldType.Int64, fieldName, list); }

+

+        void ICodedOutputStream.WriteSInt64Array(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<long> list)

+        { WriteArray(FieldType.SInt64, fieldName, list); }

+

+        void ICodedOutputStream.WriteUInt64Array(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<ulong> list)

+        { WriteArray(FieldType.UInt64, fieldName, list); }

+

+        void ICodedOutputStream.WriteFixed64Array(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<ulong> list)

+        { WriteArray(FieldType.Fixed64, fieldName, list); }

+

+        void ICodedOutputStream.WriteSFixed64Array(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<long> list)

+        { WriteArray(FieldType.SFixed64, fieldName, list); }

+

+        void ICodedOutputStream.WriteDoubleArray(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<double> list)

+        { WriteArray(FieldType.Double, fieldName, list); }

+

+        void ICodedOutputStream.WriteFloatArray(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<float> list)

+        { WriteArray(FieldType.Float, fieldName, list); }

+

+        void ICodedOutputStream.WriteEnumArray<T>(int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<T> list)

+        { WriteArray(FieldType.Enum, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedArray(FieldType fieldType, int fieldNumber, string fieldName, IEnumerable list)

+        { WriteArray(fieldType, fieldName, list); }

+

+

+        void ICodedOutputStream.WritePackedBoolArray(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<bool> list)

+        { WriteArray(FieldType.Bool, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedInt32Array(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<int> list)

+        { WriteArray(FieldType.Int32, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedSInt32Array(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<int> list)

+        { WriteArray(FieldType.SInt32, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedUInt32Array(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<uint> list)

+        { WriteArray(FieldType.UInt32, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedFixed32Array(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<uint> list)

+        { WriteArray(FieldType.Fixed32, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedSFixed32Array(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<int> list)

+        { WriteArray(FieldType.SFixed32, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedInt64Array(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<long> list)

+        { WriteArray(FieldType.Int64, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedSInt64Array(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<long> list)

+        { WriteArray(FieldType.SInt64, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedUInt64Array(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<ulong> list)

+        { WriteArray(FieldType.UInt64, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedFixed64Array(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<ulong> list)

+        { WriteArray(FieldType.Fixed64, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedSFixed64Array(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<long> list)

+        { WriteArray(FieldType.SFixed64, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedDoubleArray(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<double> list)

+        { WriteArray(FieldType.Double, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedFloatArray(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<float> list)

+        { WriteArray(FieldType.Float, fieldName, list); }

+

+        void ICodedOutputStream.WritePackedEnumArray<T>(int fieldNumber, string fieldName, int computedSize, System.Collections.Generic.IEnumerable<T> list)

+        { WriteArray(FieldType.Enum, fieldName, list); }

+

+        #endregion

+    }

+}

diff --git a/src/ProtocolBuffers/Serialization/XmlFormatReader.cs b/src/ProtocolBuffers/Serialization/XmlFormatReader.cs
new file mode 100644
index 0000000..671490e
--- /dev/null
+++ b/src/ProtocolBuffers/Serialization/XmlFormatReader.cs
@@ -0,0 +1,222 @@
+using System;

+using System.Collections.Generic;

+using System.IO;

+using System.Xml;

+using Google.ProtocolBuffers.Descriptors;

+

+namespace Google.ProtocolBuffers.Serialization

+{

+    /// <summary>

+    /// Parses a proto buffer from an XML document or fragment.  .NET 3.5 users may also

+    /// use this class to process Json by setting the options to support Json and providing

+    /// an XmlReader obtained from <see cref="System.Runtime.Serialization.Json.JsonReaderWriterFactory"/>.

+    /// </summary>

+    public class XmlFormatReader : AbstractTextReader

+    {

+        public const string DefaultRootElementName = XmlFormatWriter.DefaultRootElementName;

+        private readonly XmlReader _input;

+        private string _rootElementName;

+

+        static XmlReaderSettings DefaultSettings

+        {

+            get { return new XmlReaderSettings() { CheckCharacters=false, IgnoreComments=true, IgnoreProcessingInstructions = true }; }

+        }

+

+        /// <summary>

+        /// Constructs the XmlFormatReader using the stream provided as the xml

+        /// </summary>

+        public XmlFormatReader(Stream input) : this(XmlReader.Create(input, DefaultSettings)) { }

+        /// <summary>

+        /// Constructs the XmlFormatReader using the string provided as the xml to be read

+        /// </summary>

+        public XmlFormatReader(String input) : this(XmlReader.Create(new StringReader(input))) { }

+        /// <summary>

+        /// Constructs the XmlFormatReader using the xml in the TextReader

+        /// </summary>

+        public XmlFormatReader(TextReader input) : this(XmlReader.Create(input)) { }

+        /// <summary>

+        /// Constructs the XmlFormatReader with the XmlReader

+        /// </summary>

+        public XmlFormatReader(XmlReader input) : this(input, XmlReaderOptions.None) { }

+        /// <summary>

+        /// Constructs the XmlFormatReader with the XmlReader and options

+        /// </summary>

+        public XmlFormatReader(XmlReader input, XmlReaderOptions options)

+        {

+            _input = input;

+            _rootElementName = DefaultRootElementName;

+            Options = options;

+        }

+        

+        /// <summary>

+        /// Gets or sets the options to use when reading the xml

+        /// </summary>

+        public XmlReaderOptions Options { get; set; }

+

+        /// <summary>

+        /// Gets or sets the default element name to use when using the Merge&lt;TBuilder>()

+        /// </summary>

+        public string RootElementName 

+        {

+            get { return _rootElementName; } 

+            set { ThrowHelper.ThrowIfNull(value, "RootElementName"); _rootElementName = value; } 

+        }

+

+        private XmlFormatReader CloneWith(XmlReader rdr)

+        {

+            return new XmlFormatReader(rdr, Options);

+        }

+        private void NextElement()

+        {

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

+                continue;

+        }

+        private static void Assert(bool cond)

+        {

+            if (!cond) throw new FormatException();

+        }

+

+        /// <summary>

+        /// Merge the provided builder as an element named <see cref="RootElementName"/> in the current context

+        /// </summary>

+        public override TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)

+        { return Merge(_rootElementName, builder, registry); }

+

+        /// <summary>

+        /// Merge the provided builder as an element of the current context

+        /// </summary>

+        public TBuilder Merge<TBuilder>(string element, TBuilder builder) where TBuilder : IBuilderLite

+        { return Merge(element, builder, ExtensionRegistry.Empty); }

+

+        /// <summary>

+        /// Merge the provided builder as an element of the current context

+        /// </summary>

+        public TBuilder Merge<TBuilder>(string element, TBuilder builder, ExtensionRegistry registry) where TBuilder : IBuilderLite

+        {

+            string field;

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

+            ReadMessage(builder, 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)

+        {

+            NextElement();

+            if(_input.IsStartElement())

+            {

+                field = _input.LocalName;

+                return true;

+            }

+            field = null;

+            return false;

+        }

+

+        /// <summary>

+        /// Causes the reader to skip past this field

+        /// </summary>

+        protected override void Skip()

+        {

+            if (_input.IsStartElement())

+            {

+                if (!_input.IsEmptyElement)

+                {

+                    int depth = _input.Depth;

+                    while (_input.Depth >= depth && _input.NodeType != XmlNodeType.EndElement)

+                        Assert(_input.Read());

+                }

+                _input.Read();

+            }

+        }

+

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

+        {

+            int number;

+            string temp;

+            if (null != (temp = _input.GetAttribute("value")) && int.TryParse(temp, out number))

+            {

+                Skip();

+                value = number;

+                return true;

+            }

+            return base.ReadEnum(ref value);

+        }

+

+        /// <summary>

+        /// Returns true if it was able to read a String from the input

+        /// </summary>

+        protected override bool ReadAsText(ref string value, Type type)

+        {

+            Assert(_input.NodeType == XmlNodeType.Element);

+            value = _input.ReadElementContentAsString();

+            

+            return true;

+        }

+

+        /// <summary>

+        /// Merges the input stream into the provided IBuilderLite 

+        /// </summary>

+        protected override bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry)

+        {

+            Assert(_input.IsStartElement());

+

+            if (!_input.IsEmptyElement)

+            {

+                int depth = _input.Depth;

+                XmlReader child = _input.ReadSubtree();

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

+                    continue;

+                child.Read();

+                builder.WeakMergeFrom(CloneWith(child), registry);

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

+            }

+            _input.Read();

+            return true;

+        }

+

+        private IEnumerable<string> NonNestedArrayItems(string field)

+        {

+            return base.ForeachArrayItem(field);

+        }

+

+        /// <summary>

+        /// Cursors through the array elements and stops at the end of the array

+        /// </summary>

+        protected override IEnumerable<string> ForeachArrayItem(string field)

+        {

+            bool isNested = (Options & XmlReaderOptions.ReadNestedArrays) != 0;

+

+            if (!isNested)

+            {

+                foreach (string item in NonNestedArrayItems(field))

+                    yield return item;

+                yield break;

+            }

+            if (!_input.IsEmptyElement)

+            {

+                int depth = _input.Depth;

+                XmlReader child = _input.ReadSubtree();

+

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

+                    continue;

+                child.Read();

+

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

+                    yield return item;

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

+            }

+            _input.Read();

+            yield break;

+        }

+    }

+}

diff --git a/src/ProtocolBuffers/Serialization/XmlFormatWriter.cs b/src/ProtocolBuffers/Serialization/XmlFormatWriter.cs
new file mode 100644
index 0000000..5ed9665
--- /dev/null
+++ b/src/ProtocolBuffers/Serialization/XmlFormatWriter.cs
@@ -0,0 +1,166 @@
+using System;

+using System.IO;

+using System.Xml;

+using Google.ProtocolBuffers.Descriptors;

+

+namespace Google.ProtocolBuffers.Serialization

+{

+    /// <summary>

+    /// Writes a proto buffer to an XML document or fragment.  .NET 3.5 users may also

+    /// use this class to produce Json by setting the options to support Json and providing

+    /// an XmlWriter obtained from <see cref="System.Runtime.Serialization.Json.JsonReaderWriterFactory"/>.

+    /// </summary>

+    public class XmlFormatWriter : AbstractTextWriter

+    {

+        public const string DefaultRootElementName = "root";

+        private const int NestedArrayFlag = 0x0001;

+        private readonly XmlWriter _output;

+        private string _rootElementName;

+

+        static XmlWriterSettings DefaultSettings

+        {

+            get { return new XmlWriterSettings() {CheckCharacters = false, NewLineHandling = NewLineHandling.Entitize}; }

+        }

+

+        /// <summary>

+        /// Constructs the XmlFormatWriter to write to the given TextWriter

+        /// </summary>

+        public XmlFormatWriter(TextWriter output) : this(XmlWriter.Create(output, DefaultSettings)) { }

+        /// <summary>

+        /// Constructs the XmlFormatWriter to write to the given stream

+        /// </summary>

+        public XmlFormatWriter(Stream output) : this(XmlWriter.Create(output, DefaultSettings)) { }

+        /// <summary>

+        /// Constructs the XmlFormatWriter to write to the given XmlWriter

+        /// </summary>

+        public XmlFormatWriter(XmlWriter output)

+        {

+            _output = output;

+            _rootElementName = DefaultRootElementName;

+        }

+

+        /// <summary>

+        /// Closes the underlying XmlTextWriter

+        /// </summary>

+        protected override void Dispose(bool disposing)

+        {

+            if(disposing)

+                _output.Close();

+        }

+

+        /// <summary>

+        /// Gets or sets the default element name to use when using the Merge&lt;TBuilder>()

+        /// </summary>

+        public string RootElementName

+        {

+            get { return _rootElementName; }

+            set { ThrowHelper.ThrowIfNull(value, "RootElementName"); _rootElementName = value; }

+        }

+

+        /// <summary>

+        /// Gets or sets the options to use while generating the XML

+        /// </summary>

+        public XmlWriterOptions Options { get; set; }

+

+        private bool TestOption(XmlWriterOptions option) { return (Options & option) != 0; }

+

+        /// <summary>

+        /// Writes a message as an element using the name defined in <see cref="RootElementName"/>

+        /// </summary>

+        public override void WriteMessage(IMessageLite message)

+        { WriteMessage(_rootElementName, message); }

+

+        /// <summary>

+        /// Writes a message as an element with the given name

+        /// </summary>

+        public override void WriteMessage(string elementName, IMessageLite message)

+        {

+            if (TestOption(XmlWriterOptions.OutputJsonTypes))

+            {

+                _output.WriteStartElement("root"); // json requires this is the root-element

+                _output.WriteAttributeString("type", "object");

+            }

+            else

+                _output.WriteStartElement(elementName);

+

+            message.WriteTo(this);

+            _output.WriteEndElement();

+            _output.Flush();

+        }

+

+        /// <summary>

+        /// Writes a message

+        /// </summary>

+        protected override void WriteMessageOrGroup(string field, IMessageLite message)

+        {

+            _output.WriteStartElement(field);

+

+            if (TestOption(XmlWriterOptions.OutputJsonTypes))

+                _output.WriteAttributeString("type", "object");

+

+            message.WriteTo(this);

+            _output.WriteEndElement();

+        }

+

+        /// <summary>

+        /// Writes a String value

+        /// </summary>

+        protected override void WriteAsText(string field, string textValue, object typedValue)

+        {

+            _output.WriteStartElement(field);

+

+            if (TestOption(XmlWriterOptions.OutputJsonTypes))

+            {

+                if (typedValue is int || typedValue is uint || typedValue is long || typedValue is ulong || typedValue is double || typedValue is float)

+                    _output.WriteAttributeString("type", "number");

+                else if (typedValue is bool)

+                    _output.WriteAttributeString("type", "boolean");

+            }

+            _output.WriteString(textValue);

+

+            //Empty strings should not be written as empty elements '<item/>', rather as '<item></item>'

+            if (_output.WriteState == WriteState.Element)

+                _output.WriteRaw("");

+

+            _output.WriteEndElement();

+        }

+

+        /// <summary>

+        /// Writes an array of field values

+        /// </summary>

+        protected override void WriteArray(FieldType fieldType, string field, System.Collections.IEnumerable items)

+        {

+            //see if it's empty

+            System.Collections.IEnumerator eitems = items.GetEnumerator();

+            try { if (!eitems.MoveNext()) return; }

+            finally

+            { if (eitems is IDisposable) ((IDisposable) eitems).Dispose(); }

+

+            if (TestOption(XmlWriterOptions.OutputNestedArrays | XmlWriterOptions.OutputJsonTypes))

+            {

+                _output.WriteStartElement(field);

+                if (TestOption(XmlWriterOptions.OutputJsonTypes))

+                    _output.WriteAttributeString("type", "array");

+

+                base.WriteArray(fieldType, "item", items);

+                _output.WriteEndElement();

+            }

+            else

+                base.WriteArray(fieldType, field, items);

+        }

+

+        /// <summary>

+        /// Writes a System.Enum by the numeric and textual value

+        /// </summary>

+        protected override void WriteEnum(string field, int number, string name)

+        {

+            _output.WriteStartElement(field);

+

+            if (!TestOption(XmlWriterOptions.OutputJsonTypes) && TestOption(XmlWriterOptions.OutputEnumValues))

+                _output.WriteAttributeString("value", XmlConvert.ToString(number));

+

+            _output.WriteString(name);

+            _output.WriteEndElement();

+        }

+    }

+}

diff --git a/src/ProtocolBuffers/Serialization/XmlReaderOptions.cs b/src/ProtocolBuffers/Serialization/XmlReaderOptions.cs
new file mode 100644
index 0000000..fc75e4b
--- /dev/null
+++ b/src/ProtocolBuffers/Serialization/XmlReaderOptions.cs
@@ -0,0 +1,16 @@
+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
diff --git a/src/ProtocolBuffers/Serialization/XmlWriterOptions.cs b/src/ProtocolBuffers/Serialization/XmlWriterOptions.cs
new file mode 100644
index 0000000..2d91c74
--- /dev/null
+++ b/src/ProtocolBuffers/Serialization/XmlWriterOptions.cs
@@ -0,0 +1,21 @@
+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