aboutsummaryrefslogtreecommitdiff
path: root/csharp/ProtocolBuffers
diff options
context:
space:
mode:
authorJon Skeet <skeet@pobox.com>2008-08-14 20:33:27 +0100
committerunknown <Jon@.(none)>2008-08-14 20:33:27 +0100
commitbaa2bf54c2d8d493444fd3d58bd8a89927300a50 (patch)
tree2b293b640a1ac5ee0d44178e5b0e22ddfaccdc6f /csharp/ProtocolBuffers
parent3c38991607e993bc90c307c7a680fba97b77ecb4 (diff)
downloadprotobuf-baa2bf54c2d8d493444fd3d58bd8a89927300a50.tar.gz
protobuf-baa2bf54c2d8d493444fd3d58bd8a89927300a50.tar.bz2
protobuf-baa2bf54c2d8d493444fd3d58bd8a89927300a50.zip
First part of dotnet library
committer: Jon Skeet <skeet@pobox.com>
Diffstat (limited to 'csharp/ProtocolBuffers')
-rw-r--r--csharp/ProtocolBuffers/ByteString.cs96
-rw-r--r--csharp/ProtocolBuffers/CodedInputStream.cs31
-rw-r--r--csharp/ProtocolBuffers/CodedOutputStream.cs708
-rw-r--r--csharp/ProtocolBuffers/Descriptors.cs39
-rw-r--r--csharp/ProtocolBuffers/ExtensionRegistry.cs5
-rw-r--r--csharp/ProtocolBuffers/IBuilder.cs227
-rw-r--r--csharp/ProtocolBuffers/IMessage.cs162
-rw-r--r--csharp/ProtocolBuffers/InvalidProtocolBufferException.cs7
-rw-r--r--csharp/ProtocolBuffers/Properties/AssemblyInfo.cs36
-rw-r--r--csharp/ProtocolBuffers/ProtocolBuffers.csproj60
-rw-r--r--csharp/ProtocolBuffers/UninitializedMessageException.cs6
-rw-r--r--csharp/ProtocolBuffers/UnknownFieldSet.cs13
-rw-r--r--csharp/ProtocolBuffers/WireFormat.cs28
13 files changed, 1418 insertions, 0 deletions
diff --git a/csharp/ProtocolBuffers/ByteString.cs b/csharp/ProtocolBuffers/ByteString.cs
new file mode 100644
index 00000000..1ce2453e
--- /dev/null
+++ b/csharp/ProtocolBuffers/ByteString.cs
@@ -0,0 +1,96 @@
+using System.Text;
+using System;
+
+namespace Google.ProtocolBuffers {
+ /// <summary>
+ /// Immutable array of bytes.
+ /// TODO(jonskeet): Implement the common collection interfaces?
+ /// </summary>
+ public sealed class ByteString {
+
+ private static readonly ByteString empty = new ByteString(new byte[0]);
+
+ private byte[] bytes;
+
+ /// <summary>
+ /// Constructs a new ByteString from the given byte array. The array is
+ /// *not* copied, and must not be modified after this constructor is called.
+ /// </summary>
+ private ByteString(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ /// <summary>
+ /// Returns an empty ByteString.
+ /// </summary>
+ public static ByteString Empty {
+ get { return empty; }
+ }
+
+ /// <summary>
+ /// Returns the length of this ByteString in bytes.
+ /// </summary>
+ public int Length {
+ get { return bytes.Length; }
+ }
+
+ public bool IsEmpty {
+ get { return Length == 0; }
+ }
+
+ public byte[] ToByteArray() {
+ return (byte[])bytes.Clone();
+ }
+
+ /// <summary>
+ /// Constructs a ByteString from the given array. The contents
+ /// are copied, so further modifications to the array will not
+ /// be reflected in the returned ByteString.
+ /// </summary>
+ public static ByteString CopyFrom(byte[] bytes) {
+ return new ByteString((byte[]) bytes.Clone());
+ }
+
+ /// <summary>
+ /// Constructs a ByteString from a portion of a byte array.
+ /// </summary>
+ public static ByteString CopyFrom(byte[] bytes, int offset, int count) {
+ byte[] portion = new byte[count];
+ Array.Copy(bytes, offset, portion, 0, count);
+ return new ByteString(portion);
+ }
+
+ /// <summary>
+ /// Creates a new ByteString by encoding the specified text with
+ /// the given encoding.
+ /// </summary>
+ public static ByteString CopyFrom(string text, Encoding encoding) {
+ return new ByteString(encoding.GetBytes(text));
+ }
+
+ /// <summary>
+ /// Creates a new ByteString by encoding the specified text in UTF-8.
+ /// </summary>
+ public static ByteString CopyFromUtf8(string text) {
+ return CopyFrom(text, Encoding.UTF8);
+ }
+
+ /// <summary>
+ /// Retuns the byte at the given index.
+ /// </summary>
+ public byte this[int index] {
+ get { return bytes[index]; }
+ }
+
+ public string ToString(Encoding encoding) {
+ return encoding.GetString(bytes);
+ }
+
+ public string ToStringUtf8() {
+ return ToString(Encoding.UTF8);
+ }
+
+ // TODO(jonskeet): CopyTo, Equals, GetHashCode if they turn out to be required
+ // TODO(jonskeet): Input/Output stuff
+ }
+}
diff --git a/csharp/ProtocolBuffers/CodedInputStream.cs b/csharp/ProtocolBuffers/CodedInputStream.cs
new file mode 100644
index 00000000..66dae52c
--- /dev/null
+++ b/csharp/ProtocolBuffers/CodedInputStream.cs
@@ -0,0 +1,31 @@
+
+namespace Google.ProtocolBuffers {
+ public sealed class CodedInputStream {
+
+ /// <summary>
+ /// Decode a 32-bit value with ZigZag encoding.
+ /// </summary>
+ /// <remarks>
+ /// ZigZag encodes signed integers into values that can be efficiently
+ /// encoded with varint. (Otherwise, negative values must be
+ /// sign-extended to 64 bits to be varint encoded, thus always taking
+ /// 10 bytes on the wire.)
+ /// </remarks>
+ public static int DecodeZigZag32(uint n) {
+ return (int)(n >> 1) ^ -(int)(n & 1);
+ }
+
+ /// <summary>
+ /// Decode a 32-bit value with ZigZag encoding.
+ /// </summary>
+ /// <remarks>
+ /// ZigZag encodes signed integers into values that can be efficiently
+ /// encoded with varint. (Otherwise, negative values must be
+ /// sign-extended to 64 bits to be varint encoded, thus always taking
+ /// 10 bytes on the wire.)
+ /// </remarks>
+ public static long DecodeZigZag64(ulong n) {
+ return (long)(n >> 1) ^ -(long)(n & 1);
+ }
+ }
+}
diff --git a/csharp/ProtocolBuffers/CodedOutputStream.cs b/csharp/ProtocolBuffers/CodedOutputStream.cs
new file mode 100644
index 00000000..51d5d657
--- /dev/null
+++ b/csharp/ProtocolBuffers/CodedOutputStream.cs
@@ -0,0 +1,708 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+using System;
+using System.IO;
+using System.Text;
+
+namespace Google.ProtocolBuffers {
+
+ /// <summary>
+ /// Encodes and writes protocol message fields.
+ /// </summary>
+ /// <remarks>
+ /// This class contains two kinds of methods: methods that write specific
+ /// protocol message constructs and field types (e.g. WriteTag and
+ /// WriteInt32) and methods that write low-level values (e.g.
+ /// WriteRawVarint32 and WriteRawBytes). If you are writing encoded protocol
+ /// messages, you should use the former methods, but if you are writing some
+ /// other format of your own design, use the latter. The names of the former
+ /// methods are taken from the protocol buffer type names, not .NET types.
+ /// (Hence WriteFloat instead of WriteSingle, and WriteBool instead of WriteBoolean.)
+ /// </remarks>
+ public sealed class CodedOutputStream {
+ /// <summary>
+ /// The buffer size used by CreateInstance(Stream).
+ /// </summary>
+ public static readonly int DefaultBufferSize = 4096;
+
+ private readonly byte[] buffer;
+ private readonly int limit;
+ private int position;
+ private readonly Stream output;
+
+ #region Construction
+ private CodedOutputStream(byte[] buffer, int offset, int length) {
+ this.output = null;
+ this.buffer = buffer;
+ this.position = offset;
+ this.limit = offset + length;
+ }
+
+ private CodedOutputStream(Stream output, byte[] buffer) {
+ this.output = output;
+ this.buffer = buffer;
+ this.position = 0;
+ this.limit = buffer.Length;
+ }
+
+ /// <summary>
+ /// Creates a new CodedOutputStream which write to the given stream.
+ /// </summary>
+ public static CodedOutputStream CreateInstance(Stream output) {
+ return CreateInstance(output, DefaultBufferSize);
+ }
+
+ /// <summary>
+ /// Creates a new CodedOutputStream which write to the given stream and uses
+ /// the specified buffer size.
+ /// </summary>
+ public static CodedOutputStream CreateInstance(Stream output, int bufferSize) {
+ return new CodedOutputStream(output, new byte[bufferSize]);
+ }
+
+ /// <summary>
+ /// Creates a new CodedOutputStream that writes directly to the given
+ /// byte array. If more bytes are written than fit in the array,
+ /// OutOfSpaceException will be thrown.
+ /// </summary>
+ public static CodedOutputStream CreateInstance(byte[] flatArray) {
+ return CreateInstance(flatArray, 0, flatArray.Length);
+ }
+
+ /// <summary>
+ /// Creates a new CodedOutputStream that writes directly to the given
+ /// byte array slice. If more bytes are written than fit in the array,
+ /// OutOfSpaceException will be thrown.
+ /// </summary>
+ public static CodedOutputStream CreateInstance(byte[] flatArray, int offset, int length) {
+ return new CodedOutputStream(flatArray, offset, length);
+ }
+ #endregion
+
+ #region Writing of tags etc
+ /// <summary>
+ /// Writes a double field value, including tag, to the stream.
+ /// </summary>
+ public void WriteDouble(int fieldNumber, double value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
+ WriteRawLittleEndian64(BitConverter.DoubleToInt64Bits(value));
+ }
+
+ /// <summary>
+ /// Writes a float field value, including tag, to the stream.
+ /// </summary>
+ public void WriteFloat(int fieldNumber, float value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
+ // FIXME: How do we convert a single to 32 bits? (Without unsafe code)
+ //WriteRawLittleEndian32(BitConverter.SingleT(value));
+ }
+
+ /// <summary>
+ /// Writes a uint64 field value, including tag, to the stream.
+ /// </summary>
+ public void WriteUInt64(int fieldNumber, ulong value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Varint);
+ WriteRawVarint64(value);
+ }
+
+ /// <summary>
+ /// Writes an int64 field value, including tag, to the stream.
+ /// </summary>
+ public void WriteInt64(int fieldNumber, long value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Varint);
+ WriteRawVarint64((ulong)value);
+ }
+
+ /// <summary>
+ /// Writes an int32 field value, including tag, to the stream.
+ /// </summary>
+ public void WriteInt32(int fieldNumber, int value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Varint);
+ if (value >= 0) {
+ WriteRawVarint32((uint)value);
+ } else {
+ // Must sign-extend.
+ WriteRawVarint64((ulong)value);
+ }
+ }
+
+ /// <summary>
+ /// Writes a fixed64 field value, including tag, to the stream.
+ /// </summary>
+ public void WriteFixed64(int fieldNumber, long value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
+ WriteRawLittleEndian64(value);
+ }
+
+ /// <summary>
+ /// Writes a fixed32 field value, including tag, to the stream.
+ /// </summary>
+ public void WriteFixed32(int fieldNumber, int value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
+ WriteRawLittleEndian32(value);
+ }
+
+ /// <summary>
+ /// Writes a bool field value, including tag, to the stream.
+ /// </summary>
+ public void WriteBool(int fieldNumber, bool value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Varint);
+ WriteRawByte(value ? (byte)1 : (byte)0);
+ }
+
+ /// <summary>
+ /// Writes a string field value, including tag, to the stream.
+ /// </summary>
+ public void WriteString(int fieldNumber, string value) {
+ WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
+ // TODO(jonskeet): Optimise this if possible
+ // Unfortunately there does not appear to be any way to tell Java to encode
+ // UTF-8 directly into our buffer, so we have to let it create its own byte
+ // array and then copy. In .NET we can do the same thing very easily,
+ // so we don't need to worry about only writing one buffer at a time.
+ // We can optimise later.
+ byte[] bytes = Encoding.UTF8.GetBytes(value);
+ WriteRawVarint32((uint)bytes.Length);
+ WriteRawBytes(bytes);
+ }
+
+ /// <summary>
+ /// Writes a group field value, including tag, to the stream.
+ /// </summary>
+ public void WriteGroup(int fieldNumber, IMessage value) {
+ WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
+ value.WriteTo(this);
+ WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
+ }
+
+ public void WriteUnknownGroup(int fieldNumber, UnknownFieldSet value) {
+ WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
+ value.WriteTo(this);
+ WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
+ }
+
+ public void WriteMessage(int fieldNumber, IMessage value) {
+ WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
+ WriteRawVarint32((uint)value.SerializedSize);
+ value.WriteTo(this);
+ }
+
+ public void WriteBytes(int fieldNumber, ByteString value) {
+ // TODO(jonskeet): Optimise this! (No need to copy the bytes twice.)
+ byte[] bytes = value.ToByteArray();
+ WriteRawVarint32((uint)bytes.Length);
+ WriteRawBytes(bytes);
+ }
+
+ public void WriteUInt32(int fieldNumber, uint value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Varint);
+ WriteRawVarint32(value);
+ }
+
+ public void WriteEnum(int fieldNumber, int value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Varint);
+ WriteRawVarint32((uint)value);
+ }
+
+ public void WriteSFixed32(int fieldNumber, int value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
+ WriteRawVarint32((uint)value);
+ }
+
+ public void WriteSFixed64(int fieldNumber, long value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
+ WriteRawVarint64((ulong)value);
+ }
+
+ public void WriteSInt32(int fieldNumber, int value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Varint);
+ WriteRawVarint32(EncodeZigZag32(value));
+ }
+
+ public void WriteSInt64(int fieldNumber, long value) {
+ WriteTag(fieldNumber, WireFormat.WireType.Varint);
+ WriteRawVarint64(EncodeZigZag64(value));
+ }
+
+ public void WriteMessageSetExtension(int fieldNumber, IMessage value) {
+ WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
+ WriteUInt32(WireFormat.MessageSetField.TypeID, (uint)fieldNumber);
+ WriteMessage(WireFormat.MessageSetField.Message, value);
+ WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
+ }
+
+ public void WriteRawMessageSetExtension(int fieldNumber, ByteString value) {
+ WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
+ WriteUInt32(WireFormat.MessageSetField.TypeID, (uint)fieldNumber);
+ WriteBytes(WireFormat.MessageSetField.Message, value);
+ WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
+ }
+
+ public void WriteField(Descriptors.FieldDescriptor.Type fieldType, int fieldNumber, object value) {
+ switch (fieldType) {
+ case Descriptors.FieldDescriptor.Type.Double: WriteDouble(fieldNumber, (double)value); break;
+ case Descriptors.FieldDescriptor.Type.Float: WriteFloat(fieldNumber, (float)value); break;
+ case Descriptors.FieldDescriptor.Type.Int64: WriteInt64(fieldNumber, (long)value); break;
+ case Descriptors.FieldDescriptor.Type.UInt64: WriteUInt64(fieldNumber, (ulong)value); break;
+ case Descriptors.FieldDescriptor.Type.Int32: WriteInt32(fieldNumber, (int)value); break;
+ case Descriptors.FieldDescriptor.Type.Fixed64: WriteFixed64(fieldNumber, (long)value); break;
+ case Descriptors.FieldDescriptor.Type.Fixed32: WriteFixed32(fieldNumber, (int)value); break;
+ case Descriptors.FieldDescriptor.Type.Bool: WriteBool(fieldNumber, (bool)value); break;
+ case Descriptors.FieldDescriptor.Type.String: WriteString(fieldNumber, (string)value); break;
+ case Descriptors.FieldDescriptor.Type.Group: WriteGroup(fieldNumber, (IMessage)value); break;
+ case Descriptors.FieldDescriptor.Type.Message: WriteMessage(fieldNumber, (IMessage)value); break;
+ case Descriptors.FieldDescriptor.Type.Bytes: WriteBytes(fieldNumber, (ByteString)value); break;
+ case Descriptors.FieldDescriptor.Type.UInt32: WriteUInt32(fieldNumber, (uint)value); break;
+ case Descriptors.FieldDescriptor.Type.SFixed32: WriteSFixed32(fieldNumber, (int)value); break;
+ case Descriptors.FieldDescriptor.Type.SFixed64: WriteSFixed64(fieldNumber, (long)value); break;
+ case Descriptors.FieldDescriptor.Type.SInt32: WriteSInt32(fieldNumber, (int)value); break;
+ case Descriptors.FieldDescriptor.Type.SInt64: WriteSInt64(fieldNumber, (long)value); break;
+ case Descriptors.FieldDescriptor.Type.Enum: WriteEnum(fieldNumber, ((Descriptors.EnumValueDescriptor)value).Number);
+ break;
+ }
+ }
+
+ #endregion
+
+ #region Underlying writing primitives
+ /// <summary>
+ /// Encodes and writes a tag.
+ /// </summary>
+ public void WriteTag(int fieldNumber, WireFormat.WireType type) {
+ WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
+ }
+
+ public void WriteRawVarint32(uint value) {
+ while (true) {
+ if ((value & ~0x7F) == 0) {
+ WriteRawByte(value);
+ return;
+ } else {
+ WriteRawByte((value & 0x7F) | 0x80);
+ value >>= 7;
+ }
+ }
+ }
+
+ public void WriteRawVarint64(ulong value) {
+ while (true) {
+ if ((value & ~0x7FUL) == 0) {
+ WriteRawByte((uint)value);
+ return;
+ } else {
+ WriteRawByte(((uint)value & 0x7F) | 0x80);
+ value >>= 7;
+ }
+ }
+ }
+
+ public void WriteRawLittleEndian32(int value) {
+ WriteRawByte((byte)value);
+ WriteRawByte((byte)(value >> 8));
+ WriteRawByte((byte)(value >> 16));
+ WriteRawByte((byte)(value >> 24));
+ }
+
+ public void WriteRawLittleEndian64(long value) {
+ WriteRawByte((byte)value);
+ WriteRawByte((byte)(value >> 8));
+ WriteRawByte((byte)(value >> 16));
+ WriteRawByte((byte)(value >> 24));
+ WriteRawByte((byte)(value >> 32));
+ WriteRawByte((byte)(value >> 40));
+ WriteRawByte((byte)(value >> 48));
+ WriteRawByte((byte)(value >> 56));
+ }
+
+ public void WriteRawByte(byte value) {
+ if (position == limit) {
+ RefreshBuffer();
+ }
+
+ buffer[position++] = value;
+ }
+
+ public void WriteRawByte(uint value) {
+ WriteRawByte((byte)value);
+ }
+
+ /// <summary>
+ /// Writes out an array of bytes.
+ /// </summary>
+ public void WriteRawBytes(byte[] value) {
+ WriteRawBytes(value, 0, value.Length);
+ }
+
+ /// <summary>
+ /// Writes out part of an array of bytes.
+ /// </summary>
+ public void WriteRawBytes(byte[] value, int offset, int length) {
+ if (limit - position >= length) {
+ Array.Copy(value, offset, buffer, position, length);
+ // We have room in the current buffer.
+ position += length;
+ } else {
+ // Write extends past current buffer. Fill the rest of this buffer and
+ // flush.
+ int bytesWritten = limit - position;
+ Array.Copy(value, offset, buffer, position, bytesWritten);
+ offset += bytesWritten;
+ length -= bytesWritten;
+ position = limit;
+ RefreshBuffer();
+
+ // Now deal with the rest.
+ // Since we have an output stream, this is our buffer
+ // and buffer offset == 0
+ if (length <= limit) {
+ // Fits in new buffer.
+ Array.Copy(value, offset, buffer, 0, length);
+ position = length;
+ } else {
+ // Write is very big. Let's do it all at once.
+ output.Write(value, offset, length);
+ }
+ }
+ }
+ #endregion
+
+ #region Size computations
+
+ const int LittleEndian64Size = 8;
+ const int LittleEndian32Size = 4;
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// double field, including the tag.
+ /// </summary>
+ public static int ComputeDoubleSize(int fieldNumber, double value) {
+ return ComputeTagSize(fieldNumber) + LittleEndian64Size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// float field, including the tag.
+ /// </summary>
+ public static int ComputeFloatSize(int fieldNumber, float value) {
+ return ComputeTagSize(fieldNumber) + LittleEndian32Size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// uint64 field, including the tag.
+ /// </summary>
+ public static int ComputeUInt64Size(int fieldNumber, ulong value) {
+ return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size(value);
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// int64 field, including the tag.
+ /// </summary>
+ public static int ComputeInt64Size(int fieldNumber, long value) {
+ return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size((ulong)value);
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// int32 field, including the tag.
+ /// </summary>
+ public static int ComputeInt32Size(int fieldNumber, int value) {
+ if (value >= 0) {
+ return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint)value);
+ } else {
+ // Must sign-extend.
+ return ComputeTagSize(fieldNumber) + 10;
+ }
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// fixed64 field, including the tag.
+ /// </summary>
+ public static int ComputeFixed64Size(int fieldNumber, long value) {
+ return ComputeTagSize(fieldNumber) + LittleEndian64Size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// fixed32 field, including the tag.
+ /// </summary>
+ public static int ComputeFixed32Size(int fieldNumber, int value) {
+ return ComputeTagSize(fieldNumber) + LittleEndian32Size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// bool field, including the tag.
+ /// </summary>
+ public static int ComputeBoolSize(int fieldNumber, bool value) {
+ return ComputeTagSize(fieldNumber) + 1;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// string field, including the tag.
+ /// </summary>
+ public static int ComputeStringSize(int fieldNumber, String value) {
+ int byteArraySize = Encoding.UTF8.GetByteCount(value);
+ return ComputeTagSize(fieldNumber) +
+ ComputeRawVarint32Size((uint)byteArraySize) +
+ byteArraySize;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// group field, including the tag.
+ /// </summary>
+ public static int ComputeGroupSize(int fieldNumber, IMessage value) {
+ return ComputeTagSize(fieldNumber) * 2 + value.SerializedSize;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// group field represented by an UnknownFieldSet, including the tag.
+ /// </summary>
+ public static int ComputeUnknownGroupSize(int fieldNumber,
+ UnknownFieldSet value) {
+ return ComputeTagSize(fieldNumber) * 2 + value.SerializedSize;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// embedded message field, including the tag.
+ /// </summary>
+ public static int ComputeMessageSize(int fieldNumber, IMessage value) {
+ int size = value.SerializedSize;
+ return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint)size) + size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// bytes field, including the tag.
+ /// </summary>
+ public static int ComputeBytesSize(int fieldNumber, ByteString value) {
+ return ComputeTagSize(fieldNumber) +
+ ComputeRawVarint32Size((uint)value.Length) +
+ value.Length;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// uint32 field, including the tag.
+ /// </summary>
+ public static int ComputeUInt32Size(int fieldNumber, uint value) {
+ return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size(value);
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// enum field, including the tag. The caller is responsible for
+ /// converting the enum value to its numeric value.
+ /// </summary>
+ public static int ComputeEnumSize(int fieldNumber, int value) {
+ return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint)value);
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// sfixed32 field, including the tag.
+ /// </summary>
+ public static int ComputeSFixed32Size(int fieldNumber, int value) {
+ return ComputeTagSize(fieldNumber) + LittleEndian32Size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// sfixed64 field, including the tag.
+ /// </summary>
+ public static int ComputeSFixed64Size(int fieldNumber, long value) {
+ return ComputeTagSize(fieldNumber) + LittleEndian64Size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// sint32 field, including the tag.
+ /// </summary>
+ public static int ComputeSInt32Size(int fieldNumber, int value) {
+ return ComputeTagSize(fieldNumber) +
+ ComputeRawVarint32Size(EncodeZigZag32(value));
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// sint64 field, including the tag.
+ /// </summary>
+ public static int ComputeSInt64Size(int fieldNumber, long value) {
+ return ComputeTagSize(fieldNumber) +
+ ComputeRawVarint64Size(EncodeZigZag64(value));
+ }
+
+ /*
+ * Compute the number of bytes that would be needed to encode a
+ * MessageSet extension to the stream. For historical reasons,
+ * the wire format differs from normal fields.
+ */
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// MessageSet extension to the stream. For historical reasons,
+ /// the wire format differs from normal fields.
+ /// </summary>
+ public static int ComputeMessageSetExtensionSize(int fieldNumber, IMessage value) {
+ return ComputeTagSize(WireFormat.MessageSetField.Item) * 2 +
+ ComputeUInt32Size(WireFormat.MessageSetField.TypeID, (uint) fieldNumber) +
+ ComputeMessageSize(WireFormat.MessageSetField.Message, value);
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// unparsed MessageSet extension field to the stream. For
+ /// historical reasons, the wire format differs from normal fields.
+ /// </summary>
+ public static int ComputeRawMessageSetExtensionSize(int fieldNumber, ByteString value) {
+ return ComputeTagSize(WireFormat.MessageSetField.Item) * 2 +
+ ComputeUInt32Size(WireFormat.MessageSetField.TypeID, (uint) fieldNumber) +
+ ComputeBytesSize(WireFormat.MessageSetField.Message, value);
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a varint.
+ /// </summary>
+ public static int ComputeRawVarint32Size(uint value) {
+ if ((value & (0xffffffff << 7)) == 0) return 1;
+ if ((value & (0xffffffff << 14)) == 0) return 2;
+ if ((value & (0xffffffff << 21)) == 0) return 3;
+ if ((value & (0xffffffff << 28)) == 0) return 4;
+ return 5;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a varint.
+ /// </summary>
+ public static int ComputeRawVarint64Size(ulong value) {
+ if ((value & (0xffffffffffffffffL << 7)) == 0) return 1;
+ if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
+ if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
+ if ((value & (0xffffffffffffffffL << 28)) == 0) return 4;
+ if ((value & (0xffffffffffffffffL << 35)) == 0) return 5;
+ if ((value & (0xffffffffffffffffL << 42)) == 0) return 6;
+ if ((value & (0xffffffffffffffffL << 49)) == 0) return 7;
+ if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
+ if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
+ return 10;
+ }
+
+
+ /*
+ * Compute the number of bytes that would be needed to encode a
+ * field of arbitrary type, including tag, to the stream.
+ *
+ * @param type The field's type.
+ * @param number The field's number.
+ * @param value Object representing the field's value. Must be of the exact
+ * type which would be returned by
+ * {@link Message#getField(Descriptors.FieldDescriptor)} for
+ * this field.
+ */
+ public static int ComputeFieldSize(Descriptors.FieldDescriptor.Type fieldType, int fieldNumber, Object value) {
+ switch (fieldType) {
+ case Descriptors.FieldDescriptor.Type.Double: return ComputeDoubleSize(fieldNumber, (double)value);
+ case Descriptors.FieldDescriptor.Type.Float: return ComputeFloatSize(fieldNumber, (float)value);
+ case Descriptors.FieldDescriptor.Type.Int64: return ComputeInt64Size(fieldNumber, (long)value);
+ case Descriptors.FieldDescriptor.Type.UInt64: return ComputeUInt64Size(fieldNumber, (ulong)value);
+ case Descriptors.FieldDescriptor.Type.Int32: return ComputeInt32Size(fieldNumber, (int)value);
+ case Descriptors.FieldDescriptor.Type.Fixed64: return ComputeFixed64Size(fieldNumber, (long)value);
+ case Descriptors.FieldDescriptor.Type.Fixed32: return ComputeFixed32Size(fieldNumber, (int)value);
+ case Descriptors.FieldDescriptor.Type.Bool: return ComputeBoolSize(fieldNumber, (bool)value);
+ case Descriptors.FieldDescriptor.Type.String: return ComputeStringSize(fieldNumber, (string)value);
+ case Descriptors.FieldDescriptor.Type.Group: return ComputeGroupSize(fieldNumber, (IMessage)value);
+ case Descriptors.FieldDescriptor.Type.Message: return ComputeMessageSize(fieldNumber, (IMessage)value);
+ case Descriptors.FieldDescriptor.Type.Bytes: return ComputeBytesSize(fieldNumber, (ByteString)value);
+ case Descriptors.FieldDescriptor.Type.UInt32: return ComputeUInt32Size(fieldNumber, (uint)value);
+ case Descriptors.FieldDescriptor.Type.SFixed32: return ComputeSFixed32Size(fieldNumber, (int)value);
+ case Descriptors.FieldDescriptor.Type.SFixed64: return ComputeSFixed64Size(fieldNumber, (long)value);
+ case Descriptors.FieldDescriptor.Type.SInt32: return ComputeSInt32Size(fieldNumber, (int)value);
+ case Descriptors.FieldDescriptor.Type.SInt64: return ComputeSInt64Size(fieldNumber, (long)value);
+ case Descriptors.FieldDescriptor.Type.Enum: return ComputeEnumSize(fieldNumber, ((Descriptors.EnumValueDescriptor)value).Number);
+ default:
+ throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
+ }
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a tag.
+ /// </summary>
+ public static int ComputeTagSize(int fieldNumber) {
+ return ComputeRawVarint32Size(WireFormat.MakeTag(fieldNumber, 0));
+ }
+ #endregion
+
+ /// <summary>
+ /// Encode a 32-bit value with ZigZag encoding.
+ /// </summary>
+ /// <remarks>
+ /// ZigZag encodes signed integers into values that can be efficiently
+ /// encoded with varint. (Otherwise, negative values must be
+ /// sign-extended to 64 bits to be varint encoded, thus always taking
+ /// 10 bytes on the wire.)
+ /// </remarks>
+ public static uint EncodeZigZag32(int n) {
+ // Note: the right-shift must be arithmetic
+ return (uint)((n << 1) ^ (n >> 31));
+ }
+
+ /// <summary>
+ /// Encode a 64-bit value with ZigZag encoding.
+ /// </summary>
+ /// <remarks>
+ /// ZigZag encodes signed integers into values that can be efficiently
+ /// encoded with varint. (Otherwise, negative values must be
+ /// sign-extended to 64 bits to be varint encoded, thus always taking
+ /// 10 bytes on the wire.)
+ /// </remarks>
+ public static ulong EncodeZigZag64(long n) {
+ return (ulong)((n << 1) ^ (n >> 63));
+ }
+
+ private void RefreshBuffer() {
+ if (output == null) {
+ // We're writing to a single buffer.
+ throw new OutOfSpaceException();
+ }
+
+ // Since we have an output stream, this is our buffer
+ // and buffer offset == 0
+ output.Write(buffer, 0, position);
+ position = 0;
+ }
+
+ /// <summary>
+ /// Indicates that a CodedOutputStream wrapping a flat byte array
+ /// ran out of space.
+ /// </summary>
+ public class OutOfSpaceException : IOException {
+ internal OutOfSpaceException()
+ : base("CodedOutputStream was writing to a flat byte array and ran out of space.") {
+ }
+ }
+
+ public void Flush() {
+ if (output != null) {
+ RefreshBuffer();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/ProtocolBuffers/Descriptors.cs b/csharp/ProtocolBuffers/Descriptors.cs
new file mode 100644
index 00000000..ae09ee5a
--- /dev/null
+++ b/csharp/ProtocolBuffers/Descriptors.cs
@@ -0,0 +1,39 @@
+
+using System;
+
+namespace Google.ProtocolBuffers {
+ public class Descriptors {
+ public class Descriptor {
+ }
+ public class FieldDescriptor {
+ public enum Type {
+ Double,
+ Float,
+ Int64,
+ UInt64,
+ Int32,
+ Fixed64,
+ Fixed32,
+ Bool,
+ String,
+ Group,
+ Message,
+ Bytes,
+ UInt32,
+ SFixed32,
+ SFixed64,
+ SInt32,
+ SInt64,
+ Enum
+ }
+ }
+
+ public class EnumValueDescriptor
+ {
+ public int Number
+ {
+ get { throw new NotImplementedException(); }
+ }
+ }
+ }
+}
diff --git a/csharp/ProtocolBuffers/ExtensionRegistry.cs b/csharp/ProtocolBuffers/ExtensionRegistry.cs
new file mode 100644
index 00000000..54d86ad7
--- /dev/null
+++ b/csharp/ProtocolBuffers/ExtensionRegistry.cs
@@ -0,0 +1,5 @@
+
+namespace Google.ProtocolBuffers {
+ public class ExtensionRegistry {
+ }
+}
diff --git a/csharp/ProtocolBuffers/IBuilder.cs b/csharp/ProtocolBuffers/IBuilder.cs
new file mode 100644
index 00000000..ebd6b408
--- /dev/null
+++ b/csharp/ProtocolBuffers/IBuilder.cs
@@ -0,0 +1,227 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace Google.ProtocolBuffers {
+
+ /// <summary>
+ /// Interface implemented by Protocol Message builders.
+ /// TODO(jonskeet): Consider "SetXXX" methods returning the builder, as well as the properties.
+ /// </summary>
+ /// <typeparam name="T">Type of message</typeparam>
+ public interface IBuilder<T> where T : IMessage<T> {
+ /// <summary>
+ /// Resets all fields to their default values.
+ /// </summary>
+ IBuilder<T> Clear();
+
+ /// <summary>
+ /// Merge the specified other message into the message being
+ /// built. Merging occurs as follows. For each field:
+ /// For singular primitive fields, if the field is set in <paramref name="other"/>,
+ /// then <paramref name="other"/>'s value overwrites the value in this message.
+ /// For singular message fields, if the field is set in <paramref name="other"/>,
+ /// it is merged into the corresponding sub-message of this message using the same
+ /// merging rules.
+ /// For repeated fields, the elements in <paramref name="other"/> are concatenated
+ /// with the elements in this message.
+ /// </summary>
+ /// <param name="other"></param>
+ /// <returns></returns>
+ IBuilder<T> MergeFrom(IMessage<T> other);
+
+ /// <summary>
+ /// Constructs the final message. Once this is called, this Builder instance
+ /// is no longer valid, and calling any other method may throw a
+ /// NullReferenceException. If you need to continue working with the builder
+ /// after calling Build, call Clone first.
+ /// </summary>
+ /// <exception cref="UninitializedMessageException">the message
+ /// is missing one or more required fields; use BuildPartial to bypass
+ /// this check</exception>
+ IMessage<T> Build();
+
+ /// <summary>
+ /// Like Build(), but does not throw an exception if the message is missing
+ /// required fields. Instead, a partial message is returned.
+ /// </summary>
+ /// <returns></returns>
+ IMessage<T> BuildPartial();
+
+ /// <summary>
+ /// Clones this builder.
+ /// TODO(jonskeet): Explain depth of clone.
+ /// </summary>
+ IBuilder<T> Clone();
+
+ /// <summary>
+ /// Returns true iff all required fields in the message and all
+ /// embedded messages are set.
+ /// </summary>
+ bool Initialized { get; }
+
+ /// <summary>
+ /// Parses a message of this type from the input and merges it with this
+ /// message, as if using MergeFrom(IMessage&lt;T&gt;).
+ /// </summary>
+ /// <remarks>
+ /// Warning: This does not verify that all required fields are present
+ /// in the input message. If you call Build() without setting all
+ /// required fields, it will throw an UninitializedMessageException.
+ /// There are a few good ways to deal with this:
+ /// <list>
+ /// <item>Call Initialized to verify to verify that all required fields are
+ /// set before building.</item>
+ /// <item>Parse the message separately using one of the static ParseFrom
+ /// methods, then use MergeFrom(IMessage&lt;T&gt;) to merge it with
+ /// this one. ParseFrom will throw an InvalidProtocolBufferException
+ /// (an IOException) if some required fields are missing.
+ /// Use BuildPartial to build, which ignores missing required fields.
+ /// </list>
+ /// </remarks>
+ IBuilder<T> MergeFrom(CodedInputStream input);
+
+ /// <summary>
+ /// Like MergeFrom(CodedInputStream), but also parses extensions.
+ /// The extensions that you want to be able to parse must be registered
+ /// in <paramref name="extensionRegistry"/>. Extensions not in the registry
+ /// will be treated as unknown fields.
+ /// </summary>
+ IBuilder<T> MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry);
+
+ /// <summary>
+ /// Get the message's type's descriptor.
+ /// <see cref="IMessage{T}.DescriptorForType"/>
+ /// </summary>
+ Descriptors.Descriptor DescriptorForType { get; }
+
+ /// <summary>
+ /// Get's the message's type's default instance.
+ /// <see cref="IMessage{T}.DefaultInstanceForType" />
+ /// </summary>
+ IMessage<T> DefaultInstanceForType { get; }
+
+ /// <summary>
+ /// Behaves like the equivalent property in IMessage&lt;T&gt;.
+ /// The returned map may or may not reflect future changes to the builder.
+ /// Either way, the returned map is unmodifiable.
+ /// </summary>
+ IDictionary<ProtocolBuffers.Descriptors.FieldDescriptor, object> AllFields { get; }
+
+ /// <summary>
+ /// Create a builder for messages of the appropriate type for the given field.
+ /// Messages built with this can then be passed to the various mutation properties
+ /// and methods.
+ /// </summary>
+ /// <typeparam name="TField"></typeparam>
+ /// <param name="field"></param>
+ /// <returns></returns>
+ IBuilder<TField> NewBuilderForField<TField>(Descriptors.FieldDescriptor field)
+ where TField : IMessage<TField>;
+
+ /// <summary>
+ /// <see cref="IMessage{T}.HasField"/>
+ /// </summary>
+ bool HasField(Descriptors.FieldDescriptor field);
+
+ /// <summary>
+ /// Allows getting and setting of a field.
+ /// <see cref="IMessage{T}.Item(Descriptors.FieldDescriptor)"/>
+ /// </summary>
+ /// <param name="field"></param>
+ /// <returns></returns>
+ object this[Descriptors.FieldDescriptor field] { get; set; }
+
+ /// <summary>
+ /// Clears the field. This is exactly equivalent to calling the generated
+ /// Clear method corresponding to the field.
+ /// </summary>
+ /// <param name="field"></param>
+ /// <returns></returns>
+ IBuilder<T> ClearField(Descriptors.FieldDescriptor field);
+
+ /// <summary>
+ /// <see cref="IMessage{T}.GetRepeatedFieldCount"/>
+ /// </summary>
+ /// <param name="field"></param>
+ /// <returns></returns>
+ int GetRepeatedFieldCount(Descriptors.FieldDescriptor field);
+
+
+ /// <summary>
+ /// Allows getting and setting of a repeated field value.
+ /// <see cref="IMessage{T}.Item(Descriptors.FieldDescriptor, int)"/>
+ /// </summary>
+ object this[Descriptors.FieldDescriptor field, int index] { get; set; }
+
+ /// <summary>
+ /// Appends the given value as a new element for the specified repeated field.
+ /// </summary>
+ /// <exception cref="ArgumentException">the field is not a repeated field,
+ /// the field does not belong to this builder's type, or the value is
+ /// of the incorrect type
+ /// </exception>
+ IBuilder<T> AddRepeatedField(Descriptors.FieldDescriptor field, object value);
+
+ /// <summary>
+ /// <see cref="IMessage{T}.UnknownFields"/>
+ /// </summary>
+ UnknownFieldSet UnknownFields { get; set; }
+
+ /// <summary>
+ /// Merge some unknown fields into the set for this message.
+ /// </summary>
+ IBuilder<T> MergeUnknownFields(UnknownFieldSet unknownFields);
+
+ #region Convenience methods
+ // TODO(jonskeet): Implement these as extension methods?
+
+ /// <summary>
+ /// Parse <paramref name="data"/> as a message of this type and merge
+ /// it with the message being built. This is just a small wrapper around
+ /// MergeFrom(CodedInputStream).
+ /// </summary>
+ IBuilder<T> MergeFrom(ByteString data);
+
+ /// <summary>
+ /// Parse <paramref name="data"/> as a message of this type and merge
+ /// it with the message being built. This is just a small wrapper around
+ /// MergeFrom(CodedInputStream, ExtensionRegistry).
+ /// </summary>
+ IBuilder<T> MergeFrom(ByteString data, ExtensionRegistry extensionRegistry);
+
+ /// <summary>
+ /// Parse <paramref name="data"/> as a message of this type and merge
+ /// it with the message being built. This is just a small wrapper around
+ /// MergeFrom(CodedInputStream).
+ /// </summary>
+ IBuilder<T> MergeFrom(byte[] data);
+
+ /// <summary>
+ /// Parse <paramref name="data"/> as a message of this type and merge
+ /// it with the message being built. This is just a small wrapper around
+ /// MergeFrom(CodedInputStream, ExtensionRegistry).
+ /// </summary>
+ IBuilder<T> MergeFrom(byte[] data, ExtensionRegistry extensionRegistry);
+
+ /// <summary>
+ /// Parse <paramref name="data"/> as a message of this type and merge
+ /// it with the message being built. This is just a small wrapper around
+ /// MergeFrom(CodedInputStream). Note that this method always reads
+ /// the entire input (unless it throws an exception). If you want it to
+ /// stop earlier, you will need to wrap the input in a wrapper
+ /// stream which limits reading. Despite usually reading the entire
+ /// stream, this method never closes the stream.
+ /// </summary>
+ IBuilder<T> MergeFrom(Stream input);
+
+ /// <summary>
+ /// Parse <paramref name="data"/> as a message of this type and merge
+ /// it with the message being built. This is just a small wrapper around
+ /// MergeFrom(CodedInputStream, ExtensionRegistry).
+ /// </summary>
+ IBuilder<T> MergeFrom(Stream input, ExtensionRegistry extensionRegistry);
+ #endregion
+ }
+}
diff --git a/csharp/ProtocolBuffers/IMessage.cs b/csharp/ProtocolBuffers/IMessage.cs
new file mode 100644
index 00000000..6a41d78e
--- /dev/null
+++ b/csharp/ProtocolBuffers/IMessage.cs
@@ -0,0 +1,162 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Google.ProtocolBuffers {
+
+ /// <summary>
+ /// Non-generic interface.
+ /// TODO(jonskeet): Do we want or need this?
+ /// </summary>
+ public interface IMessage {
+ void WriteTo(CodedOutputStream output);
+ int SerializedSize { get; }
+ }
+
+ /// <summary>
+ /// Interface implemented by all Protocol Buffers messages.
+ /// </summary>
+ public interface IMessage<T> where T : IMessage<T> {
+ /// <summary>
+ /// Returns the message's type's descriptor. This differs from the
+ /// Descriptor property of each generated message class in that this
+ /// method is an abstract method of IMessage whereas Descriptor is
+ /// a static property of a specific class. They return the same thing.
+ /// </summary>
+ Descriptors.Descriptor DescriptorForType { get; }
+
+ /// <summary>
+ /// Returns an instance of this message type with all fields set to
+ /// their default values. This may or may not be a singleton. This differs
+ /// from the DefaultInstance property of each generated message class in that this
+ /// method is an abstract method of IMessage whereas DefaultInstance is
+ /// a static property of a specific class. They return the same thing.
+ /// </summary>
+ IMessage<T> DefaultInstanceForType { get; }
+
+ /// <summary>
+ /// Returns a collection of all the fields in this message which are set
+ /// and their corresponding values. A singular ("required" or "optional")
+ /// field is set iff HasField() returns true for that field. A "repeated"
+ /// field is set iff GetRepeatedFieldSize() is greater than zero. The
+ /// values are exactly what would be returned by calling
+ /// GetField(Descriptors.FieldDescriptor) for each field. The map
+ /// is guaranteed to be a sorted map, so iterating over it will return fields
+ /// in order by field number.
+ /// </summary>
+ IDictionary<Descriptors.FieldDescriptor, object> AllFields { get; }
+
+ /// <summary>
+ /// Returns true if the given field is set. This is exactly equivalent
+ /// to calling the generated "Has" property corresponding to the field.
+ /// </summary>
+ /// <exception cref="ArgumentException">the field is a repeated field,
+ /// or it's not a field of this type</exception>
+ bool HasField(Descriptors.FieldDescriptor field);
+
+ /// <summary>
+ /// Obtains the value of the given field, or the default value if
+ /// it isn't set. For value type fields including enums, the boxed
+ /// value is returned. For embedded message fields, the sub-message
+ /// is returned. For repeated fields, an IList&lt;T&gt; is returned.
+ /// </summary>
+ object this[Descriptors.FieldDescriptor field] { get; }
+
+ /// <summary>
+ /// Returns the number of elements of a repeated field. This is
+ /// exactly equivalent to calling the generated "Count" property
+ /// corresponding to the field.
+ /// </summary>
+ /// <exception cref="ArgumentException">the field is not a repeated field,
+ /// or it's not a field of this type</exception>
+ int GetRepeatedFieldCount(Descriptors.FieldDescriptor field);
+
+ /// <summary>
+ /// Gets an element of a repeated field. For value type fields
+ /// including enums, the boxed value is returned. For embedded
+ /// message fields, the sub-message is returned.
+ /// </summary>
+ /// <exception cref="ArgumentException">the field is not a repeated field,
+ /// or it's not a field of this type</exception>
+ /// <exception cref="ArgumentOutOfRangeException">the index is out of
+ /// range for the repeated field's value</exception>
+ object this[Descriptors.FieldDescriptor field, int index] { get; }
+
+ /// <summary>
+ /// Returns the unknown fields for this message.
+ /// </summary>
+ UnknownFieldSet UnknownFields { get; }
+
+ /// <summary>
+ /// Returns true iff all required fields in the message and all embedded
+ /// messages are set.
+ /// </summary>
+ bool Initialized { get; }
+
+ /// <summary>
+ /// Serializes the message and writes it to the given output stream.
+ /// This does not flush or close the stream.
+ /// </summary>
+ /// <param name="output"></param>
+ void WriteTo(CodedOutputStream output);
+
+ /// <summary>
+ /// Returns the number of bytes required to encode this message.
+ /// The result is only computed on the first call and memoized after that.
+ /// </summary>
+ int SerializedSize { get; }
+
+ #region Comparison and hashing
+ /// <summary>
+ /// Compares the specified object with this message for equality.
+ /// Returns true iff the given object is a message of the same type
+ /// (as defined by DescriptorForType) and has identical values
+ /// for all its fields.
+ /// </summary>
+ bool Equals(object other);
+
+ /// <summary>
+ /// Returns the hash code value for this message.
+ /// TODO(jonskeet): Specify the hash algorithm, but better than the Java one!
+ /// </summary>
+ /// <returns></returns>
+ int GetHashCode();
+ #endregion
+
+ #region Convenience methods
+ /// <summary>
+ /// Converts the message to a string in protocol buffer text format.
+ /// This is just a trivial wrapper around TextFormat.PrintToString.
+ /// </summary>
+ string ToString();
+
+ /// <summary>
+ /// Serializes the message to a ByteString. This is a trivial wrapper
+ /// around WriteTo(CodedOutputStream).
+ /// </summary>
+ ByteString ToByteString();
+
+ /// <summary>
+ /// Serializes the message to a byte array. This is a trivial wrapper
+ /// around WriteTo(CodedOutputStream).
+ /// </summary>
+ byte[] ToByteArray();
+
+ /// <summary>
+ /// Serializes the message and writes it to the given stream.
+ /// This is just a wrapper around WriteTo(CodedOutputStream). This
+ /// does not flush or close the stream.
+ /// </summary>
+ /// <param name="output"></param>
+ void WriteTo(Stream output);
+ #endregion
+
+ #region Builders
+ /// <summary>
+ /// Constructs a new builder for a message of the same type as this message.
+ /// </summary>
+ IBuilder<T> NewBuilderForType();
+ #endregion
+
+ }
+}
diff --git a/csharp/ProtocolBuffers/InvalidProtocolBufferException.cs b/csharp/ProtocolBuffers/InvalidProtocolBufferException.cs
new file mode 100644
index 00000000..8b61f9f1
--- /dev/null
+++ b/csharp/ProtocolBuffers/InvalidProtocolBufferException.cs
@@ -0,0 +1,7 @@
+using System;
+using System.IO;
+
+namespace Google.ProtocolBuffers {
+ public class InvalidProtocolBufferException : IOException {
+ }
+}
diff --git a/csharp/ProtocolBuffers/Properties/AssemblyInfo.cs b/csharp/ProtocolBuffers/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..4653dbe3
--- /dev/null
+++ b/csharp/ProtocolBuffers/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 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("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("279b643d-70e8-47ae-9eb1-500d1c48bab6")]
+
+// 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("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/csharp/ProtocolBuffers/ProtocolBuffers.csproj b/csharp/ProtocolBuffers/ProtocolBuffers.csproj
new file mode 100644
index 00000000..196f46d3
--- /dev/null
+++ b/csharp/ProtocolBuffers/ProtocolBuffers.csproj
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Google.ProtocolBuffers</RootNamespace>
+ <AssemblyName>Google.ProtocolBuffers</AssemblyName>
+ <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="ByteString.cs" />
+ <Compile Include="CodedInputStream.cs" />
+ <Compile Include="CodedOutputStream.cs" />
+ <Compile Include="Descriptors.cs" />
+ <Compile Include="ExtensionRegistry.cs" />
+ <Compile Include="IBuilder.cs" />
+ <Compile Include="IMessage.cs" />
+ <Compile Include="InvalidProtocolBufferException.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="UninitializedMessageException.cs" />
+ <Compile Include="UnknownFieldSet.cs" />
+ <Compile Include="WireFormat.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/csharp/ProtocolBuffers/UninitializedMessageException.cs b/csharp/ProtocolBuffers/UninitializedMessageException.cs
new file mode 100644
index 00000000..a77499af
--- /dev/null
+++ b/csharp/ProtocolBuffers/UninitializedMessageException.cs
@@ -0,0 +1,6 @@
+using System;
+
+namespace Google.ProtocolBuffers {
+ public class UninitializedMessageException : Exception {
+ }
+}
diff --git a/csharp/ProtocolBuffers/UnknownFieldSet.cs b/csharp/ProtocolBuffers/UnknownFieldSet.cs
new file mode 100644
index 00000000..a9602b3e
--- /dev/null
+++ b/csharp/ProtocolBuffers/UnknownFieldSet.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Google.ProtocolBuffers {
+ public class UnknownFieldSet {
+ public void WriteTo(CodedOutputStream output) {
+ throw new NotImplementedException();
+ }
+
+ public int SerializedSize { get { return 0; } }
+ }
+}
diff --git a/csharp/ProtocolBuffers/WireFormat.cs b/csharp/ProtocolBuffers/WireFormat.cs
new file mode 100644
index 00000000..df15526a
--- /dev/null
+++ b/csharp/ProtocolBuffers/WireFormat.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Google.ProtocolBuffers {
+ public class WireFormat {
+ public enum WireType {
+ Varint = 0,
+ Fixed64 = 1,
+ LengthDelimited = 2,
+ StartGroup = 3,
+ EndGroup = 4,
+ Fixed32 = 5
+ }
+
+ internal class MessageSetField {
+ internal const int Item = 1;
+ internal const int TypeID = 2;
+ internal const int Message = 3;
+ }
+
+ public static uint MakeTag(int fieldNumber, WireType type) {
+
+ // FIXME
+ return 0;
+ }
+ }
+}