aboutsummaryrefslogtreecommitdiff
path: root/src/ProtocolBuffers
diff options
context:
space:
mode:
authorcsharptest <roger@csharptest.net>2011-05-20 13:57:07 -0500
committerrogerk <devnull@localhost>2011-05-20 13:57:07 -0500
commitd965c666ecf405f4e997ab251e72551508a14678 (patch)
treed5a76f7fda1daebc6838f9fa44afa98bec1bea05 /src/ProtocolBuffers
parent62ce3a625e2a81f7631c73805b892c40ec8519f5 (diff)
downloadprotobuf-d965c666ecf405f4e997ab251e72551508a14678.tar.gz
protobuf-d965c666ecf405f4e997ab251e72551508a14678.tar.bz2
protobuf-d965c666ecf405f4e997ab251e72551508a14678.zip
line-ending-to-crlf
Diffstat (limited to 'src/ProtocolBuffers')
-rw-r--r--src/ProtocolBuffers/RpcUtil.cs142
-rw-r--r--src/ProtocolBuffers/SilverlightCompatibility.cs104
-rw-r--r--src/ProtocolBuffers/SortedList.cs342
-rw-r--r--src/ProtocolBuffers/TextFormat.cs1366
-rw-r--r--src/ProtocolBuffers/TextGenerator.cs286
-rw-r--r--src/ProtocolBuffers/TextTokenizer.cs824
-rw-r--r--src/ProtocolBuffers/ThrowHelper.cs146
-rw-r--r--src/ProtocolBuffers/UninitializedMessageException.cs340
-rw-r--r--src/ProtocolBuffers/UnknownField.cs742
-rw-r--r--src/ProtocolBuffers/UnknownFieldSet.cs1536
-rw-r--r--src/ProtocolBuffers/WireFormat.cs342
11 files changed, 3085 insertions, 3085 deletions
diff --git a/src/ProtocolBuffers/RpcUtil.cs b/src/ProtocolBuffers/RpcUtil.cs
index 48d389d0..d0614a37 100644
--- a/src/ProtocolBuffers/RpcUtil.cs
+++ b/src/ProtocolBuffers/RpcUtil.cs
@@ -1,71 +1,71 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://github.com/jskeet/dotnet-protobufs/
-// Original C++/Java/Python code:
-// http://code.google.com/p/protobuf/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System;
-
-namespace Google.ProtocolBuffers {
- /// <summary>
- /// Grab-bag of utility functions useful when dealing with RPCs.
- /// </summary>
- public static class RpcUtil {
-
- /// <summary>
- /// Converts an Action[IMessage] to an Action[T].
- /// </summary>
- public static Action<T> SpecializeCallback<T>(Action<IMessage> action)
- where T : IMessage<T> {
- return message => action(message);
- }
-
- /// <summary>
- /// Converts an Action[T] to an Action[IMessage].
- /// The generalized action will accept any message object which has
- /// the same descriptor, and will convert it to the correct class
- /// before calling the original action. However, if the generalized
- /// callback is given a message with a different descriptor, an
- /// exception will be thrown.
- /// </summary>
- public static Action<IMessage> GeneralizeCallback<TMessage, TBuilder>(Action<TMessage> action, TMessage defaultInstance)
- where TMessage : class, IMessage<TMessage, TBuilder>
- where TBuilder : IBuilder<TMessage, TBuilder> {
- return message => {
- TMessage castMessage = message as TMessage;
- if (castMessage == null) {
- castMessage = defaultInstance.CreateBuilderForType().MergeFrom(message).Build();
- }
- action(castMessage);
- };
- }
- }
-}
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+
+namespace Google.ProtocolBuffers {
+ /// <summary>
+ /// Grab-bag of utility functions useful when dealing with RPCs.
+ /// </summary>
+ public static class RpcUtil {
+
+ /// <summary>
+ /// Converts an Action[IMessage] to an Action[T].
+ /// </summary>
+ public static Action<T> SpecializeCallback<T>(Action<IMessage> action)
+ where T : IMessage<T> {
+ return message => action(message);
+ }
+
+ /// <summary>
+ /// Converts an Action[T] to an Action[IMessage].
+ /// The generalized action will accept any message object which has
+ /// the same descriptor, and will convert it to the correct class
+ /// before calling the original action. However, if the generalized
+ /// callback is given a message with a different descriptor, an
+ /// exception will be thrown.
+ /// </summary>
+ public static Action<IMessage> GeneralizeCallback<TMessage, TBuilder>(Action<TMessage> action, TMessage defaultInstance)
+ where TMessage : class, IMessage<TMessage, TBuilder>
+ where TBuilder : IBuilder<TMessage, TBuilder> {
+ return message => {
+ TMessage castMessage = message as TMessage;
+ if (castMessage == null) {
+ castMessage = defaultInstance.CreateBuilderForType().MergeFrom(message).Build();
+ }
+ action(castMessage);
+ };
+ }
+ }
+}
diff --git a/src/ProtocolBuffers/SilverlightCompatibility.cs b/src/ProtocolBuffers/SilverlightCompatibility.cs
index 37b45828..5f2e12b1 100644
--- a/src/ProtocolBuffers/SilverlightCompatibility.cs
+++ b/src/ProtocolBuffers/SilverlightCompatibility.cs
@@ -1,52 +1,52 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://github.com/jskeet/dotnet-protobufs/
-// Original C++/Java/Python code:
-// http://code.google.com/p/protobuf/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System.Text.RegularExpressions;
-
-namespace Google.ProtocolBuffers
-{
- /// <summary>
- /// Class containing helpful workarounds for Silverlight compatibility
- /// </summary>
- internal static class SilverlightCompatibility
- {
-
-#if SILVERLIGHT2
- internal const RegexOptions CompiledRegexWhereAvailable = RegexOptions.None;
-#else
- internal const RegexOptions CompiledRegexWhereAvailable = RegexOptions.Compiled;
-#endif
-
- }
-}
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.Text.RegularExpressions;
+
+namespace Google.ProtocolBuffers
+{
+ /// <summary>
+ /// Class containing helpful workarounds for Silverlight compatibility
+ /// </summary>
+ internal static class SilverlightCompatibility
+ {
+
+#if SILVERLIGHT2
+ internal const RegexOptions CompiledRegexWhereAvailable = RegexOptions.None;
+#else
+ internal const RegexOptions CompiledRegexWhereAvailable = RegexOptions.Compiled;
+#endif
+
+ }
+}
diff --git a/src/ProtocolBuffers/SortedList.cs b/src/ProtocolBuffers/SortedList.cs
index 14f14e30..da186ee5 100644
--- a/src/ProtocolBuffers/SortedList.cs
+++ b/src/ProtocolBuffers/SortedList.cs
@@ -1,172 +1,172 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://github.com/jskeet/dotnet-protobufs/
-// Original C++/Java/Python code:
-// http://code.google.com/p/protobuf/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-#if SILVERLIGHT2
-using System.Collections;
-using System.Collections.Generic;
-
-namespace Google.ProtocolBuffers
-{
- /// <summary>
- /// Dictionary implementation which always yields keys in sorted order.
- /// This is not particularly efficient: it wraps a normal dictionary
- /// for most operations, but sorts by key when either iterating or
- /// fetching the Keys/Values properties.
- /// This is only used for Silverlight, which doesn't have the normal
- /// sorted collections.
- /// </summary>
- internal sealed class SortedList<TKey, TValue> : IDictionary<TKey, TValue>
- {
- private readonly IDictionary<TKey, TValue> wrapped = new Dictionary<TKey, TValue>();
-
- public SortedList()
- {
- }
-
- public SortedList(IDictionary<TKey, TValue> dictionary)
- {
- foreach (KeyValuePair<TKey, TValue> entry in dictionary)
- {
- Add(entry.Key, entry.Value);
- }
- }
-
- public void Add(TKey key, TValue value)
- {
- wrapped.Add(key, value);
- }
-
- public bool ContainsKey(TKey key)
- {
- return wrapped.ContainsKey(key);
- }
-
- public ICollection<TKey> Keys
- {
- get
- {
- List<TKey> keys = new List<TKey>(wrapped.Count);
- foreach (var pair in this)
- {
- keys.Add(pair.Key);
- }
- return keys;
- }
- }
-
- public bool Remove(TKey key)
- {
- return wrapped.Remove(key);
- }
-
- public bool TryGetValue(TKey key, out TValue value)
- {
- return wrapped.TryGetValue(key, out value);
- }
-
- public ICollection<TValue> Values
- {
- get
- {
- List<TValue> values = new List<TValue>(wrapped.Count);
- foreach (var pair in this)
- {
- values.Add(pair.Value);
- }
- return values;
- }
- }
-
- public TValue this[TKey key]
- {
- get
- {
- return wrapped[key];
- }
- set
- {
- wrapped[key] = value;
- }
- }
-
- public void Add(KeyValuePair<TKey, TValue> item)
- {
- wrapped.Add(item);
- }
-
- public void Clear()
- {
- wrapped.Clear();
- }
-
- public bool Contains(KeyValuePair<TKey, TValue> item)
- {
- return wrapped.Contains(item);
- }
-
- public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
- {
- wrapped.CopyTo(array, arrayIndex);
- }
-
- public int Count
- {
- get { return wrapped.Count; }
- }
-
- public bool IsReadOnly
- {
- get { return wrapped.IsReadOnly; }
- }
-
- public bool Remove(KeyValuePair<TKey, TValue> item)
- {
- return wrapped.Remove(item);
- }
-
- public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
- {
- IComparer<TKey> comparer = Comparer<TKey>.Default;
- var list = new List<KeyValuePair<TKey, TValue>>(wrapped);
- list.Sort((x, y) => comparer.Compare(x.Key, y.Key));
- return list.GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
- }
-}
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+#if SILVERLIGHT2
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Google.ProtocolBuffers
+{
+ /// <summary>
+ /// Dictionary implementation which always yields keys in sorted order.
+ /// This is not particularly efficient: it wraps a normal dictionary
+ /// for most operations, but sorts by key when either iterating or
+ /// fetching the Keys/Values properties.
+ /// This is only used for Silverlight, which doesn't have the normal
+ /// sorted collections.
+ /// </summary>
+ internal sealed class SortedList<TKey, TValue> : IDictionary<TKey, TValue>
+ {
+ private readonly IDictionary<TKey, TValue> wrapped = new Dictionary<TKey, TValue>();
+
+ public SortedList()
+ {
+ }
+
+ public SortedList(IDictionary<TKey, TValue> dictionary)
+ {
+ foreach (KeyValuePair<TKey, TValue> entry in dictionary)
+ {
+ Add(entry.Key, entry.Value);
+ }
+ }
+
+ public void Add(TKey key, TValue value)
+ {
+ wrapped.Add(key, value);
+ }
+
+ public bool ContainsKey(TKey key)
+ {
+ return wrapped.ContainsKey(key);
+ }
+
+ public ICollection<TKey> Keys
+ {
+ get
+ {
+ List<TKey> keys = new List<TKey>(wrapped.Count);
+ foreach (var pair in this)
+ {
+ keys.Add(pair.Key);
+ }
+ return keys;
+ }
+ }
+
+ public bool Remove(TKey key)
+ {
+ return wrapped.Remove(key);
+ }
+
+ public bool TryGetValue(TKey key, out TValue value)
+ {
+ return wrapped.TryGetValue(key, out value);
+ }
+
+ public ICollection<TValue> Values
+ {
+ get
+ {
+ List<TValue> values = new List<TValue>(wrapped.Count);
+ foreach (var pair in this)
+ {
+ values.Add(pair.Value);
+ }
+ return values;
+ }
+ }
+
+ public TValue this[TKey key]
+ {
+ get
+ {
+ return wrapped[key];
+ }
+ set
+ {
+ wrapped[key] = value;
+ }
+ }
+
+ public void Add(KeyValuePair<TKey, TValue> item)
+ {
+ wrapped.Add(item);
+ }
+
+ public void Clear()
+ {
+ wrapped.Clear();
+ }
+
+ public bool Contains(KeyValuePair<TKey, TValue> item)
+ {
+ return wrapped.Contains(item);
+ }
+
+ public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+ {
+ wrapped.CopyTo(array, arrayIndex);
+ }
+
+ public int Count
+ {
+ get { return wrapped.Count; }
+ }
+
+ public bool IsReadOnly
+ {
+ get { return wrapped.IsReadOnly; }
+ }
+
+ public bool Remove(KeyValuePair<TKey, TValue> item)
+ {
+ return wrapped.Remove(item);
+ }
+
+ public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+ {
+ IComparer<TKey> comparer = Comparer<TKey>.Default;
+ var list = new List<KeyValuePair<TKey, TValue>>(wrapped);
+ list.Sort((x, y) => comparer.Compare(x.Key, y.Key));
+ return list.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ }
+}
#endif \ No newline at end of file
diff --git a/src/ProtocolBuffers/TextFormat.cs b/src/ProtocolBuffers/TextFormat.cs
index 885152db..cf352273 100644
--- a/src/ProtocolBuffers/TextFormat.cs
+++ b/src/ProtocolBuffers/TextFormat.cs
@@ -1,685 +1,685 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://github.com/jskeet/dotnet-protobufs/
-// Original C++/Java/Python code:
-// http://code.google.com/p/protobuf/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using Google.ProtocolBuffers.Descriptors;
-using System.Collections;
-
-namespace Google.ProtocolBuffers {
- /// <summary>
- /// Provides ASCII text formatting support for messages.
- /// TODO(jonskeet): Support for alternative line endings.
- /// (Easy to print, via TextGenerator. Not sure about parsing.)
- /// </summary>
- public static class TextFormat {
-
- /// <summary>
- /// Outputs a textual representation of the Protocol Message supplied into
- /// the parameter output.
- /// </summary>
- public static void Print(IMessage message, TextWriter output) {
- TextGenerator generator = new TextGenerator(output, "\n");
- Print(message, generator);
- }
-
- /// <summary>
- /// Outputs a textual representation of <paramref name="fields" /> to <paramref name="output"/>.
- /// </summary>
- public static void Print(UnknownFieldSet fields, TextWriter output) {
- TextGenerator generator = new TextGenerator(output, "\n");
- PrintUnknownFields(fields, generator);
- }
-
- public static string PrintToString(IMessage message) {
- StringWriter text = new StringWriter();
- Print(message, text);
- return text.ToString();
- }
-
- public static string PrintToString(UnknownFieldSet fields) {
- StringWriter text = new StringWriter();
- Print(fields, text);
- return text.ToString();
- }
-
- private static void Print(IMessage message, TextGenerator generator) {
- foreach (KeyValuePair<FieldDescriptor, object> entry in message.AllFields) {
- PrintField(entry.Key, entry.Value, generator);
- }
- PrintUnknownFields(message.UnknownFields, generator);
- }
-
- internal static void PrintField(FieldDescriptor field, object value, TextGenerator generator) {
- if (field.IsRepeated) {
- // Repeated field. Print each element.
- foreach (object element in (IEnumerable) value) {
- PrintSingleField(field, element, generator);
- }
- } else {
- PrintSingleField(field, value, generator);
- }
- }
-
- private static void PrintSingleField(FieldDescriptor field, Object value, TextGenerator generator) {
- if (field.IsExtension) {
- generator.Print("[");
- // We special-case MessageSet elements for compatibility with proto1.
- if (field.ContainingType.Options.MessageSetWireFormat
- && field.FieldType == FieldType.Message
- && field.IsOptional
- // object equality (TODO(jonskeet): Work out what this comment means!)
- && field.ExtensionScope == field.MessageType) {
- generator.Print(field.MessageType.FullName);
- } else {
- generator.Print(field.FullName);
- }
- generator.Print("]");
- } else {
- if (field.FieldType == FieldType.Group) {
- // Groups must be serialized with their original capitalization.
- generator.Print(field.MessageType.Name);
- } else {
- generator.Print(field.Name);
- }
- }
-
- if (field.MappedType == MappedType.Message) {
- generator.Print(" {\n");
- generator.Indent();
- } else {
- generator.Print(": ");
- }
-
- PrintFieldValue(field, value, generator);
-
- if (field.MappedType == MappedType.Message) {
- generator.Outdent();
- generator.Print("}");
- }
- generator.Print("\n");
- }
-
- private static void PrintFieldValue(FieldDescriptor field, object value, TextGenerator generator) {
- switch (field.FieldType) {
- case FieldType.Int32:
- case FieldType.Int64:
- case FieldType.SInt32:
- case FieldType.SInt64:
- case FieldType.SFixed32:
- case FieldType.SFixed64:
- case FieldType.Float:
- case FieldType.Double:
- case FieldType.UInt32:
- case FieldType.UInt64:
- case FieldType.Fixed32:
- case FieldType.Fixed64:
- // The simple Object.ToString converts using the current culture.
- // We want to always use the invariant culture so it's predictable.
- generator.Print(((IConvertible) value).ToString(CultureInfo.InvariantCulture));
- break;
- case FieldType.Bool:
- // Explicitly use the Java true/false
- generator.Print((bool) value ? "true" : "false");
- break;
-
- case FieldType.String:
- generator.Print("\"");
- generator.Print(EscapeText((string) value));
- generator.Print("\"");
- break;
-
- case FieldType.Bytes: {
- generator.Print("\"");
- generator.Print(EscapeBytes((ByteString) value));
- generator.Print("\"");
- break;
- }
-
- case FieldType.Enum: {
- if (value is IEnumLite && !(value is EnumValueDescriptor)) {
- throw new NotSupportedException("Lite enumerations are not supported.");
- }
- generator.Print(((EnumValueDescriptor)value).Name);
- break;
- }
-
- case FieldType.Message:
- case FieldType.Group:
- if (value is IMessageLite && !(value is IMessage)) {
- throw new NotSupportedException("Lite messages are not supported.");
- }
- Print((IMessage)value, generator);
- break;
- }
- }
-
- private static void PrintUnknownFields(UnknownFieldSet unknownFields, TextGenerator generator) {
- foreach (KeyValuePair<int, UnknownField> entry in unknownFields.FieldDictionary) {
- String prefix = entry.Key.ToString() + ": ";
- UnknownField field = entry.Value;
-
- foreach (ulong value in field.VarintList) {
- generator.Print(prefix);
- generator.Print(value.ToString());
- generator.Print("\n");
- }
- foreach (uint value in field.Fixed32List) {
- generator.Print(prefix);
- generator.Print(string.Format("0x{0:x8}", value));
- generator.Print("\n");
- }
- foreach (ulong value in field.Fixed64List) {
- generator.Print(prefix);
- generator.Print(string.Format("0x{0:x16}", value));
- generator.Print("\n");
- }
- foreach (ByteString value in field.LengthDelimitedList) {
- generator.Print(entry.Key.ToString());
- generator.Print(": \"");
- generator.Print(EscapeBytes(value));
- generator.Print("\"\n");
- }
- foreach (UnknownFieldSet value in field.GroupList) {
- generator.Print(entry.Key.ToString());
- generator.Print(" {\n");
- generator.Indent();
- PrintUnknownFields(value, generator);
- generator.Outdent();
- generator.Print("}\n");
- }
- }
- }
-
- [CLSCompliant(false)]
- public static ulong ParseUInt64(string text) {
- return (ulong) ParseInteger(text, false, true);
- }
-
- public static long ParseInt64(string text) {
- return ParseInteger(text, true, true);
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using Google.ProtocolBuffers.Descriptors;
+using System.Collections;
+
+namespace Google.ProtocolBuffers {
+ /// <summary>
+ /// Provides ASCII text formatting support for messages.
+ /// TODO(jonskeet): Support for alternative line endings.
+ /// (Easy to print, via TextGenerator. Not sure about parsing.)
+ /// </summary>
+ public static class TextFormat {
+
+ /// <summary>
+ /// Outputs a textual representation of the Protocol Message supplied into
+ /// the parameter output.
+ /// </summary>
+ public static void Print(IMessage message, TextWriter output) {
+ TextGenerator generator = new TextGenerator(output, "\n");
+ Print(message, generator);
+ }
+
+ /// <summary>
+ /// Outputs a textual representation of <paramref name="fields" /> to <paramref name="output"/>.
+ /// </summary>
+ public static void Print(UnknownFieldSet fields, TextWriter output) {
+ TextGenerator generator = new TextGenerator(output, "\n");
+ PrintUnknownFields(fields, generator);
+ }
+
+ public static string PrintToString(IMessage message) {
+ StringWriter text = new StringWriter();
+ Print(message, text);
+ return text.ToString();
+ }
+
+ public static string PrintToString(UnknownFieldSet fields) {
+ StringWriter text = new StringWriter();
+ Print(fields, text);
+ return text.ToString();
+ }
+
+ private static void Print(IMessage message, TextGenerator generator) {
+ foreach (KeyValuePair<FieldDescriptor, object> entry in message.AllFields) {
+ PrintField(entry.Key, entry.Value, generator);
+ }
+ PrintUnknownFields(message.UnknownFields, generator);
+ }
+
+ internal static void PrintField(FieldDescriptor field, object value, TextGenerator generator) {
+ if (field.IsRepeated) {
+ // Repeated field. Print each element.
+ foreach (object element in (IEnumerable) value) {
+ PrintSingleField(field, element, generator);
+ }
+ } else {
+ PrintSingleField(field, value, generator);
+ }
+ }
+
+ private static void PrintSingleField(FieldDescriptor field, Object value, TextGenerator generator) {
+ if (field.IsExtension) {
+ generator.Print("[");
+ // We special-case MessageSet elements for compatibility with proto1.
+ if (field.ContainingType.Options.MessageSetWireFormat
+ && field.FieldType == FieldType.Message
+ && field.IsOptional
+ // object equality (TODO(jonskeet): Work out what this comment means!)
+ && field.ExtensionScope == field.MessageType) {
+ generator.Print(field.MessageType.FullName);
+ } else {
+ generator.Print(field.FullName);
+ }
+ generator.Print("]");
+ } else {
+ if (field.FieldType == FieldType.Group) {
+ // Groups must be serialized with their original capitalization.
+ generator.Print(field.MessageType.Name);
+ } else {
+ generator.Print(field.Name);
+ }
+ }
+
+ if (field.MappedType == MappedType.Message) {
+ generator.Print(" {\n");
+ generator.Indent();
+ } else {
+ generator.Print(": ");
+ }
+
+ PrintFieldValue(field, value, generator);
+
+ if (field.MappedType == MappedType.Message) {
+ generator.Outdent();
+ generator.Print("}");
+ }
+ generator.Print("\n");
+ }
+
+ private static void PrintFieldValue(FieldDescriptor field, object value, TextGenerator generator) {
+ switch (field.FieldType) {
+ case FieldType.Int32:
+ case FieldType.Int64:
+ case FieldType.SInt32:
+ case FieldType.SInt64:
+ case FieldType.SFixed32:
+ case FieldType.SFixed64:
+ case FieldType.Float:
+ case FieldType.Double:
+ case FieldType.UInt32:
+ case FieldType.UInt64:
+ case FieldType.Fixed32:
+ case FieldType.Fixed64:
+ // The simple Object.ToString converts using the current culture.
+ // We want to always use the invariant culture so it's predictable.
+ generator.Print(((IConvertible) value).ToString(CultureInfo.InvariantCulture));
+ break;
+ case FieldType.Bool:
+ // Explicitly use the Java true/false
+ generator.Print((bool) value ? "true" : "false");
+ break;
+
+ case FieldType.String:
+ generator.Print("\"");
+ generator.Print(EscapeText((string) value));
+ generator.Print("\"");
+ break;
+
+ case FieldType.Bytes: {
+ generator.Print("\"");
+ generator.Print(EscapeBytes((ByteString) value));
+ generator.Print("\"");
+ break;
+ }
+
+ case FieldType.Enum: {
+ if (value is IEnumLite && !(value is EnumValueDescriptor)) {
+ throw new NotSupportedException("Lite enumerations are not supported.");
+ }
+ generator.Print(((EnumValueDescriptor)value).Name);
+ break;
+ }
+
+ case FieldType.Message:
+ case FieldType.Group:
+ if (value is IMessageLite && !(value is IMessage)) {
+ throw new NotSupportedException("Lite messages are not supported.");
+ }
+ Print((IMessage)value, generator);
+ break;
+ }
+ }
+
+ private static void PrintUnknownFields(UnknownFieldSet unknownFields, TextGenerator generator) {
+ foreach (KeyValuePair<int, UnknownField> entry in unknownFields.FieldDictionary) {
+ String prefix = entry.Key.ToString() + ": ";
+ UnknownField field = entry.Value;
+
+ foreach (ulong value in field.VarintList) {
+ generator.Print(prefix);
+ generator.Print(value.ToString());
+ generator.Print("\n");
+ }
+ foreach (uint value in field.Fixed32List) {
+ generator.Print(prefix);
+ generator.Print(string.Format("0x{0:x8}", value));
+ generator.Print("\n");
+ }
+ foreach (ulong value in field.Fixed64List) {
+ generator.Print(prefix);
+ generator.Print(string.Format("0x{0:x16}", value));
+ generator.Print("\n");
+ }
+ foreach (ByteString value in field.LengthDelimitedList) {
+ generator.Print(entry.Key.ToString());
+ generator.Print(": \"");
+ generator.Print(EscapeBytes(value));
+ generator.Print("\"\n");
+ }
+ foreach (UnknownFieldSet value in field.GroupList) {
+ generator.Print(entry.Key.ToString());
+ generator.Print(" {\n");
+ generator.Indent();
+ PrintUnknownFields(value, generator);
+ generator.Outdent();
+ generator.Print("}\n");
+ }
+ }
+ }
+
+ [CLSCompliant(false)]
+ public static ulong ParseUInt64(string text) {
+ return (ulong) ParseInteger(text, false, true);
+ }
+
+ public static long ParseInt64(string text) {
+ return ParseInteger(text, true, true);
+ }
+
+ [CLSCompliant(false)]
+ public static uint ParseUInt32(string text) {
+ return (uint) ParseInteger(text, false, false);
+ }
+
+ public static int ParseInt32(string text) {
+ return (int) ParseInteger(text, true, false);
+ }
+
+ public static float ParseFloat(string text) {
+ switch (text) {
+ case "-inf":
+ case "-infinity":
+ case "-inff":
+ case "-infinityf":
+ return float.NegativeInfinity;
+ case "inf":
+ case "infinity":
+ case "inff":
+ case "infinityf":
+ return float.PositiveInfinity;
+ case "nan":
+ case "nanf":
+ return float.NaN;
+ default:
+ return float.Parse(text, CultureInfo.InvariantCulture);
+ }
+ }
+
+ public static double ParseDouble(string text) {
+ switch (text) {
+ case "-inf":
+ case "-infinity":
+ return double.NegativeInfinity;
+ case "inf":
+ case "infinity":
+ return double.PositiveInfinity;
+ case "nan":
+ return double.NaN;
+ default:
+ return double.Parse(text, CultureInfo.InvariantCulture);
+ }
+ }
+
+ /// <summary>
+ /// Parses an integer in hex (leading 0x), decimal (no prefix) or octal (leading 0).
+ /// Only a negative sign is permitted, and it must come before the radix indicator.
+ /// </summary>
+ private static long ParseInteger(string text, bool isSigned, bool isLong) {
+ string original = text;
+ bool negative = false;
+ if (text.StartsWith("-")) {
+ if (!isSigned) {
+ throw new FormatException("Number must be positive: " + original);
+ }
+ negative = true;
+ text = text.Substring(1);
+ }
+
+ int radix = 10;
+ if (text.StartsWith("0x")) {
+ radix = 16;
+ text = text.Substring(2);
+ } else if (text.StartsWith("0")) {
+ radix = 8;
+ }
+
+ ulong result;
+ try {
+ // Workaround for https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=278448
+ // We should be able to use Convert.ToUInt64 for all cases.
+ result = radix == 10 ? ulong.Parse(text) : Convert.ToUInt64(text, radix);
+ } catch (OverflowException) {
+ // Convert OverflowException to FormatException so there's a single exception type this method can throw.
+ string numberDescription = string.Format("{0}-bit {1}signed integer", isLong ? 64 : 32, isSigned ? "" : "un");
+ throw new FormatException("Number out of range for " + numberDescription + ": " + original);
+ }
+
+ if (negative) {
+ ulong max = isLong ? 0x8000000000000000UL : 0x80000000L;
+ if (result > max) {
+ string numberDescription = string.Format("{0}-bit signed integer", isLong ? 64 : 32);
+ throw new FormatException("Number out of range for " + numberDescription + ": " + original);
+ }
+ return -((long) result);
+ } else {
+ ulong max = isSigned
+ ? (isLong ? (ulong) long.MaxValue : int.MaxValue)
+ : (isLong ? ulong.MaxValue : uint.MaxValue);
+ if (result > max) {
+ string numberDescription = string.Format("{0}-bit {1}signed integer", isLong ? 64 : 32, isSigned ? "" : "un");
+ throw new FormatException("Number out of range for " + numberDescription + ": " + original);
+ }
+ return (long) result;
+ }
+ }
+
+ /// <summary>
+ /// Tests a character to see if it's an octal digit.
+ /// </summary>
+ private static bool IsOctal(char c) {
+ return '0' <= c && c <= '7';
+ }
+
+ /// <summary>
+ /// Tests a character to see if it's a hex digit.
+ /// </summary>
+ private static bool IsHex(char c) {
+ return ('0' <= c && c <= '9') ||
+ ('a' <= c && c <= 'f') ||
+ ('A' <= c && c <= 'F');
+ }
+
+ /// <summary>
+ /// Interprets a character as a digit (in any base up to 36) and returns the
+ /// numeric value.
+ /// </summary>
+ private static int ParseDigit(char c) {
+ if ('0' <= c && c <= '9') {
+ return c - '0';
+ } else if ('a' <= c && c <= 'z') {
+ return c - 'a' + 10;
+ } else {
+ return c - 'A' + 10;
+ }
+ }
+
+ /// <summary>
+ /// Unescapes a text string as escaped using <see cref="EscapeText(string)" />.
+ /// Two-digit hex escapes (starting with "\x" are also recognised.
+ /// </summary>
+ public static string UnescapeText(string input) {
+ return UnescapeBytes(input).ToStringUtf8();
+ }
+
+ /// <summary>
+ /// Like <see cref="EscapeBytes" /> but escapes a text string.
+ /// The string is first encoded as UTF-8, then each byte escaped individually.
+ /// The returned value is guaranteed to be entirely ASCII.
+ /// </summary>
+ public static string EscapeText(string input) {
+ return EscapeBytes(ByteString.CopyFromUtf8(input));
+ }
+
+ /// <summary>
+ /// Escapes bytes in the format used in protocol buffer text format, which
+ /// is the same as the format used for C string literals. All bytes
+ /// that are not printable 7-bit ASCII characters are escaped, as well as
+ /// backslash, single-quote, and double-quote characters. Characters for
+ /// which no defined short-hand escape sequence is defined will be escaped
+ /// using 3-digit octal sequences.
+ /// The returned value is guaranteed to be entirely ASCII.
+ /// </summary>
+ public static String EscapeBytes(ByteString input) {
+ StringBuilder builder = new StringBuilder(input.Length);
+ foreach (byte b in input) {
+ switch (b) {
+ // C# does not use \a or \v
+ case 0x07: builder.Append("\\a" ); break;
+ case (byte)'\b': builder.Append("\\b" ); break;
+ case (byte)'\f': builder.Append("\\f" ); break;
+ case (byte)'\n': builder.Append("\\n" ); break;
+ case (byte)'\r': builder.Append("\\r" ); break;
+ case (byte)'\t': builder.Append("\\t" ); break;
+ case 0x0b: builder.Append("\\v" ); break;
+ case (byte)'\\': builder.Append("\\\\"); break;
+ case (byte)'\'': builder.Append("\\\'"); break;
+ case (byte)'"' : builder.Append("\\\""); break;
+ default:
+ if (b >= 0x20 && b < 128) {
+ builder.Append((char) b);
+ } else {
+ builder.Append('\\');
+ builder.Append((char) ('0' + ((b >> 6) & 3)));
+ builder.Append((char) ('0' + ((b >> 3) & 7)));
+ builder.Append((char) ('0' + (b & 7)));
+ }
+ break;
+ }
+ }
+ return builder.ToString();
+ }
+
+ /// <summary>
+ /// Performs string unescaping from C style (octal, hex, form feeds, tab etc) into a byte string.
+ /// </summary>
+ public static ByteString UnescapeBytes(string input) {
+ byte[] result = new byte[input.Length];
+ int pos = 0;
+ for (int i = 0; i < input.Length; i++) {
+ char c = input[i];
+ if (c > 127 || c < 32) {
+ throw new FormatException("Escaped string must only contain ASCII");
+ }
+ if (c != '\\') {
+ result[pos++] = (byte) c;
+ continue;
+ }
+ if (i + 1 >= input.Length) {
+ throw new FormatException("Invalid escape sequence: '\\' at end of string.");
+ }
+
+ i++;
+ c = input[i];
+ if (c >= '0' && c <= '7') {
+ // Octal escape.
+ int code = ParseDigit(c);
+ if (i + 1 < input.Length && IsOctal(input[i+1])) {
+ i++;
+ code = code * 8 + ParseDigit(input[i]);
+ }
+ if (i + 1 < input.Length && IsOctal(input[i+1])) {
+ i++;
+ code = code * 8 + ParseDigit(input[i]);
+ }
+ result[pos++] = (byte) code;
+ } else {
+ switch (c) {
+ case 'a': result[pos++] = 0x07; break;
+ case 'b': result[pos++] = (byte) '\b'; break;
+ case 'f': result[pos++] = (byte) '\f'; break;
+ case 'n': result[pos++] = (byte) '\n'; break;
+ case 'r': result[pos++] = (byte) '\r'; break;
+ case 't': result[pos++] = (byte) '\t'; break;
+ case 'v': result[pos++] = 0x0b; break;
+ case '\\': result[pos++] = (byte) '\\'; break;
+ case '\'': result[pos++] = (byte) '\''; break;
+ case '"': result[pos++] = (byte) '\"'; break;
+
+ case 'x':
+ // hex escape
+ int code;
+ if (i + 1 < input.Length && IsHex(input[i+1])) {
+ i++;
+ code = ParseDigit(input[i]);
+ } else {
+ throw new FormatException("Invalid escape sequence: '\\x' with no digits");
+ }
+ if (i + 1 < input.Length && IsHex(input[i+1])) {
+ ++i;
+ code = code * 16 + ParseDigit(input[i]);
+ }
+ result[pos++] = (byte)code;
+ break;
+
+ default:
+ throw new FormatException("Invalid escape sequence: '\\" + c + "'");
+ }
+ }
+ }
+
+ return ByteString.CopyFrom(result, 0, pos);
+ }
+
+ public static void Merge(string text, IBuilder builder) {
+ Merge(text, ExtensionRegistry.Empty, builder);
}
- [CLSCompliant(false)]
- public static uint ParseUInt32(string text) {
- return (uint) ParseInteger(text, false, false);
- }
-
- public static int ParseInt32(string text) {
- return (int) ParseInteger(text, true, false);
- }
-
- public static float ParseFloat(string text) {
- switch (text) {
- case "-inf":
- case "-infinity":
- case "-inff":
- case "-infinityf":
- return float.NegativeInfinity;
- case "inf":
- case "infinity":
- case "inff":
- case "infinityf":
- return float.PositiveInfinity;
- case "nan":
- case "nanf":
- return float.NaN;
- default:
- return float.Parse(text, CultureInfo.InvariantCulture);
- }
- }
-
- public static double ParseDouble(string text) {
- switch (text) {
- case "-inf":
- case "-infinity":
- return double.NegativeInfinity;
- case "inf":
- case "infinity":
- return double.PositiveInfinity;
- case "nan":
- return double.NaN;
- default:
- return double.Parse(text, CultureInfo.InvariantCulture);
- }
- }
-
- /// <summary>
- /// Parses an integer in hex (leading 0x), decimal (no prefix) or octal (leading 0).
- /// Only a negative sign is permitted, and it must come before the radix indicator.
- /// </summary>
- private static long ParseInteger(string text, bool isSigned, bool isLong) {
- string original = text;
- bool negative = false;
- if (text.StartsWith("-")) {
- if (!isSigned) {
- throw new FormatException("Number must be positive: " + original);
- }
- negative = true;
- text = text.Substring(1);
- }
-
- int radix = 10;
- if (text.StartsWith("0x")) {
- radix = 16;
- text = text.Substring(2);
- } else if (text.StartsWith("0")) {
- radix = 8;
- }
-
- ulong result;
- try {
- // Workaround for https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=278448
- // We should be able to use Convert.ToUInt64 for all cases.
- result = radix == 10 ? ulong.Parse(text) : Convert.ToUInt64(text, radix);
- } catch (OverflowException) {
- // Convert OverflowException to FormatException so there's a single exception type this method can throw.
- string numberDescription = string.Format("{0}-bit {1}signed integer", isLong ? 64 : 32, isSigned ? "" : "un");
- throw new FormatException("Number out of range for " + numberDescription + ": " + original);
- }
-
- if (negative) {
- ulong max = isLong ? 0x8000000000000000UL : 0x80000000L;
- if (result > max) {
- string numberDescription = string.Format("{0}-bit signed integer", isLong ? 64 : 32);
- throw new FormatException("Number out of range for " + numberDescription + ": " + original);
- }
- return -((long) result);
- } else {
- ulong max = isSigned
- ? (isLong ? (ulong) long.MaxValue : int.MaxValue)
- : (isLong ? ulong.MaxValue : uint.MaxValue);
- if (result > max) {
- string numberDescription = string.Format("{0}-bit {1}signed integer", isLong ? 64 : 32, isSigned ? "" : "un");
- throw new FormatException("Number out of range for " + numberDescription + ": " + original);
- }
- return (long) result;
- }
- }
-
- /// <summary>
- /// Tests a character to see if it's an octal digit.
- /// </summary>
- private static bool IsOctal(char c) {
- return '0' <= c && c <= '7';
- }
-
- /// <summary>
- /// Tests a character to see if it's a hex digit.
- /// </summary>
- private static bool IsHex(char c) {
- return ('0' <= c && c <= '9') ||
- ('a' <= c && c <= 'f') ||
- ('A' <= c && c <= 'F');
- }
-
- /// <summary>
- /// Interprets a character as a digit (in any base up to 36) and returns the
- /// numeric value.
- /// </summary>
- private static int ParseDigit(char c) {
- if ('0' <= c && c <= '9') {
- return c - '0';
- } else if ('a' <= c && c <= 'z') {
- return c - 'a' + 10;
- } else {
- return c - 'A' + 10;
- }
- }
-
- /// <summary>
- /// Unescapes a text string as escaped using <see cref="EscapeText(string)" />.
- /// Two-digit hex escapes (starting with "\x" are also recognised.
- /// </summary>
- public static string UnescapeText(string input) {
- return UnescapeBytes(input).ToStringUtf8();
- }
-
- /// <summary>
- /// Like <see cref="EscapeBytes" /> but escapes a text string.
- /// The string is first encoded as UTF-8, then each byte escaped individually.
- /// The returned value is guaranteed to be entirely ASCII.
- /// </summary>
- public static string EscapeText(string input) {
- return EscapeBytes(ByteString.CopyFromUtf8(input));
- }
-
- /// <summary>
- /// Escapes bytes in the format used in protocol buffer text format, which
- /// is the same as the format used for C string literals. All bytes
- /// that are not printable 7-bit ASCII characters are escaped, as well as
- /// backslash, single-quote, and double-quote characters. Characters for
- /// which no defined short-hand escape sequence is defined will be escaped
- /// using 3-digit octal sequences.
- /// The returned value is guaranteed to be entirely ASCII.
- /// </summary>
- public static String EscapeBytes(ByteString input) {
- StringBuilder builder = new StringBuilder(input.Length);
- foreach (byte b in input) {
- switch (b) {
- // C# does not use \a or \v
- case 0x07: builder.Append("\\a" ); break;
- case (byte)'\b': builder.Append("\\b" ); break;
- case (byte)'\f': builder.Append("\\f" ); break;
- case (byte)'\n': builder.Append("\\n" ); break;
- case (byte)'\r': builder.Append("\\r" ); break;
- case (byte)'\t': builder.Append("\\t" ); break;
- case 0x0b: builder.Append("\\v" ); break;
- case (byte)'\\': builder.Append("\\\\"); break;
- case (byte)'\'': builder.Append("\\\'"); break;
- case (byte)'"' : builder.Append("\\\""); break;
- default:
- if (b >= 0x20 && b < 128) {
- builder.Append((char) b);
- } else {
- builder.Append('\\');
- builder.Append((char) ('0' + ((b >> 6) & 3)));
- builder.Append((char) ('0' + ((b >> 3) & 7)));
- builder.Append((char) ('0' + (b & 7)));
- }
- break;
- }
- }
- return builder.ToString();
- }
-
- /// <summary>
- /// Performs string unescaping from C style (octal, hex, form feeds, tab etc) into a byte string.
- /// </summary>
- public static ByteString UnescapeBytes(string input) {
- byte[] result = new byte[input.Length];
- int pos = 0;
- for (int i = 0; i < input.Length; i++) {
- char c = input[i];
- if (c > 127 || c < 32) {
- throw new FormatException("Escaped string must only contain ASCII");
- }
- if (c != '\\') {
- result[pos++] = (byte) c;
- continue;
- }
- if (i + 1 >= input.Length) {
- throw new FormatException("Invalid escape sequence: '\\' at end of string.");
- }
-
- i++;
- c = input[i];
- if (c >= '0' && c <= '7') {
- // Octal escape.
- int code = ParseDigit(c);
- if (i + 1 < input.Length && IsOctal(input[i+1])) {
- i++;
- code = code * 8 + ParseDigit(input[i]);
- }
- if (i + 1 < input.Length && IsOctal(input[i+1])) {
- i++;
- code = code * 8 + ParseDigit(input[i]);
- }
- result[pos++] = (byte) code;
- } else {
- switch (c) {
- case 'a': result[pos++] = 0x07; break;
- case 'b': result[pos++] = (byte) '\b'; break;
- case 'f': result[pos++] = (byte) '\f'; break;
- case 'n': result[pos++] = (byte) '\n'; break;
- case 'r': result[pos++] = (byte) '\r'; break;
- case 't': result[pos++] = (byte) '\t'; break;
- case 'v': result[pos++] = 0x0b; break;
- case '\\': result[pos++] = (byte) '\\'; break;
- case '\'': result[pos++] = (byte) '\''; break;
- case '"': result[pos++] = (byte) '\"'; break;
-
- case 'x':
- // hex escape
- int code;
- if (i + 1 < input.Length && IsHex(input[i+1])) {
- i++;
- code = ParseDigit(input[i]);
- } else {
- throw new FormatException("Invalid escape sequence: '\\x' with no digits");
- }
- if (i + 1 < input.Length && IsHex(input[i+1])) {
- ++i;
- code = code * 16 + ParseDigit(input[i]);
- }
- result[pos++] = (byte)code;
- break;
-
- default:
- throw new FormatException("Invalid escape sequence: '\\" + c + "'");
- }
- }
- }
-
- return ByteString.CopyFrom(result, 0, pos);
- }
-
- public static void Merge(string text, IBuilder builder) {
- Merge(text, ExtensionRegistry.Empty, builder);
- }
-
- public static void Merge(TextReader reader, IBuilder builder) {
- Merge(reader, ExtensionRegistry.Empty, builder);
- }
-
- public static void Merge(TextReader reader, ExtensionRegistry registry, IBuilder builder) {
- Merge(reader.ReadToEnd(), registry, builder);
- }
-
- public static void Merge(string text, ExtensionRegistry registry, IBuilder builder) {
- TextTokenizer tokenizer = new TextTokenizer(text);
-
- while (!tokenizer.AtEnd) {
- MergeField(tokenizer, registry, builder);
- }
- }
-
- /// <summary>
- /// Parses a single field from the specified tokenizer and merges it into
- /// the builder.
- /// </summary>
- private static void MergeField(TextTokenizer tokenizer, ExtensionRegistry extensionRegistry,
- IBuilder builder) {
-
- FieldDescriptor field;
- MessageDescriptor type = builder.DescriptorForType;
- ExtensionInfo extension = null;
-
- if (tokenizer.TryConsume("[")) {
- // An extension.
- StringBuilder name = new StringBuilder(tokenizer.ConsumeIdentifier());
- while (tokenizer.TryConsume(".")) {
- name.Append(".");
- name.Append(tokenizer.ConsumeIdentifier());
- }
-
- extension = extensionRegistry[name.ToString()];
-
- if (extension == null) {
- throw tokenizer.CreateFormatExceptionPreviousToken("Extension \"" + name + "\" not found in the ExtensionRegistry.");
- } else if (extension.Descriptor.ContainingType != type) {
- throw tokenizer.CreateFormatExceptionPreviousToken("Extension \"" + name + "\" does not extend message type \"" +
- type.FullName + "\".");
- }
-
- tokenizer.Consume("]");
-
- field = extension.Descriptor;
- } else {
- String name = tokenizer.ConsumeIdentifier();
- field = type.FindDescriptor<FieldDescriptor>(name);
-
- // Group names are expected to be capitalized as they appear in the
- // .proto file, which actually matches their type names, not their field
- // names.
- if (field == null) {
- // Explicitly specify the invariant culture so that this code does not break when
- // executing in Turkey.
- String lowerName = name.ToLower(CultureInfo.InvariantCulture);
- field = type.FindDescriptor<FieldDescriptor>(lowerName);
- // If the case-insensitive match worked but the field is NOT a group,
- // TODO(jonskeet): What? Java comment ends here!
- if (field != null && field.FieldType != FieldType.Group) {
- field = null;
- }
- }
- // Again, special-case group names as described above.
- if (field != null && field.FieldType == FieldType.Group && field.MessageType.Name != name) {
- field = null;
- }
-
- if (field == null) {
- throw tokenizer.CreateFormatExceptionPreviousToken(
- "Message type \"" + type.FullName + "\" has no field named \"" + name + "\".");
- }
- }
-
- object value = null;
-
- if (field.MappedType == MappedType.Message) {
- tokenizer.TryConsume(":"); // optional
-
- String endToken;
- if (tokenizer.TryConsume("<")) {
- endToken = ">";
- } else {
- tokenizer.Consume("{");
- endToken = "}";
- }
-
- IBuilder subBuilder;
- if (extension == null) {
- subBuilder = builder.CreateBuilderForField(field);
- } else {
- subBuilder = extension.DefaultInstance.WeakCreateBuilderForType() as IBuilder;
- if (subBuilder == null)
- throw new NotSupportedException("Lite messages are not supported.");
- }
-
- while (!tokenizer.TryConsume(endToken)) {
- if (tokenizer.AtEnd) {
- throw tokenizer.CreateFormatException("Expected \"" + endToken + "\".");
- }
- MergeField(tokenizer, extensionRegistry, subBuilder);
- }
-
- value = subBuilder.WeakBuild();
-
- } else {
- tokenizer.Consume(":");
-
- switch (field.FieldType) {
- case FieldType.Int32:
- case FieldType.SInt32:
- case FieldType.SFixed32:
- value = tokenizer.ConsumeInt32();
- break;
-
- case FieldType.Int64:
- case FieldType.SInt64:
- case FieldType.SFixed64:
- value = tokenizer.ConsumeInt64();
- break;
-
- case FieldType.UInt32:
- case FieldType.Fixed32:
- value = tokenizer.ConsumeUInt32();
- break;
-
- case FieldType.UInt64:
- case FieldType.Fixed64:
- value = tokenizer.ConsumeUInt64();
- break;
-
- case FieldType.Float:
- value = tokenizer.ConsumeFloat();
- break;
-
- case FieldType.Double:
- value = tokenizer.ConsumeDouble();
- break;
-
- case FieldType.Bool:
- value = tokenizer.ConsumeBoolean();
- break;
-
- case FieldType.String:
- value = tokenizer.ConsumeString();
- break;
-
- case FieldType.Bytes:
- value = tokenizer.ConsumeByteString();
- break;
-
- case FieldType.Enum: {
- EnumDescriptor enumType = field.EnumType;
-
- if (tokenizer.LookingAtInteger()) {
- int number = tokenizer.ConsumeInt32();
- value = enumType.FindValueByNumber(number);
- if (value == null) {
- throw tokenizer.CreateFormatExceptionPreviousToken(
- "Enum type \"" + enumType.FullName +
- "\" has no value with number " + number + ".");
- }
- } else {
- String id = tokenizer.ConsumeIdentifier();
- value = enumType.FindValueByName(id);
- if (value == null) {
- throw tokenizer.CreateFormatExceptionPreviousToken(
- "Enum type \"" + enumType.FullName +
- "\" has no value named \"" + id + "\".");
- }
- }
-
- break;
- }
-
- case FieldType.Message:
- case FieldType.Group:
- throw new InvalidOperationException("Can't get here.");
- }
- }
-
- if (field.IsRepeated) {
- builder.WeakAddRepeatedField(field, value);
- } else {
- builder.SetField(field, value);
- }
- }
- }
-}
+ public static void Merge(TextReader reader, IBuilder builder) {
+ Merge(reader, ExtensionRegistry.Empty, builder);
+ }
+
+ public static void Merge(TextReader reader, ExtensionRegistry registry, IBuilder builder) {
+ Merge(reader.ReadToEnd(), registry, builder);
+ }
+
+ public static void Merge(string text, ExtensionRegistry registry, IBuilder builder) {
+ TextTokenizer tokenizer = new TextTokenizer(text);
+
+ while (!tokenizer.AtEnd) {
+ MergeField(tokenizer, registry, builder);
+ }
+ }
+
+ /// <summary>
+ /// Parses a single field from the specified tokenizer and merges it into
+ /// the builder.
+ /// </summary>
+ private static void MergeField(TextTokenizer tokenizer, ExtensionRegistry extensionRegistry,
+ IBuilder builder) {
+
+ FieldDescriptor field;
+ MessageDescriptor type = builder.DescriptorForType;
+ ExtensionInfo extension = null;
+
+ if (tokenizer.TryConsume("[")) {
+ // An extension.
+ StringBuilder name = new StringBuilder(tokenizer.ConsumeIdentifier());
+ while (tokenizer.TryConsume(".")) {
+ name.Append(".");
+ name.Append(tokenizer.ConsumeIdentifier());
+ }
+
+ extension = extensionRegistry[name.ToString()];
+
+ if (extension == null) {
+ throw tokenizer.CreateFormatExceptionPreviousToken("Extension \"" + name + "\" not found in the ExtensionRegistry.");
+ } else if (extension.Descriptor.ContainingType != type) {
+ throw tokenizer.CreateFormatExceptionPreviousToken("Extension \"" + name + "\" does not extend message type \"" +
+ type.FullName + "\".");
+ }
+
+ tokenizer.Consume("]");
+
+ field = extension.Descriptor;
+ } else {
+ String name = tokenizer.ConsumeIdentifier();
+ field = type.FindDescriptor<FieldDescriptor>(name);
+
+ // Group names are expected to be capitalized as they appear in the
+ // .proto file, which actually matches their type names, not their field
+ // names.
+ if (field == null) {
+ // Explicitly specify the invariant culture so that this code does not break when
+ // executing in Turkey.
+ String lowerName = name.ToLower(CultureInfo.InvariantCulture);
+ field = type.FindDescriptor<FieldDescriptor>(lowerName);
+ // If the case-insensitive match worked but the field is NOT a group,
+ // TODO(jonskeet): What? Java comment ends here!
+ if (field != null && field.FieldType != FieldType.Group) {
+ field = null;
+ }
+ }
+ // Again, special-case group names as described above.
+ if (field != null && field.FieldType == FieldType.Group && field.MessageType.Name != name) {
+ field = null;
+ }
+
+ if (field == null) {
+ throw tokenizer.CreateFormatExceptionPreviousToken(
+ "Message type \"" + type.FullName + "\" has no field named \"" + name + "\".");
+ }
+ }
+
+ object value = null;
+
+ if (field.MappedType == MappedType.Message) {
+ tokenizer.TryConsume(":"); // optional
+
+ String endToken;
+ if (tokenizer.TryConsume("<")) {
+ endToken = ">";
+ } else {
+ tokenizer.Consume("{");
+ endToken = "}";
+ }
+
+ IBuilder subBuilder;
+ if (extension == null) {
+ subBuilder = builder.CreateBuilderForField(field);
+ } else {
+ subBuilder = extension.DefaultInstance.WeakCreateBuilderForType() as IBuilder;
+ if (subBuilder == null)
+ throw new NotSupportedException("Lite messages are not supported.");
+ }
+
+ while (!tokenizer.TryConsume(endToken)) {
+ if (tokenizer.AtEnd) {
+ throw tokenizer.CreateFormatException("Expected \"" + endToken + "\".");
+ }
+ MergeField(tokenizer, extensionRegistry, subBuilder);
+ }
+
+ value = subBuilder.WeakBuild();
+
+ } else {
+ tokenizer.Consume(":");
+
+ switch (field.FieldType) {
+ case FieldType.Int32:
+ case FieldType.SInt32:
+ case FieldType.SFixed32:
+ value = tokenizer.ConsumeInt32();
+ break;
+
+ case FieldType.Int64:
+ case FieldType.SInt64:
+ case FieldType.SFixed64:
+ value = tokenizer.ConsumeInt64();
+ break;
+
+ case FieldType.UInt32:
+ case FieldType.Fixed32:
+ value = tokenizer.ConsumeUInt32();
+ break;
+
+ case FieldType.UInt64:
+ case FieldType.Fixed64:
+ value = tokenizer.ConsumeUInt64();
+ break;
+
+ case FieldType.Float:
+ value = tokenizer.ConsumeFloat();
+ break;
+
+ case FieldType.Double:
+ value = tokenizer.ConsumeDouble();
+ break;
+
+ case FieldType.Bool:
+ value = tokenizer.ConsumeBoolean();
+ break;
+
+ case FieldType.String:
+ value = tokenizer.ConsumeString();
+ break;
+
+ case FieldType.Bytes:
+ value = tokenizer.ConsumeByteString();
+ break;
+
+ case FieldType.Enum: {
+ EnumDescriptor enumType = field.EnumType;
+
+ if (tokenizer.LookingAtInteger()) {
+ int number = tokenizer.ConsumeInt32();
+ value = enumType.FindValueByNumber(number);
+ if (value == null) {
+ throw tokenizer.CreateFormatExceptionPreviousToken(
+ "Enum type \"" + enumType.FullName +
+ "\" has no value with number " + number + ".");
+ }
+ } else {
+ String id = tokenizer.ConsumeIdentifier();
+ value = enumType.FindValueByName(id);
+ if (value == null) {
+ throw tokenizer.CreateFormatExceptionPreviousToken(
+ "Enum type \"" + enumType.FullName +
+ "\" has no value named \"" + id + "\".");
+ }
+ }
+
+ break;
+ }
+
+ case FieldType.Message:
+ case FieldType.Group:
+ throw new InvalidOperationException("Can't get here.");
+ }
+ }
+
+ if (field.IsRepeated) {
+ builder.WeakAddRepeatedField(field, value);
+ } else {
+ builder.SetField(field, value);
+ }
+ }
+ }
+}
diff --git a/src/ProtocolBuffers/TextGenerator.cs b/src/ProtocolBuffers/TextGenerator.cs
index 6b8fa048..b333ff0a 100644
--- a/src/ProtocolBuffers/TextGenerator.cs
+++ b/src/ProtocolBuffers/TextGenerator.cs
@@ -1,143 +1,143 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://github.com/jskeet/dotnet-protobufs/
-// Original C++/Java/Python code:
-// http://code.google.com/p/protobuf/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System;
-using System.IO;
-using System.Text;
-
-namespace Google.ProtocolBuffers {
-
- /// <summary>
- /// Helper class to control indentation. Used for TextFormat and by ProtoGen.
- /// </summary>
- public sealed class TextGenerator {
-
- /// <summary>
- /// The string to use at the end of each line. We assume that "Print" is only called using \n
- /// to indicate a line break; that's what we use to detect when we need to indent etc, and
- /// *just* the \n is replaced with the contents of lineBreak.
- /// </summary>
- private readonly string lineBreak;
-
- /// <summary>
- /// Writer to write formatted text to.
- /// </summary>
- private readonly TextWriter writer;
-
- /// <summary>
- /// Keeps track of whether the next piece of text should be indented
- /// </summary>
- bool atStartOfLine = true;
-
- /// <summary>
- /// Keeps track of the current level of indentation
- /// </summary>
- readonly StringBuilder indent = new StringBuilder();
-
- /// <summary>
- /// Creates a generator writing to the given writer. The writer
- /// is not closed by this class.
- /// </summary>
- public TextGenerator(TextWriter writer, string lineBreak) {
- this.writer = writer;
- this.lineBreak = lineBreak;
- }
-
- /// <summary>
- /// Indents text by two spaces. After calling Indent(), two spaces
- /// will be inserted at the beginning of each line of text. Indent() may
- /// be called multiple times to produce deeper indents.
- /// </summary>
- public void Indent() {
- indent.Append(" ");
- }
-
- /// <summary>
- /// Reduces the current indent level by two spaces.
- /// </summary>
- public void Outdent() {
- if (indent.Length == 0) {
- throw new InvalidOperationException("Too many calls to Outdent()");
- }
- indent.Length -= 2;
- }
-
- public void WriteLine(string text) {
- Print(text);
- Print("\n");
- }
-
- public void WriteLine(string format, params object[] args) {
- WriteLine(string.Format(format, args));
- }
-
- public void WriteLine() {
- WriteLine("");
- }
-
- /// <summary>
- /// Prints the given text to the output stream, indenting at line boundaries.
- /// </summary>
- /// <param name="text"></param>
- public void Print(string text) {
- int pos = 0;
-
- for (int i = 0; i < text.Length; i++) {
- if (text[i] == '\n') {
- // Strip off the \n from what we write
- Write(text.Substring(pos, i - pos));
- Write(lineBreak);
- pos = i + 1;
- atStartOfLine = true;
- }
- }
- Write(text.Substring(pos));
- }
-
- public void Write(string format, params object[] args) {
- Write(string.Format(format, args));
- }
-
- private void Write(string data) {
- if (data.Length == 0) {
- return;
- }
- if (atStartOfLine) {
- atStartOfLine = false;
- writer.Write(indent);
- }
- writer.Write(data);
- }
- }
-}
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.IO;
+using System.Text;
+
+namespace Google.ProtocolBuffers {
+
+ /// <summary>
+ /// Helper class to control indentation. Used for TextFormat and by ProtoGen.
+ /// </summary>
+ public sealed class TextGenerator {
+
+ /// <summary>
+ /// The string to use at the end of each line. We assume that "Print" is only called using \n
+ /// to indicate a line break; that's what we use to detect when we need to indent etc, and
+ /// *just* the \n is replaced with the contents of lineBreak.
+ /// </summary>
+ private readonly string lineBreak;
+
+ /// <summary>
+ /// Writer to write formatted text to.
+ /// </summary>
+ private readonly TextWriter writer;
+
+ /// <summary>
+ /// Keeps track of whether the next piece of text should be indented
+ /// </summary>
+ bool atStartOfLine = true;
+
+ /// <summary>
+ /// Keeps track of the current level of indentation
+ /// </summary>
+ readonly StringBuilder indent = new StringBuilder();
+
+ /// <summary>
+ /// Creates a generator writing to the given writer. The writer
+ /// is not closed by this class.
+ /// </summary>
+ public TextGenerator(TextWriter writer, string lineBreak) {
+ this.writer = writer;
+ this.lineBreak = lineBreak;
+ }
+
+ /// <summary>
+ /// Indents text by two spaces. After calling Indent(), two spaces
+ /// will be inserted at the beginning of each line of text. Indent() may
+ /// be called multiple times to produce deeper indents.
+ /// </summary>
+ public void Indent() {
+ indent.Append(" ");
+ }
+
+ /// <summary>
+ /// Reduces the current indent level by two spaces.
+ /// </summary>
+ public void Outdent() {
+ if (indent.Length == 0) {
+ throw new InvalidOperationException("Too many calls to Outdent()");
+ }
+ indent.Length -= 2;
+ }
+
+ public void WriteLine(string text) {
+ Print(text);
+ Print("\n");
+ }
+
+ public void WriteLine(string format, params object[] args) {
+ WriteLine(string.Format(format, args));
+ }
+
+ public void WriteLine() {
+ WriteLine("");
+ }
+
+ /// <summary>
+ /// Prints the given text to the output stream, indenting at line boundaries.
+ /// </summary>
+ /// <param name="text"></param>
+ public void Print(string text) {
+ int pos = 0;
+
+ for (int i = 0; i < text.Length; i++) {
+ if (text[i] == '\n') {
+ // Strip off the \n from what we write
+ Write(text.Substring(pos, i - pos));
+ Write(lineBreak);
+ pos = i + 1;
+ atStartOfLine = true;
+ }
+ }
+ Write(text.Substring(pos));
+ }
+
+ public void Write(string format, params object[] args) {
+ Write(string.Format(format, args));
+ }
+
+ private void Write(string data) {
+ if (data.Length == 0) {
+ return;
+ }
+ if (atStartOfLine) {
+ atStartOfLine = false;
+ writer.Write(indent);
+ }
+ writer.Write(data);
+ }
+ }
+}
diff --git a/src/ProtocolBuffers/TextTokenizer.cs b/src/ProtocolBuffers/TextTokenizer.cs
index ce067728..d3e8878c 100644
--- a/src/ProtocolBuffers/TextTokenizer.cs
+++ b/src/ProtocolBuffers/TextTokenizer.cs
@@ -1,412 +1,412 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://github.com/jskeet/dotnet-protobufs/
-// Original C++/Java/Python code:
-// http://code.google.com/p/protobuf/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System;
-using System.Globalization;
-using System.Text.RegularExpressions;
-
-namespace Google.ProtocolBuffers {
- /// <summary>
- /// Represents a stream of tokens parsed from a string.
- /// </summary>
- internal sealed class TextTokenizer {
- private readonly string text;
- private string currentToken;
-
- /// <summary>
- /// The character index within the text to perform the next regex match at.
- /// </summary>
- private int matchPos = 0;
-
- /// <summary>
- /// The character index within the text at which the current token begins.
- /// </summary>
- private int pos = 0;
-
- /// <summary>
- /// The line number of the current token.
- /// </summary>
- private int line = 0;
- /// <summary>
- /// The column number of the current token.
- /// </summary>
- private int column = 0;
-
- /// <summary>
- /// The line number of the previous token.
- /// </summary>
- private int previousLine = 0;
- /// <summary>
- /// The column number of the previous token.
- /// </summary>
- private int previousColumn = 0;
-
- // Note: atomic groups used to mimic possessive quantifiers in Java in both of these regexes
- internal static readonly Regex WhitespaceAndCommentPattern = new Regex("\\G(?>(\\s|(#.*$))+)",
- SilverlightCompatibility.CompiledRegexWhereAvailable | RegexOptions.Multiline);
- private static readonly Regex TokenPattern = new Regex(
- "\\G[a-zA-Z_](?>[0-9a-zA-Z_+-]*)|" + // an identifier
- "\\G[0-9+-](?>[0-9a-zA-Z_.+-]*)|" + // a number
- "\\G\"(?>([^\"\\\n\\\\]|\\\\.)*)(\"|\\\\?$)|" + // a double-quoted string
- "\\G\'(?>([^\"\\\n\\\\]|\\\\.)*)(\'|\\\\?$)", // a single-quoted string
- SilverlightCompatibility.CompiledRegexWhereAvailable | RegexOptions.Multiline);
-
- private static readonly Regex DoubleInfinity = new Regex("^-?inf(inity)?$",
- SilverlightCompatibility.CompiledRegexWhereAvailable | RegexOptions.IgnoreCase);
- private static readonly Regex FloatInfinity = new Regex("^-?inf(inity)?f?$",
- SilverlightCompatibility.CompiledRegexWhereAvailable | RegexOptions.IgnoreCase);
- private static readonly Regex FloatNan = new Regex("^nanf?$",
- SilverlightCompatibility.CompiledRegexWhereAvailable | RegexOptions.IgnoreCase);
-
- /** Construct a tokenizer that parses tokens from the given text. */
- public TextTokenizer(string text) {
- this.text = text;
- SkipWhitespace();
- NextToken();
- }
-
- /// <summary>
- /// Are we at the end of the input?
- /// </summary>
- public bool AtEnd {
- get { return currentToken.Length == 0; }
- }
-
- /// <summary>
- /// Advances to the next token.
- /// </summary>
- public void NextToken() {
- previousLine = line;
- previousColumn = column;
-
- // Advance the line counter to the current position.
- while (pos < matchPos) {
- if (text[pos] == '\n') {
- ++line;
- column = 0;
- } else {
- ++column;
- }
- ++pos;
- }
-
- // Match the next token.
- if (matchPos == text.Length) {
- // EOF
- currentToken = "";
- } else {
- Match match = TokenPattern.Match(text, matchPos);
- if (match.Success) {
- currentToken = match.Value;
- matchPos += match.Length;
- } else {
- // Take one character.
- currentToken = text[matchPos].ToString();
- matchPos++;
- }
-
- SkipWhitespace();
- }
- }
-
- /// <summary>
- /// Skip over any whitespace so that matchPos starts at the next token.
- /// </summary>
- private void SkipWhitespace() {
- Match match = WhitespaceAndCommentPattern.Match(text, matchPos);
- if (match.Success) {
- matchPos += match.Length;
- }
- }
-
- /// <summary>
- /// If the next token exactly matches the given token, consume it and return
- /// true. Otherwise, return false without doing anything.
- /// </summary>
- public bool TryConsume(string token) {
- if (currentToken == token) {
- NextToken();
- return true;
- }
- return false;
- }
-
- /*
- * If the next token exactly matches {@code token}, consume it. Otherwise,
- * throw a {@link ParseException}.
- */
- /// <summary>
- /// If the next token exactly matches the specified one, consume it.
- /// Otherwise, throw a FormatException.
- /// </summary>
- /// <param name="token"></param>
- public void Consume(string token) {
- if (!TryConsume(token)) {
- throw CreateFormatException("Expected \"" + token + "\".");
- }
- }
-
- /// <summary>
- /// Returns true if the next token is an integer, but does not consume it.
- /// </summary>
- public bool LookingAtInteger() {
- if (currentToken.Length == 0) {
- return false;
- }
-
- char c = currentToken[0];
- return ('0' <= c && c <= '9') || c == '-' || c == '+';
- }
-
- /// <summary>
- /// If the next token is an identifier, consume it and return its value.
- /// Otherwise, throw a FormatException.
- /// </summary>
- public string ConsumeIdentifier() {
- foreach (char c in currentToken) {
- if (('a' <= c && c <= 'z') ||
- ('A' <= c && c <= 'Z') ||
- ('0' <= c && c <= '9') ||
- (c == '_') || (c == '.')) {
- // OK
- } else {
- throw CreateFormatException("Expected identifier.");
- }
- }
-
- string result = currentToken;
- NextToken();
- return result;
- }
-
- /// <summary>
- /// If the next token is a 32-bit signed integer, consume it and return its
- /// value. Otherwise, throw a FormatException.
- /// </summary>
- public int ConsumeInt32() {
- try {
- int result = TextFormat.ParseInt32(currentToken);
- NextToken();
- return result;
- } catch (FormatException e) {
- throw CreateIntegerParseException(e);
- }
- }
-
- /// <summary>
- /// If the next token is a 32-bit unsigned integer, consume it and return its
- /// value. Otherwise, throw a FormatException.
- /// </summary>
- public uint ConsumeUInt32() {
- try {
- uint result = TextFormat.ParseUInt32(currentToken);
- NextToken();
- return result;
- } catch (FormatException e) {
- throw CreateIntegerParseException(e);
- }
- }
-
- /// <summary>
- /// If the next token is a 64-bit signed integer, consume it and return its
- /// value. Otherwise, throw a FormatException.
- /// </summary>
- public long ConsumeInt64() {
- try {
- long result = TextFormat.ParseInt64(currentToken);
- NextToken();
- return result;
- } catch (FormatException e) {
- throw CreateIntegerParseException(e);
- }
- }
-
- /// <summary>
- /// If the next token is a 64-bit unsigned integer, consume it and return its
- /// value. Otherwise, throw a FormatException.
- /// </summary>
- public ulong ConsumeUInt64() {
- try {
- ulong result = TextFormat.ParseUInt64(currentToken);
- NextToken();
- return result;
- } catch (FormatException e) {
- throw CreateIntegerParseException(e);
- }
- }
-
- /// <summary>
- /// If the next token is a double, consume it and return its value.
- /// Otherwise, throw a FormatException.
- /// </summary>
- public double ConsumeDouble() {
- // We need to parse infinity and nan separately because
- // double.Parse() does not accept "inf", "infinity", or "nan".
- if (DoubleInfinity.IsMatch(currentToken)) {
- bool negative = currentToken.StartsWith("-");
- NextToken();
- return negative ? double.NegativeInfinity : double.PositiveInfinity;
- }
- if (currentToken.Equals("nan", StringComparison.InvariantCultureIgnoreCase)) {
- NextToken();
- return Double.NaN;
- }
-
- try {
- double result = double.Parse(currentToken, CultureInfo.InvariantCulture);
- NextToken();
- return result;
- } catch (FormatException e) {
- throw CreateFloatParseException(e);
- } catch (OverflowException e) {
- throw CreateFloatParseException(e);
- }
- }
-
- /// <summary>
- /// If the next token is a float, consume it and return its value.
- /// Otherwise, throw a FormatException.
- /// </summary>
- public float ConsumeFloat() {
- // We need to parse infinity and nan separately because
- // Float.parseFloat() does not accept "inf", "infinity", or "nan".
- if (FloatInfinity.IsMatch(currentToken)) {
- bool negative = currentToken.StartsWith("-");
- NextToken();
- return negative ? float.NegativeInfinity : float.PositiveInfinity;
- }
- if (FloatNan.IsMatch(currentToken)) {
- NextToken();
- return float.NaN;
- }
-
- if (currentToken.EndsWith("f")) {
- currentToken = currentToken.TrimEnd('f');
- }
-
- try {
- float result = float.Parse(currentToken, CultureInfo.InvariantCulture);
- NextToken();
- return result;
- } catch (FormatException e) {
- throw CreateFloatParseException(e);
- } catch (OverflowException e) {
- throw CreateFloatParseException(e);
- }
- }
-
- /// <summary>
- /// If the next token is a Boolean, consume it and return its value.
- /// Otherwise, throw a FormatException.
- /// </summary>
- public bool ConsumeBoolean() {
- if (currentToken == "true") {
- NextToken();
- return true;
- }
- if (currentToken == "false") {
- NextToken();
- return false;
- }
- throw CreateFormatException("Expected \"true\" or \"false\".");
- }
-
- /// <summary>
- /// If the next token is a string, consume it and return its (unescaped) value.
- /// Otherwise, throw a FormatException.
- /// </summary>
- public string ConsumeString() {
- return ConsumeByteString().ToStringUtf8();
- }
-
- /// <summary>
- /// If the next token is a string, consume it, unescape it as a
- /// ByteString and return it. Otherwise, throw a FormatException.
- /// </summary>
- public ByteString ConsumeByteString() {
- char quote = currentToken.Length > 0 ? currentToken[0] : '\0';
- if (quote != '\"' && quote != '\'') {
- throw CreateFormatException("Expected string.");
- }
-
- if (currentToken.Length < 2 ||
- currentToken[currentToken.Length-1] != quote) {
- throw CreateFormatException("String missing ending quote.");
- }
-
- try {
- string escaped = currentToken.Substring(1, currentToken.Length - 2);
- ByteString result = TextFormat.UnescapeBytes(escaped);
- NextToken();
- return result;
- } catch (FormatException e) {
- throw CreateFormatException(e.Message);
- }
- }
-
- /// <summary>
- /// Returns a format exception with the current line and column numbers
- /// in the description, suitable for throwing.
- /// </summary>
- public FormatException CreateFormatException(string description) {
- // Note: People generally prefer one-based line and column numbers.
- return new FormatException((line + 1) + ":" + (column + 1) + ": " + description);
- }
-
- /// <summary>
- /// Returns a format exception with the line and column numbers of the
- /// previous token in the description, suitable for throwing.
- /// </summary>
- public FormatException CreateFormatExceptionPreviousToken(string description) {
- // Note: People generally prefer one-based line and column numbers.
- return new FormatException((previousLine + 1) + ":" + (previousColumn + 1) + ": " + description);
- }
-
- /// <summary>
- /// Constructs an appropriate FormatException for the given existing exception
- /// when trying to parse an integer.
- /// </summary>
- private FormatException CreateIntegerParseException(FormatException e) {
- return CreateFormatException("Couldn't parse integer: " + e.Message);
- }
-
- /// <summary>
- /// Constructs an appropriate FormatException for the given existing exception
- /// when trying to parse a float or double.
- /// </summary>
- private FormatException CreateFloatParseException(Exception e) {
- return CreateFormatException("Couldn't parse number: " + e.Message);
- }
- }
-}
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Globalization;
+using System.Text.RegularExpressions;
+
+namespace Google.ProtocolBuffers {
+ /// <summary>
+ /// Represents a stream of tokens parsed from a string.
+ /// </summary>
+ internal sealed class TextTokenizer {
+ private readonly string text;
+ private string currentToken;
+
+ /// <summary>
+ /// The character index within the text to perform the next regex match at.
+ /// </summary>
+ private int matchPos = 0;
+
+ /// <summary>
+ /// The character index within the text at which the current token begins.
+ /// </summary>
+ private int pos = 0;
+
+ /// <summary>
+ /// The line number of the current token.
+ /// </summary>
+ private int line = 0;
+ /// <summary>
+ /// The column number of the current token.
+ /// </summary>
+ private int column = 0;
+
+ /// <summary>
+ /// The line number of the previous token.
+ /// </summary>
+ private int previousLine = 0;
+ /// <summary>
+ /// The column number of the previous token.
+ /// </summary>
+ private int previousColumn = 0;
+
+ // Note: atomic groups used to mimic possessive quantifiers in Java in both of these regexes
+ internal static readonly Regex WhitespaceAndCommentPattern = new Regex("\\G(?>(\\s|(#.*$))+)",
+ SilverlightCompatibility.CompiledRegexWhereAvailable | RegexOptions.Multiline);
+ private static readonly Regex TokenPattern = new Regex(
+ "\\G[a-zA-Z_](?>[0-9a-zA-Z_+-]*)|" + // an identifier
+ "\\G[0-9+-](?>[0-9a-zA-Z_.+-]*)|" + // a number
+ "\\G\"(?>([^\"\\\n\\\\]|\\\\.)*)(\"|\\\\?$)|" + // a double-quoted string
+ "\\G\'(?>([^\"\\\n\\\\]|\\\\.)*)(\'|\\\\?$)", // a single-quoted string
+ SilverlightCompatibility.CompiledRegexWhereAvailable | RegexOptions.Multiline);
+
+ private static readonly Regex DoubleInfinity = new Regex("^-?inf(inity)?$",
+ SilverlightCompatibility.CompiledRegexWhereAvailable | RegexOptions.IgnoreCase);
+ private static readonly Regex FloatInfinity = new Regex("^-?inf(inity)?f?$",
+ SilverlightCompatibility.CompiledRegexWhereAvailable | RegexOptions.IgnoreCase);
+ private static readonly Regex FloatNan = new Regex("^nanf?$",
+ SilverlightCompatibility.CompiledRegexWhereAvailable | RegexOptions.IgnoreCase);
+
+ /** Construct a tokenizer that parses tokens from the given text. */
+ public TextTokenizer(string text) {
+ this.text = text;
+ SkipWhitespace();
+ NextToken();
+ }
+
+ /// <summary>
+ /// Are we at the end of the input?
+ /// </summary>
+ public bool AtEnd {
+ get { return currentToken.Length == 0; }
+ }
+
+ /// <summary>
+ /// Advances to the next token.
+ /// </summary>
+ public void NextToken() {
+ previousLine = line;
+ previousColumn = column;
+
+ // Advance the line counter to the current position.
+ while (pos < matchPos) {
+ if (text[pos] == '\n') {
+ ++line;
+ column = 0;
+ } else {
+ ++column;
+ }
+ ++pos;
+ }
+
+ // Match the next token.
+ if (matchPos == text.Length) {
+ // EOF
+ currentToken = "";
+ } else {
+ Match match = TokenPattern.Match(text, matchPos);
+ if (match.Success) {
+ currentToken = match.Value;
+ matchPos += match.Length;
+ } else {
+ // Take one character.
+ currentToken = text[matchPos].ToString();
+ matchPos++;
+ }
+
+ SkipWhitespace();
+ }
+ }
+
+ /// <summary>
+ /// Skip over any whitespace so that matchPos starts at the next token.
+ /// </summary>
+ private void SkipWhitespace() {
+ Match match = WhitespaceAndCommentPattern.Match(text, matchPos);
+ if (match.Success) {
+ matchPos += match.Length;
+ }
+ }
+
+ /// <summary>
+ /// If the next token exactly matches the given token, consume it and return
+ /// true. Otherwise, return false without doing anything.
+ /// </summary>
+ public bool TryConsume(string token) {
+ if (currentToken == token) {
+ NextToken();
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ * If the next token exactly matches {@code token}, consume it. Otherwise,
+ * throw a {@link ParseException}.
+ */
+ /// <summary>
+ /// If the next token exactly matches the specified one, consume it.
+ /// Otherwise, throw a FormatException.
+ /// </summary>
+ /// <param name="token"></param>
+ public void Consume(string token) {
+ if (!TryConsume(token)) {
+ throw CreateFormatException("Expected \"" + token + "\".");
+ }
+ }
+
+ /// <summary>
+ /// Returns true if the next token is an integer, but does not consume it.
+ /// </summary>
+ public bool LookingAtInteger() {
+ if (currentToken.Length == 0) {
+ return false;
+ }
+
+ char c = currentToken[0];
+ return ('0' <= c && c <= '9') || c == '-' || c == '+';
+ }
+
+ /// <summary>
+ /// If the next token is an identifier, consume it and return its value.
+ /// Otherwise, throw a FormatException.
+ /// </summary>
+ public string ConsumeIdentifier() {
+ foreach (char c in currentToken) {
+ if (('a' <= c && c <= 'z') ||
+ ('A' <= c && c <= 'Z') ||
+ ('0' <= c && c <= '9') ||
+ (c == '_') || (c == '.')) {
+ // OK
+ } else {
+ throw CreateFormatException("Expected identifier.");
+ }
+ }
+
+ string result = currentToken;
+ NextToken();
+ return result;
+ }
+
+ /// <summary>
+ /// If the next token is a 32-bit signed integer, consume it and return its
+ /// value. Otherwise, throw a FormatException.
+ /// </summary>
+ public int ConsumeInt32() {
+ try {
+ int result = TextFormat.ParseInt32(currentToken);
+ NextToken();
+ return result;
+ } catch (FormatException e) {
+ throw CreateIntegerParseException(e);
+ }
+ }
+
+ /// <summary>
+ /// If the next token is a 32-bit unsigned integer, consume it and return its
+ /// value. Otherwise, throw a FormatException.
+ /// </summary>
+ public uint ConsumeUInt32() {
+ try {
+ uint result = TextFormat.ParseUInt32(currentToken);
+ NextToken();
+ return result;
+ } catch (FormatException e) {
+ throw CreateIntegerParseException(e);
+ }
+ }
+
+ /// <summary>
+ /// If the next token is a 64-bit signed integer, consume it and return its
+ /// value. Otherwise, throw a FormatException.
+ /// </summary>
+ public long ConsumeInt64() {
+ try {
+ long result = TextFormat.ParseInt64(currentToken);
+ NextToken();
+ return result;
+ } catch (FormatException e) {
+ throw CreateIntegerParseException(e);
+ }
+ }
+
+ /// <summary>
+ /// If the next token is a 64-bit unsigned integer, consume it and return its
+ /// value. Otherwise, throw a FormatException.
+ /// </summary>
+ public ulong ConsumeUInt64() {
+ try {
+ ulong result = TextFormat.ParseUInt64(currentToken);
+ NextToken();
+ return result;
+ } catch (FormatException e) {
+ throw CreateIntegerParseException(e);
+ }
+ }
+
+ /// <summary>
+ /// If the next token is a double, consume it and return its value.
+ /// Otherwise, throw a FormatException.
+ /// </summary>
+ public double ConsumeDouble() {
+ // We need to parse infinity and nan separately because
+ // double.Parse() does not accept "inf", "infinity", or "nan".
+ if (DoubleInfinity.IsMatch(currentToken)) {
+ bool negative = currentToken.StartsWith("-");
+ NextToken();
+ return negative ? double.NegativeInfinity : double.PositiveInfinity;
+ }
+ if (currentToken.Equals("nan", StringComparison.InvariantCultureIgnoreCase)) {
+ NextToken();
+ return Double.NaN;
+ }
+
+ try {
+ double result = double.Parse(currentToken, CultureInfo.InvariantCulture);
+ NextToken();
+ return result;
+ } catch (FormatException e) {
+ throw CreateFloatParseException(e);
+ } catch (OverflowException e) {
+ throw CreateFloatParseException(e);
+ }
+ }
+
+ /// <summary>
+ /// If the next token is a float, consume it and return its value.
+ /// Otherwise, throw a FormatException.
+ /// </summary>
+ public float ConsumeFloat() {
+ // We need to parse infinity and nan separately because
+ // Float.parseFloat() does not accept "inf", "infinity", or "nan".
+ if (FloatInfinity.IsMatch(currentToken)) {
+ bool negative = currentToken.StartsWith("-");
+ NextToken();
+ return negative ? float.NegativeInfinity : float.PositiveInfinity;
+ }
+ if (FloatNan.IsMatch(currentToken)) {
+ NextToken();
+ return float.NaN;
+ }
+
+ if (currentToken.EndsWith("f")) {
+ currentToken = currentToken.TrimEnd('f');
+ }
+
+ try {
+ float result = float.Parse(currentToken, CultureInfo.InvariantCulture);
+ NextToken();
+ return result;
+ } catch (FormatException e) {
+ throw CreateFloatParseException(e);
+ } catch (OverflowException e) {
+ throw CreateFloatParseException(e);
+ }
+ }
+
+ /// <summary>
+ /// If the next token is a Boolean, consume it and return its value.
+ /// Otherwise, throw a FormatException.
+ /// </summary>
+ public bool ConsumeBoolean() {
+ if (currentToken == "true") {
+ NextToken();
+ return true;
+ }
+ if (currentToken == "false") {
+ NextToken();
+ return false;
+ }
+ throw CreateFormatException("Expected \"true\" or \"false\".");
+ }
+
+ /// <summary>
+ /// If the next token is a string, consume it and return its (unescaped) value.
+ /// Otherwise, throw a FormatException.
+ /// </summary>
+ public string ConsumeString() {
+ return ConsumeByteString().ToStringUtf8();
+ }
+
+ /// <summary>
+ /// If the next token is a string, consume it, unescape it as a
+ /// ByteString and return it. Otherwise, throw a FormatException.
+ /// </summary>
+ public ByteString ConsumeByteString() {
+ char quote = currentToken.Length > 0 ? currentToken[0] : '\0';
+ if (quote != '\"' && quote != '\'') {
+ throw CreateFormatException("Expected string.");
+ }
+
+ if (currentToken.Length < 2 ||
+ currentToken[currentToken.Length-1] != quote) {
+ throw CreateFormatException("String missing ending quote.");
+ }
+
+ try {
+ string escaped = currentToken.Substring(1, currentToken.Length - 2);
+ ByteString result = TextFormat.UnescapeBytes(escaped);
+ NextToken();
+ return result;
+ } catch (FormatException e) {
+ throw CreateFormatException(e.Message);
+ }
+ }
+
+ /// <summary>
+ /// Returns a format exception with the current line and column numbers
+ /// in the description, suitable for throwing.
+ /// </summary>
+ public FormatException CreateFormatException(string description) {
+ // Note: People generally prefer one-based line and column numbers.
+ return new FormatException((line + 1) + ":" + (column + 1) + ": " + description);
+ }
+
+ /// <summary>
+ /// Returns a format exception with the line and column numbers of the
+ /// previous token in the description, suitable for throwing.
+ /// </summary>
+ public FormatException CreateFormatExceptionPreviousToken(string description) {
+ // Note: People generally prefer one-based line and column numbers.
+ return new FormatException((previousLine + 1) + ":" + (previousColumn + 1) + ": " + description);
+ }
+
+ /// <summary>
+ /// Constructs an appropriate FormatException for the given existing exception
+ /// when trying to parse an integer.
+ /// </summary>
+ private FormatException CreateIntegerParseException(FormatException e) {
+ return CreateFormatException("Couldn't parse integer: " + e.Message);
+ }
+
+ /// <summary>
+ /// Constructs an appropriate FormatException for the given existing exception
+ /// when trying to parse a float or double.
+ /// </summary>
+ private FormatException CreateFloatParseException(Exception e) {
+ return CreateFormatException("Couldn't parse number: " + e.Message);
+ }
+ }
+}
diff --git a/src/ProtocolBuffers/ThrowHelper.cs b/src/ProtocolBuffers/ThrowHelper.cs
index 76983140..580024db 100644
--- a/src/ProtocolBuffers/ThrowHelper.cs
+++ b/src/ProtocolBuffers/ThrowHelper.cs
@@ -1,73 +1,73 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://github.com/jskeet/dotnet-protobufs/
-// Original C++/Java/Python code:
-// http://code.google.com/p/protobuf/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System;
-using System.Collections.Generic;
-
-namespace Google.ProtocolBuffers {
- /// <summary>
- /// Helper methods for throwing exceptions
- /// </summary>
- public static class ThrowHelper {
-
- /// <summary>
- /// Throws an ArgumentNullException if the given value is null.
- /// </summary>
- public static void ThrowIfNull(object value, string name) {
- if (value == null) {
- throw new ArgumentNullException(name);
- }
- }
-
- /// <summary>
- /// Throws an ArgumentNullException if the given value is null.
- /// </summary>
- public static void ThrowIfNull(object value) {
- if (value == null) {
- throw new ArgumentNullException();
- }
- }
-
- /// <summary>
- /// Throws an ArgumentNullException if the given value or any element within it is null.
- /// </summary>
- public static void ThrowIfAnyNull<T>(IEnumerable<T> sequence) {
- foreach (T t in sequence) {
- if (t == null) {
- throw new ArgumentNullException();
- }
- }
- }
- }
-}
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace Google.ProtocolBuffers {
+ /// <summary>
+ /// Helper methods for throwing exceptions
+ /// </summary>
+ public static class ThrowHelper {
+
+ /// <summary>
+ /// Throws an ArgumentNullException if the given value is null.
+ /// </summary>
+ public static void ThrowIfNull(object value, string name) {
+ if (value == null) {
+ throw new ArgumentNullException(name);
+ }
+ }
+
+ /// <summary>
+ /// Throws an ArgumentNullException if the given value is null.
+ /// </summary>
+ public static void ThrowIfNull(object value) {
+ if (value == null) {
+ throw new ArgumentNullException();
+ }
+ }
+
+ /// <summary>
+ /// Throws an ArgumentNullException if the given value or any element within it is null.
+ /// </summary>
+ public static void ThrowIfAnyNull<T>(IEnumerable<T> sequence) {
+ foreach (T t in sequence) {
+ if (t == null) {
+ throw new ArgumentNullException();
+ }
+ }
+ }
+ }
+}
diff --git a/src/ProtocolBuffers/UninitializedMessageException.cs b/src/ProtocolBuffers/UninitializedMessageException.cs
index d7f58197..96f50653 100644
--- a/src/ProtocolBuffers/UninitializedMessageException.cs
+++ b/src/ProtocolBuffers/UninitializedMessageException.cs
@@ -1,170 +1,170 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://github.com/jskeet/dotnet-protobufs/
-// Original C++/Java/Python code:
-// http://code.google.com/p/protobuf/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Text;
-#if !LITE
-using Google.ProtocolBuffers.Collections;
-using Google.ProtocolBuffers.Descriptors;
-#endif
-
-namespace Google.ProtocolBuffers {
- /// <summary>
- /// TODO(jonskeet): Write summary text.
- /// </summary>
- public sealed class UninitializedMessageException : Exception {
-
- private readonly IList<string> missingFields;
-
- private UninitializedMessageException(IList<string> missingFields)
- : base(BuildDescription(missingFields)) {
- this.missingFields = new List<string>(missingFields);
- }
- /// <summary>
- /// Returns a read-only list of human-readable names of
- /// required fields missing from this message. Each name
- /// is a full path to a field, e.g. "foo.bar[5].baz"
- /// </summary>
- public IList<string> MissingFields {
- get { return missingFields; }
- }
-
- /// <summary>
- /// Converts this exception into an InvalidProtocolBufferException.
- /// When a parsed message is missing required fields, this should be thrown
- /// instead of UninitializedMessageException.
- /// </summary>
- public InvalidProtocolBufferException AsInvalidProtocolBufferException() {
- return new InvalidProtocolBufferException(Message);
- }
-
- /// <summary>
- /// Constructs the description string for a given list of missing fields.
- /// </summary>
- private static string BuildDescription(IEnumerable<string> missingFields) {
- StringBuilder description = new StringBuilder("Message missing required fields: ");
- bool first = true;
- foreach(string field in missingFields) {
- if (first) {
- first = false;
- } else {
- description.Append(", ");
- }
- description.Append(field);
- }
- return description.ToString();
- }
-
- /// <summary>
- /// For Lite exceptions that do not known how to enumerate missing fields
- /// </summary>
- public UninitializedMessageException(IMessageLite message)
- : base(String.Format("Message {0} is missing required fields", message.GetType())) {
- missingFields = new List<string>();
- }
-
-#if !LITE
- public UninitializedMessageException(IMessage message)
- : this(FindMissingFields(message)) {
- }
-
- /// <summary>
- /// Returns a list of the full "paths" of missing required
- /// fields in the specified message.
- /// </summary>
- private static IList<String> FindMissingFields(IMessage message) {
- List<String> results = new List<String>();
- FindMissingFields(message, "", results);
- return results;
- }
-
- /// <summary>
- /// Recursive helper implementing FindMissingFields.
- /// </summary>
- private static void FindMissingFields(IMessage message, String prefix, List<String> results) {
- foreach (FieldDescriptor field in message.DescriptorForType.Fields) {
- if (field.IsRequired && !message.HasField(field)) {
- results.Add(prefix + field.Name);
- }
- }
-
- foreach (KeyValuePair<FieldDescriptor, object> entry in message.AllFields) {
- FieldDescriptor field = entry.Key;
- object value = entry.Value;
-
- if (field.MappedType == MappedType.Message) {
- if (field.IsRepeated) {
- int i = 0;
- foreach (object element in (IEnumerable) value) {
- if (element is IMessage) {
- FindMissingFields((IMessage)element, SubMessagePrefix(prefix, field, i++), results);
- } else {
- results.Add(prefix + field.Name);
- }
- }
- } else {
- if (message.HasField(field)) {
- if (value is IMessage) {
- FindMissingFields((IMessage)value, SubMessagePrefix(prefix, field, -1), results);
- } else {
- results.Add(prefix + field.Name);
- }
- }
- }
- }
- }
- }
-
- private static String SubMessagePrefix(String prefix, FieldDescriptor field, int index) {
- StringBuilder result = new StringBuilder(prefix);
- if (field.IsExtension) {
- result.Append('(')
- .Append(field.FullName)
- .Append(')');
- } else {
- result.Append(field.Name);
- }
- if (index != -1) {
- result.Append('[')
- .Append(index)
- .Append(']');
- }
- result.Append('.');
- return result.ToString();
- }
-#endif
- }
-}
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+#if !LITE
+using Google.ProtocolBuffers.Collections;
+using Google.ProtocolBuffers.Descriptors;
+#endif
+
+namespace Google.ProtocolBuffers {
+ /// <summary>
+ /// TODO(jonskeet): Write summary text.
+ /// </summary>
+ public sealed class UninitializedMessageException : Exception {
+
+ private readonly IList<string> missingFields;
+
+ private UninitializedMessageException(IList<string> missingFields)
+ : base(BuildDescription(missingFields)) {
+ this.missingFields = new List<string>(missingFields);
+ }
+ /// <summary>
+ /// Returns a read-only list of human-readable names of
+ /// required fields missing from this message. Each name
+ /// is a full path to a field, e.g. "foo.bar[5].baz"
+ /// </summary>
+ public IList<string> MissingFields {
+ get { return missingFields; }
+ }
+
+ /// <summary>
+ /// Converts this exception into an InvalidProtocolBufferException.
+ /// When a parsed message is missing required fields, this should be thrown
+ /// instead of UninitializedMessageException.
+ /// </summary>
+ public InvalidProtocolBufferException AsInvalidProtocolBufferException() {
+ return new InvalidProtocolBufferException(Message);
+ }
+
+ /// <summary>
+ /// Constructs the description string for a given list of missing fields.
+ /// </summary>
+ private static string BuildDescription(IEnumerable<string> missingFields) {
+ StringBuilder description = new StringBuilder("Message missing required fields: ");
+ bool first = true;
+ foreach(string field in missingFields) {
+ if (first) {
+ first = false;
+ } else {
+ description.Append(", ");
+ }
+ description.Append(field);
+ }
+ return description.ToString();
+ }
+
+ /// <summary>
+ /// For Lite exceptions that do not known how to enumerate missing fields
+ /// </summary>
+ public UninitializedMessageException(IMessageLite message)
+ : base(String.Format("Message {0} is missing required fields", message.GetType())) {
+ missingFields = new List<string>();
+ }
+
+#if !LITE
+ public UninitializedMessageException(IMessage message)
+ : this(FindMissingFields(message)) {
+ }
+
+ /// <summary>
+ /// Returns a list of the full "paths" of missing required
+ /// fields in the specified message.
+ /// </summary>
+ private static IList<String> FindMissingFields(IMessage message) {
+ List<String> results = new List<String>();
+ FindMissingFields(message, "", results);
+ return results;
+ }
+
+ /// <summary>
+ /// Recursive helper implementing FindMissingFields.
+ /// </summary>
+ private static void FindMissingFields(IMessage message, String prefix, List<String> results) {
+ foreach (FieldDescriptor field in message.DescriptorForType.Fields) {
+ if (field.IsRequired && !message.HasField(field)) {
+ results.Add(prefix + field.Name);
+ }
+ }
+
+ foreach (KeyValuePair<FieldDescriptor, object> entry in message.AllFields) {
+ FieldDescriptor field = entry.Key;
+ object value = entry.Value;
+
+ if (field.MappedType == MappedType.Message) {
+ if (field.IsRepeated) {
+ int i = 0;
+ foreach (object element in (IEnumerable) value) {
+ if (element is IMessage) {
+ FindMissingFields((IMessage)element, SubMessagePrefix(prefix, field, i++), results);
+ } else {
+ results.Add(prefix + field.Name);
+ }
+ }
+ } else {
+ if (message.HasField(field)) {
+ if (value is IMessage) {
+ FindMissingFields((IMessage)value, SubMessagePrefix(prefix, field, -1), results);
+ } else {
+ results.Add(prefix + field.Name);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static String SubMessagePrefix(String prefix, FieldDescriptor field, int index) {
+ StringBuilder result = new StringBuilder(prefix);
+ if (field.IsExtension) {
+ result.Append('(')
+ .Append(field.FullName)
+ .Append(')');
+ } else {
+ result.Append(field.Name);
+ }
+ if (index != -1) {
+ result.Append('[')
+ .Append(index)
+ .Append(']');
+ }
+ result.Append('.');
+ return result.ToString();
+ }
+#endif
+ }
+}
diff --git a/src/ProtocolBuffers/UnknownField.cs b/src/ProtocolBuffers/UnknownField.cs
index ad1b59b4..7aed8473 100644
--- a/src/ProtocolBuffers/UnknownField.cs
+++ b/src/ProtocolBuffers/UnknownField.cs
@@ -1,371 +1,371 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://github.com/jskeet/dotnet-protobufs/
-// Original C++/Java/Python code:
-// http://code.google.com/p/protobuf/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using Google.ProtocolBuffers.Collections;
-
-namespace Google.ProtocolBuffers {
- /// <summary>
- /// Represents a single field in an UnknownFieldSet.
- ///
- /// An UnknownField consists of five lists of values. The lists correspond
- /// to the five "wire types" used in the protocol buffer binary format.
- /// The wire type of each field can be determined from the encoded form alone,
- /// without knowing the field's declared type. So, we are able to parse
- /// unknown values at least this far and separate them. Normally, only one
- /// of the five lists will contain any values, since it is impossible to
- /// define a valid message type that declares two different types for the
- /// same field number. However, the code is designed to allow for the case
- /// where the same unknown field number is encountered using multiple different
- /// wire types.
- ///
- /// UnknownField is an immutable class. To construct one, you must use an
- /// UnknownField.Builder.
- /// </summary>
- public sealed class UnknownField {
-
- private static readonly UnknownField defaultInstance = CreateBuilder().Build();
- private readonly ReadOnlyCollection<ulong> varintList;
- private readonly ReadOnlyCollection<uint> fixed32List;
- private readonly ReadOnlyCollection<ulong> fixed64List;
- private readonly ReadOnlyCollection<ByteString> lengthDelimitedList;
- private readonly ReadOnlyCollection<UnknownFieldSet> groupList;
-
- private UnknownField(ReadOnlyCollection<ulong> varintList,
- ReadOnlyCollection<uint> fixed32List,
- ReadOnlyCollection<ulong> fixed64List,
- ReadOnlyCollection<ByteString> lengthDelimitedList,
- ReadOnlyCollection<UnknownFieldSet> groupList) {
- this.varintList = varintList;
- this.fixed32List = fixed32List;
- this.fixed64List = fixed64List;
- this.lengthDelimitedList = lengthDelimitedList;
- this.groupList = groupList;
- }
-
- public static UnknownField DefaultInstance {
- get { return defaultInstance; }
- }
-
- /// <summary>
- /// The list of varint values for this field.
- /// </summary>
- public IList<ulong> VarintList {
- get { return varintList; }
- }
-
- /// <summary>
- /// The list of fixed32 values for this field.
- /// </summary>
- public IList<uint> Fixed32List {
- get { return fixed32List; }
- }
-
- /// <summary>
- /// The list of fixed64 values for this field.
- /// </summary>
- public IList<ulong> Fixed64List {
- get { return fixed64List; }
- }
-
- /// <summary>
- /// The list of length-delimited values for this field.
- /// </summary>
- public IList<ByteString> LengthDelimitedList {
- get { return lengthDelimitedList; }
- }
-
- /// <summary>
- /// The list of embedded group values for this field. These
- /// are represented using UnknownFieldSets rather than Messages
- /// since the group's type is presumably unknown.
- /// </summary>
- public IList<UnknownFieldSet> GroupList {
- get { return groupList; }
- }
-
- public override bool Equals(object other) {
- if (ReferenceEquals(this, other)) {
- return true;
- }
- UnknownField otherField = other as UnknownField;
- return otherField != null
- && Lists.Equals(varintList, otherField.varintList)
- && Lists.Equals(fixed32List, otherField.fixed32List)
- && Lists.Equals(fixed64List, otherField.fixed64List)
- && Lists.Equals(lengthDelimitedList, otherField.lengthDelimitedList)
- && Lists.Equals(groupList, otherField.groupList);
- }
-
- public override int GetHashCode() {
- int hash = 43;
- hash = hash * 47 + Lists.GetHashCode(varintList);
- hash = hash * 47 + Lists.GetHashCode(fixed32List);
- hash = hash * 47 + Lists.GetHashCode(fixed64List);
- hash = hash * 47 + Lists.GetHashCode(lengthDelimitedList);
- hash = hash * 47 + Lists.GetHashCode(groupList);
- return hash;
- }
-
- /// <summary>
- /// Constructs a new Builder.
- /// </summary>
- public static Builder CreateBuilder() {
- return new Builder();
- }
-
- /// <summary>
- /// Constructs a new Builder and initializes it to a copy of <paramref name="copyFrom"/>.
- /// </summary>
- public static Builder CreateBuilder(UnknownField copyFrom) {
- return new Builder().MergeFrom(copyFrom);
- }
-
- /// <summary>
- /// Serializes the field, including the field number, and writes it to
- /// <paramref name="output"/>.
- /// </summary>
- public void WriteTo(int fieldNumber, CodedOutputStream output) {
- foreach (ulong value in varintList) {
- output.WriteUInt64(fieldNumber, value);
- }
- foreach (uint value in fixed32List) {
- output.WriteFixed32(fieldNumber, value);
- }
- foreach (ulong value in fixed64List) {
- output.WriteFixed64(fieldNumber, value);
- }
- foreach (ByteString value in lengthDelimitedList) {
- output.WriteBytes(fieldNumber, value);
- }
- foreach (UnknownFieldSet value in groupList) {
-#pragma warning disable 0612
- output.WriteUnknownGroup(fieldNumber, value);
-#pragma warning restore 0612
- }
- }
-
- /// <summary>
- /// Computes the number of bytes required to encode this field, including field
- /// number.
- /// </summary>
- public int GetSerializedSize(int fieldNumber) {
- int result = 0;
- foreach (ulong value in varintList) {
- result += CodedOutputStream.ComputeUInt64Size(fieldNumber, value);
- }
- foreach (uint value in fixed32List) {
- result += CodedOutputStream.ComputeFixed32Size(fieldNumber, value);
- }
- foreach (ulong value in fixed64List) {
- result += CodedOutputStream.ComputeFixed64Size(fieldNumber, value);
- }
- foreach (ByteString value in lengthDelimitedList) {
- result += CodedOutputStream.ComputeBytesSize(fieldNumber, value);
- }
- foreach (UnknownFieldSet value in groupList) {
-#pragma warning disable 0612
- result += CodedOutputStream.ComputeUnknownGroupSize(fieldNumber, value);
-#pragma warning restore 0612
- }
- return result;
- }
-
- /// <summary>
- /// Serializes the length-delimited values of the field, including field
- /// number, and writes them to <paramref name="output"/> using the MessageSet wire format.
- /// </summary>
- /// <param name="fieldNumber"></param>
- /// <param name="output"></param>
- public void WriteAsMessageSetExtensionTo(int fieldNumber, CodedOutputStream output) {
- foreach (ByteString value in lengthDelimitedList) {
- output.WriteRawMessageSetExtension(fieldNumber, value);
- }
- }
-
- /// <summary>
- /// Get the number of bytes required to encode this field, incuding field number,
- /// using the MessageSet wire format.
- /// </summary>
- public int GetSerializedSizeAsMessageSetExtension(int fieldNumber) {
- int result = 0;
- foreach (ByteString value in lengthDelimitedList) {
- result += CodedOutputStream.ComputeRawMessageSetExtensionSize(fieldNumber, value);
- }
- return result;
- }
-
- /// <summary>
- /// Used to build instances of UnknownField.
- /// </summary>
- public sealed class Builder {
-
- private List<ulong> varintList;
- private List<uint> fixed32List;
- private List<ulong> fixed64List;
- private List<ByteString> lengthDelimitedList;
- private List<UnknownFieldSet> groupList;
-
- /// <summary>
- /// Builds the field. After building, the builder is reset to an empty
- /// state. (This is actually easier than making it unusable.)
- /// </summary>
- public UnknownField Build() {
- return new UnknownField(MakeReadOnly(ref varintList),
- MakeReadOnly(ref fixed32List),
- MakeReadOnly(ref fixed64List),
- MakeReadOnly(ref lengthDelimitedList),
- MakeReadOnly(ref groupList));
- }
-
- /// <summary>
- /// Merge the values in <paramref name="other" /> into this field. For each list
- /// of values, <paramref name="other"/>'s values are append to the ones in this
- /// field.
- /// </summary>
- public Builder MergeFrom(UnknownField other) {
- varintList = AddAll(varintList, other.VarintList);
- fixed32List = AddAll(fixed32List, other.Fixed32List);
- fixed64List = AddAll(fixed64List, other.Fixed64List);
- lengthDelimitedList = AddAll(lengthDelimitedList, other.LengthDelimitedList);
- groupList = AddAll(groupList, other.GroupList);
- return this;
- }
-
- /// <summary>
- /// Returns a new list containing all of the given specified values from
- /// both the <paramref name="current"/> and <paramref name="extras"/> lists.
- /// If <paramref name="current" /> is null and <paramref name="extras"/> is empty,
- /// null is returned. Otherwise, either a new list is created (if <paramref name="current" />
- /// is null) or the elements of <paramref name="extras"/> are added to <paramref name="current" />.
- /// </summary>
- private static List<T> AddAll<T>(List<T> current, IList<T> extras)
- {
- if (extras.Count == 0) {
- return current;
- }
- if (current == null) {
- current = new List<T>(extras);
- } else {
- current.AddRange(extras);
- }
- return current;
- }
-
- /// <summary>
- /// Clears the contents of this builder.
- /// </summary>
- public Builder Clear() {
- varintList = null;
- fixed32List = null;
- fixed64List = null;
- lengthDelimitedList = null;
- groupList = null;
- return this;
- }
-
- /// <summary>
- /// Adds a varint value.
- /// </summary>
- [CLSCompliant(false)]
- public Builder AddVarint(ulong value) {
- varintList = Add(varintList, value);
- return this;
- }
-
- /// <summary>
- /// Adds a fixed32 value.
- /// </summary>
- [CLSCompliant(false)]
- public Builder AddFixed32(uint value) {
- fixed32List = Add(fixed32List, value);
- return this;
- }
-
- /// <summary>
- /// Adds a fixed64 value.
- /// </summary>
- [CLSCompliant(false)]
- public Builder AddFixed64(ulong value) {
- fixed64List = Add(fixed64List, value);
- return this;
- }
-
- /// <summary>
- /// Adds a length-delimited value.
- /// </summary>
- public Builder AddLengthDelimited(ByteString value) {
- lengthDelimitedList = Add(lengthDelimitedList, value);
- return this;
- }
-
- /// <summary>
- /// Adds an embedded group.
- /// </summary>
- /// <param name="value"></param>
- /// <returns></returns>
- public Builder AddGroup(UnknownFieldSet value) {
- groupList = Add(groupList, value);
- return this;
- }
-
- /// <summary>
- /// Adds <paramref name="value"/> to the <paramref name="list"/>, creating
- /// a new list if <paramref name="list"/> is null. The list is returned - either
- /// the original reference or the new list.
- /// </summary>
- private static List<T> Add<T>(List<T> list, T value) {
- if (list == null) {
- list = new List<T>();
- }
- list.Add(value);
- return list;
- }
-
- /// <summary>
- /// Returns a read-only version of the given IList, and clears
- /// the field used for <paramref name="list"/>. If the value
- /// is null, an empty list is produced using Lists.Empty.
- /// </summary>
- /// <returns></returns>
- private static ReadOnlyCollection<T> MakeReadOnly<T>(ref List<T> list) {
- ReadOnlyCollection<T> ret = list == null ? Lists<T>.Empty : new ReadOnlyCollection<T>(list);
- list = null;
- return ret;
- }
- }
- }
-}
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using Google.ProtocolBuffers.Collections;
+
+namespace Google.ProtocolBuffers {
+ /// <summary>
+ /// Represents a single field in an UnknownFieldSet.
+ ///
+ /// An UnknownField consists of five lists of values. The lists correspond
+ /// to the five "wire types" used in the protocol buffer binary format.
+ /// The wire type of each field can be determined from the encoded form alone,
+ /// without knowing the field's declared type. So, we are able to parse
+ /// unknown values at least this far and separate them. Normally, only one
+ /// of the five lists will contain any values, since it is impossible to
+ /// define a valid message type that declares two different types for the
+ /// same field number. However, the code is designed to allow for the case
+ /// where the same unknown field number is encountered using multiple different
+ /// wire types.
+ ///
+ /// UnknownField is an immutable class. To construct one, you must use an
+ /// UnknownField.Builder.
+ /// </summary>
+ public sealed class UnknownField {
+
+ private static readonly UnknownField defaultInstance = CreateBuilder().Build();
+ private readonly ReadOnlyCollection<ulong> varintList;
+ private readonly ReadOnlyCollection<uint> fixed32List;
+ private readonly ReadOnlyCollection<ulong> fixed64List;
+ private readonly ReadOnlyCollection<ByteString> lengthDelimitedList;
+ private readonly ReadOnlyCollection<UnknownFieldSet> groupList;
+
+ private UnknownField(ReadOnlyCollection<ulong> varintList,
+ ReadOnlyCollection<uint> fixed32List,
+ ReadOnlyCollection<ulong> fixed64List,
+ ReadOnlyCollection<ByteString> lengthDelimitedList,
+ ReadOnlyCollection<UnknownFieldSet> groupList) {
+ this.varintList = varintList;
+ this.fixed32List = fixed32List;
+ this.fixed64List = fixed64List;
+ this.lengthDelimitedList = lengthDelimitedList;
+ this.groupList = groupList;
+ }
+
+ public static UnknownField DefaultInstance {
+ get { return defaultInstance; }
+ }
+
+ /// <summary>
+ /// The list of varint values for this field.
+ /// </summary>
+ public IList<ulong> VarintList {
+ get { return varintList; }
+ }
+
+ /// <summary>
+ /// The list of fixed32 values for this field.
+ /// </summary>
+ public IList<uint> Fixed32List {
+ get { return fixed32List; }
+ }
+
+ /// <summary>
+ /// The list of fixed64 values for this field.
+ /// </summary>
+ public IList<ulong> Fixed64List {
+ get { return fixed64List; }
+ }
+
+ /// <summary>
+ /// The list of length-delimited values for this field.
+ /// </summary>
+ public IList<ByteString> LengthDelimitedList {
+ get { return lengthDelimitedList; }
+ }
+
+ /// <summary>
+ /// The list of embedded group values for this field. These
+ /// are represented using UnknownFieldSets rather than Messages
+ /// since the group's type is presumably unknown.
+ /// </summary>
+ public IList<UnknownFieldSet> GroupList {
+ get { return groupList; }
+ }
+
+ public override bool Equals(object other) {
+ if (ReferenceEquals(this, other)) {
+ return true;
+ }
+ UnknownField otherField = other as UnknownField;
+ return otherField != null
+ && Lists.Equals(varintList, otherField.varintList)
+ && Lists.Equals(fixed32List, otherField.fixed32List)
+ && Lists.Equals(fixed64List, otherField.fixed64List)
+ && Lists.Equals(lengthDelimitedList, otherField.lengthDelimitedList)
+ && Lists.Equals(groupList, otherField.groupList);
+ }
+
+ public override int GetHashCode() {
+ int hash = 43;
+ hash = hash * 47 + Lists.GetHashCode(varintList);
+ hash = hash * 47 + Lists.GetHashCode(fixed32List);
+ hash = hash * 47 + Lists.GetHashCode(fixed64List);
+ hash = hash * 47 + Lists.GetHashCode(lengthDelimitedList);
+ hash = hash * 47 + Lists.GetHashCode(groupList);
+ return hash;
+ }
+
+ /// <summary>
+ /// Constructs a new Builder.
+ /// </summary>
+ public static Builder CreateBuilder() {
+ return new Builder();
+ }
+
+ /// <summary>
+ /// Constructs a new Builder and initializes it to a copy of <paramref name="copyFrom"/>.
+ /// </summary>
+ public static Builder CreateBuilder(UnknownField copyFrom) {
+ return new Builder().MergeFrom(copyFrom);
+ }
+
+ /// <summary>
+ /// Serializes the field, including the field number, and writes it to
+ /// <paramref name="output"/>.
+ /// </summary>
+ public void WriteTo(int fieldNumber, CodedOutputStream output) {
+ foreach (ulong value in varintList) {
+ output.WriteUInt64(fieldNumber, value);
+ }
+ foreach (uint value in fixed32List) {
+ output.WriteFixed32(fieldNumber, value);
+ }
+ foreach (ulong value in fixed64List) {
+ output.WriteFixed64(fieldNumber, value);
+ }
+ foreach (ByteString value in lengthDelimitedList) {
+ output.WriteBytes(fieldNumber, value);
+ }
+ foreach (UnknownFieldSet value in groupList) {
+#pragma warning disable 0612
+ output.WriteUnknownGroup(fieldNumber, value);
+#pragma warning restore 0612
+ }
+ }
+
+ /// <summary>
+ /// Computes the number of bytes required to encode this field, including field
+ /// number.
+ /// </summary>
+ public int GetSerializedSize(int fieldNumber) {
+ int result = 0;
+ foreach (ulong value in varintList) {
+ result += CodedOutputStream.ComputeUInt64Size(fieldNumber, value);
+ }
+ foreach (uint value in fixed32List) {
+ result += CodedOutputStream.ComputeFixed32Size(fieldNumber, value);
+ }
+ foreach (ulong value in fixed64List) {
+ result += CodedOutputStream.ComputeFixed64Size(fieldNumber, value);
+ }
+ foreach (ByteString value in lengthDelimitedList) {
+ result += CodedOutputStream.ComputeBytesSize(fieldNumber, value);
+ }
+ foreach (UnknownFieldSet value in groupList) {
+#pragma warning disable 0612
+ result += CodedOutputStream.ComputeUnknownGroupSize(fieldNumber, value);
+#pragma warning restore 0612
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Serializes the length-delimited values of the field, including field
+ /// number, and writes them to <paramref name="output"/> using the MessageSet wire format.
+ /// </summary>
+ /// <param name="fieldNumber"></param>
+ /// <param name="output"></param>
+ public void WriteAsMessageSetExtensionTo(int fieldNumber, CodedOutputStream output) {
+ foreach (ByteString value in lengthDelimitedList) {
+ output.WriteRawMessageSetExtension(fieldNumber, value);
+ }
+ }
+
+ /// <summary>
+ /// Get the number of bytes required to encode this field, incuding field number,
+ /// using the MessageSet wire format.
+ /// </summary>
+ public int GetSerializedSizeAsMessageSetExtension(int fieldNumber) {
+ int result = 0;
+ foreach (ByteString value in lengthDelimitedList) {
+ result += CodedOutputStream.ComputeRawMessageSetExtensionSize(fieldNumber, value);
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Used to build instances of UnknownField.
+ /// </summary>
+ public sealed class Builder {
+
+ private List<ulong> varintList;
+ private List<uint> fixed32List;
+ private List<ulong> fixed64List;
+ private List<ByteString> lengthDelimitedList;
+ private List<UnknownFieldSet> groupList;
+
+ /// <summary>
+ /// Builds the field. After building, the builder is reset to an empty
+ /// state. (This is actually easier than making it unusable.)
+ /// </summary>
+ public UnknownField Build() {
+ return new UnknownField(MakeReadOnly(ref varintList),
+ MakeReadOnly(ref fixed32List),
+ MakeReadOnly(ref fixed64List),
+ MakeReadOnly(ref lengthDelimitedList),
+ MakeReadOnly(ref groupList));
+ }
+
+ /// <summary>
+ /// Merge the values in <paramref name="other" /> into this field. For each list
+ /// of values, <paramref name="other"/>'s values are append to the ones in this
+ /// field.
+ /// </summary>
+ public Builder MergeFrom(UnknownField other) {
+ varintList = AddAll(varintList, other.VarintList);
+ fixed32List = AddAll(fixed32List, other.Fixed32List);
+ fixed64List = AddAll(fixed64List, other.Fixed64List);
+ lengthDelimitedList = AddAll(lengthDelimitedList, other.LengthDelimitedList);
+ groupList = AddAll(groupList, other.GroupList);
+ return this;
+ }
+
+ /// <summary>
+ /// Returns a new list containing all of the given specified values from
+ /// both the <paramref name="current"/> and <paramref name="extras"/> lists.
+ /// If <paramref name="current" /> is null and <paramref name="extras"/> is empty,
+ /// null is returned. Otherwise, either a new list is created (if <paramref name="current" />
+ /// is null) or the elements of <paramref name="extras"/> are added to <paramref name="current" />.
+ /// </summary>
+ private static List<T> AddAll<T>(List<T> current, IList<T> extras)
+ {
+ if (extras.Count == 0) {
+ return current;
+ }
+ if (current == null) {
+ current = new List<T>(extras);
+ } else {
+ current.AddRange(extras);
+ }
+ return current;
+ }
+
+ /// <summary>
+ /// Clears the contents of this builder.
+ /// </summary>
+ public Builder Clear() {
+ varintList = null;
+ fixed32List = null;
+ fixed64List = null;
+ lengthDelimitedList = null;
+ groupList = null;
+ return this;
+ }
+
+ /// <summary>
+ /// Adds a varint value.
+ /// </summary>
+ [CLSCompliant(false)]
+ public Builder AddVarint(ulong value) {
+ varintList = Add(varintList, value);
+ return this;
+ }
+
+ /// <summary>
+ /// Adds a fixed32 value.
+ /// </summary>
+ [CLSCompliant(false)]
+ public Builder AddFixed32(uint value) {
+ fixed32List = Add(fixed32List, value);
+ return this;
+ }
+
+ /// <summary>
+ /// Adds a fixed64 value.
+ /// </summary>
+ [CLSCompliant(false)]
+ public Builder AddFixed64(ulong value) {
+ fixed64List = Add(fixed64List, value);
+ return this;
+ }
+
+ /// <summary>
+ /// Adds a length-delimited value.
+ /// </summary>
+ public Builder AddLengthDelimited(ByteString value) {
+ lengthDelimitedList = Add(lengthDelimitedList, value);
+ return this;
+ }
+
+ /// <summary>
+ /// Adds an embedded group.
+ /// </summary>
+ /// <param name="value"></param>
+ /// <returns></returns>
+ public Builder AddGroup(UnknownFieldSet value) {
+ groupList = Add(groupList, value);
+ return this;
+ }
+
+ /// <summary>
+ /// Adds <paramref name="value"/> to the <paramref name="list"/>, creating
+ /// a new list if <paramref name="list"/> is null. The list is returned - either
+ /// the original reference or the new list.
+ /// </summary>
+ private static List<T> Add<T>(List<T> list, T value) {
+ if (list == null) {
+ list = new List<T>();
+ }
+ list.Add(value);
+ return list;
+ }
+
+ /// <summary>
+ /// Returns a read-only version of the given IList, and clears
+ /// the field used for <paramref name="list"/>. If the value
+ /// is null, an empty list is produced using Lists.Empty.
+ /// </summary>
+ /// <returns></returns>
+ private static ReadOnlyCollection<T> MakeReadOnly<T>(ref List<T> list) {
+ ReadOnlyCollection<T> ret = list == null ? Lists<T>.Empty : new ReadOnlyCollection<T>(list);
+ list = null;
+ return ret;
+ }
+ }
+ }
+}
diff --git a/src/ProtocolBuffers/UnknownFieldSet.cs b/src/ProtocolBuffers/UnknownFieldSet.cs
index 594ae8bd..be773e41 100644
--- a/src/ProtocolBuffers/UnknownFieldSet.cs
+++ b/src/ProtocolBuffers/UnknownFieldSet.cs
@@ -1,768 +1,768 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://github.com/jskeet/dotnet-protobufs/
-// Original C++/Java/Python code:
-// http://code.google.com/p/protobuf/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using Google.ProtocolBuffers.Collections;
-using Google.ProtocolBuffers.Descriptors;
-using Google.ProtocolBuffers.DescriptorProtos;
-
-namespace Google.ProtocolBuffers {
- /// <summary>
- /// Used to keep track of fields which were seen when parsing a protocol message
- /// but whose field numbers or types are unrecognized. This most frequently
- /// occurs when new fields are added to a message type and then messages containing
- /// those fields are read by old software that was built before the new types were
- /// added.
- ///
- /// Every message contains an UnknownFieldSet.
- ///
- /// Most users will never need to use this class directly.
- /// </summary>
- public sealed class UnknownFieldSet : IMessageLite {
-
- private static readonly UnknownFieldSet defaultInstance = new UnknownFieldSet(new Dictionary<int, UnknownField>());
-
- private readonly IDictionary<int, UnknownField> fields;
-
- private UnknownFieldSet(IDictionary<int, UnknownField> fields) {
- this.fields = fields;
- }
-
- /// <summary>
- /// Creates a new unknown field set builder.
- /// </summary>
- public static Builder CreateBuilder() {
- return new Builder();
- }
-
- /// <summary>
- /// Creates a new unknown field set builder
- /// and initialize it from <paramref name="original"/>.
- /// </summary>
- public static Builder CreateBuilder(UnknownFieldSet original) {
- return new Builder().MergeFrom(original);
- }
-
- public static UnknownFieldSet DefaultInstance {
- get { return defaultInstance; }
- }
-
- /// <summary>
- /// Returns a read-only view of the mapping from field numbers to values.
- /// </summary>
- public IDictionary<int, UnknownField> FieldDictionary {
- get { return Dictionaries.AsReadOnly(fields); }
- }
-
- /// <summary>
- /// Checks whether or not the given field number is present in the set.
- /// </summary>
- public bool HasField(int field) {
- return fields.ContainsKey(field);
- }
-
- /// <summary>
- /// Fetches a field by number, returning an empty field if not present.
- /// Never returns null.
- /// </summary>
- public UnknownField this[int number] {
- get {
- UnknownField ret;
- if (!fields.TryGetValue(number, out ret)) {
- ret = UnknownField.DefaultInstance;
- }
- return ret;
- }
- }
-
- /// <summary>
- /// Serializes the set and writes it to <paramref name="output"/>.
- /// </summary>
- public void WriteTo(CodedOutputStream output) {
- foreach (KeyValuePair<int, UnknownField> entry in fields) {
- entry.Value.WriteTo(entry.Key, output);
- }
- }
-
- /// <summary>
- /// Gets the number of bytes required to encode this set.
- /// </summary>
- public int SerializedSize {
- get {
- int result = 0;
- foreach (KeyValuePair<int, UnknownField> entry in fields) {
- result += entry.Value.GetSerializedSize(entry.Key);
- }
- return result;
- }
- }
-
- /// <summary>
- /// Converts the set to a string in protocol buffer text format. This
- /// is just a trivial wrapper around TextFormat.PrintToString.
- /// </summary>
- public override String ToString() {
- return TextFormat.PrintToString(this);
- }
-
- /// <summary>
- /// Converts the set to a string in protocol buffer text format. This
- /// is just a trivial wrapper around TextFormat.PrintToString.
- /// </summary>
- public void PrintTo(TextWriter writer) {
- TextFormat.Print(this, writer);
- }
-
- /// <summary>
- /// Serializes the message to a ByteString and returns it. This is
- /// just a trivial wrapper around WriteTo(CodedOutputStream).
- /// </summary>
- /// <returns></returns>
- public ByteString ToByteString() {
- ByteString.CodedBuilder codedBuilder = new ByteString.CodedBuilder(SerializedSize);
- WriteTo(codedBuilder.CodedOutput);
- return codedBuilder.Build();
- }
-
- /// <summary>
- /// Serializes the message to a byte array and returns it. This is
- /// just a trivial wrapper around WriteTo(CodedOutputStream).
- /// </summary>
- /// <returns></returns>
- public byte[] ToByteArray() {
- byte[] data = new byte[SerializedSize];
- CodedOutputStream output = CodedOutputStream.CreateInstance(data);
- WriteTo(output);
- output.CheckNoSpaceLeft();
- return data;
- }
-
- /// <summary>
- /// Serializes the message and writes it to <paramref name="output"/>. This is
- /// just a trivial wrapper around WriteTo(CodedOutputStream).
- /// </summary>
- /// <param name="output"></param>
- public void WriteTo(Stream output) {
- CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
- WriteTo(codedOutput);
- codedOutput.Flush();
- }
-
- /// <summary>
- /// Serializes the set and writes it to <paramref name="output"/> using
- /// the MessageSet wire format.
- /// </summary>
- public void WriteAsMessageSetTo(CodedOutputStream output) {
- foreach (KeyValuePair<int, UnknownField> entry in fields) {
- entry.Value.WriteAsMessageSetExtensionTo(entry.Key, output);
- }
- }
-
- /// <summary>
- /// Gets the number of bytes required to encode this set using the MessageSet
- /// wire format.
- /// </summary>
- public int SerializedSizeAsMessageSet {
- get {
- int result = 0;
- foreach (KeyValuePair<int, UnknownField> entry in fields) {
- result += entry.Value.GetSerializedSizeAsMessageSetExtension(entry.Key);
- }
- return result;
- }
- }
-
- public override bool Equals(object other) {
- if (ReferenceEquals(this, other)) {
- return true;
- }
- UnknownFieldSet otherSet = other as UnknownFieldSet;
- return otherSet != null && Dictionaries.Equals(fields, otherSet.fields);
- }
-
- public override int GetHashCode() {
- return Dictionaries.GetHashCode(fields);
- }
-
- /// <summary>
- /// Parses an UnknownFieldSet from the given input.
- /// </summary>
- public static UnknownFieldSet ParseFrom(CodedInputStream input) {
- return CreateBuilder().MergeFrom(input).Build();
- }
-
- /// <summary>
- /// Parses an UnknownFieldSet from the given data.
- /// </summary>
- public static UnknownFieldSet ParseFrom(ByteString data) {
- return CreateBuilder().MergeFrom(data).Build();
- }
-
- /// <summary>
- /// Parses an UnknownFieldSet from the given data.
- /// </summary>
- public static UnknownFieldSet ParseFrom(byte[] data) {
- return CreateBuilder().MergeFrom(data).Build();
- }
-
- /// <summary>
- /// Parses an UnknownFieldSet from the given input.
- /// </summary>
- public static UnknownFieldSet ParseFrom(Stream input) {
- return CreateBuilder().MergeFrom(input).Build();
- }
-
- #region IMessageLite Members
-
- public bool IsInitialized {
- get { return fields != null; }
- }
-
- public void WriteDelimitedTo(Stream output) {
- CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
- codedOutput.WriteRawVarint32((uint) SerializedSize);
- WriteTo(codedOutput);
- codedOutput.Flush();
- }
-
- public IBuilderLite WeakCreateBuilderForType() {
- return new Builder();
- }
-
- public IBuilderLite WeakToBuilder() {
- return new Builder(fields);
- }
-
- public IMessageLite WeakDefaultInstanceForType {
- get { return defaultInstance; }
- }
-
- #endregion
-
- /// <summary>
- /// Builder for UnknownFieldSets.
- /// </summary>
- public sealed class Builder : IBuilderLite
- {
- /// <summary>
- /// Mapping from number to field. Note that by using a SortedList we ensure
- /// that the fields will be serialized in ascending order.
- /// </summary>
- private IDictionary<int, UnknownField> fields;
- // Optimization: We keep around a builder for the last field that was
- // modified so that we can efficiently add to it multiple times in a
- // row (important when parsing an unknown repeated field).
- private int lastFieldNumber;
- private UnknownField.Builder lastField;
-
- internal Builder() {
- fields = new SortedList<int, UnknownField>();
- }
-
- internal Builder(IDictionary<int, UnknownField> dictionary) {
- fields = new SortedList<int, UnknownField>(dictionary);
- }
-
- /// <summary>
- /// Returns a field builder for the specified field number, including any values
- /// which already exist.
- /// </summary>
- private UnknownField.Builder GetFieldBuilder(int number) {
- if (lastField != null) {
- if (number == lastFieldNumber) {
- return lastField;
- }
- // Note: AddField() will reset lastField and lastFieldNumber.
- AddField(lastFieldNumber, lastField.Build());
- }
- if (number == 0) {
- return null;
- }
-
- lastField = UnknownField.CreateBuilder();
- UnknownField existing;
- if (fields.TryGetValue(number, out existing)) {
- lastField.MergeFrom(existing);
- }
- lastFieldNumber = number;
- return lastField;
- }
-
- /// <summary>
- /// Build the UnknownFieldSet and return it. Once this method has been called,
- /// this instance will no longer be usable. Calling any method after this
- /// will throw a NullReferenceException.
- /// </summary>
- public UnknownFieldSet Build() {
- GetFieldBuilder(0); // Force lastField to be built.
- UnknownFieldSet result = fields.Count == 0 ? DefaultInstance : new UnknownFieldSet(fields);
- fields = null;
- return result;
- }
-
- /// <summary>
- /// Adds a field to the set. If a field with the same number already exists, it
- /// is replaced.
- /// </summary>
- public Builder AddField(int number, UnknownField field) {
- if (number == 0) {
- throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
- }
- if (lastField != null && lastFieldNumber == number) {
- // Discard this.
- lastField = null;
- lastFieldNumber = 0;
- }
- fields[number] = field;
- return this;
- }
-
- /// <summary>
- /// Resets the builder to an empty set.
- /// </summary>
- public Builder Clear() {
- fields.Clear();
- lastFieldNumber = 0;
- lastField = null;
- return this;
- }
-
- /// <summary>
- /// Parse an entire message from <paramref name="input"/> and merge
- /// its fields into this set.
- /// </summary>
- public Builder MergeFrom(CodedInputStream input) {
- while (true) {
- uint tag = input.ReadTag();
- if (tag == 0 || !MergeFieldFrom(tag, input)) {
- break;
- }
- }
- return this;
- }
-
- /// <summary>
- /// Parse a single field from <paramref name="input"/> and merge it
- /// into this set.
- /// </summary>
- /// <param name="tag">The field's tag number, which was already parsed.</param>
- /// <param name="input">The coded input stream containing the field</param>
- /// <returns>false if the tag is an "end group" tag, true otherwise</returns>
- [CLSCompliant(false)]
- public bool MergeFieldFrom(uint tag, CodedInputStream input) {
- int number = WireFormat.GetTagFieldNumber(tag);
- switch (WireFormat.GetTagWireType(tag)) {
- case WireFormat.WireType.Varint:
- GetFieldBuilder(number).AddVarint(input.ReadUInt64());
- return true;
- case WireFormat.WireType.Fixed64:
- GetFieldBuilder(number).AddFixed64(input.ReadFixed64());
- return true;
- case WireFormat.WireType.LengthDelimited:
- GetFieldBuilder(number).AddLengthDelimited(input.ReadBytes());
- return true;
- case WireFormat.WireType.StartGroup: {
- Builder subBuilder = CreateBuilder();
-#pragma warning disable 0612
- input.ReadUnknownGroup(number, subBuilder);
-#pragma warning restore 0612
- GetFieldBuilder(number).AddGroup(subBuilder.Build());
- return true;
- }
- case WireFormat.WireType.EndGroup:
- return false;
- case WireFormat.WireType.Fixed32:
- GetFieldBuilder(number).AddFixed32(input.ReadFixed32());
- return true;
- default:
- throw InvalidProtocolBufferException.InvalidWireType();
- }
- }
-
- /// <summary>
- /// Parses <paramref name="input"/> as an UnknownFieldSet and merge it
- /// with the set being built. This is just a small wrapper around
- /// MergeFrom(CodedInputStream).
- /// </summary>
- public Builder MergeFrom(Stream input) {
- CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
- MergeFrom(codedInput);
- codedInput.CheckLastTagWas(0);
- return this;
- }
-
- /// <summary>
- /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
- /// with the set being built. This is just a small wrapper around
- /// MergeFrom(CodedInputStream).
- /// </summary>
- public Builder MergeFrom(ByteString data) {
- CodedInputStream input = data.CreateCodedInput();
- MergeFrom(input);
- input.CheckLastTagWas(0);
- return this;
- }
-
- /// <summary>
- /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
- /// with the set being built. This is just a small wrapper around
- /// MergeFrom(CodedInputStream).
- /// </summary>
- public Builder MergeFrom(byte[] data) {
- CodedInputStream input = CodedInputStream.CreateInstance(data);
- MergeFrom(input);
- input.CheckLastTagWas(0);
- return this;
- }
-
- /// <summary>
- /// Convenience method for merging a new field containing a single varint
- /// value. This is used in particular when an unknown enum value is
- /// encountered.
- /// </summary>
- [CLSCompliant(false)]
- public Builder MergeVarintField(int number, ulong value) {
- if (number == 0) {
- throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
- }
- GetFieldBuilder(number).AddVarint(value);
- return this;
- }
-
- /// <summary>
- /// Merges the fields from <paramref name="other"/> into this set.
- /// If a field number exists in both sets, the values in <paramref name="other"/>
- /// will be appended to the values in this set.
- /// </summary>
- public Builder MergeFrom(UnknownFieldSet other) {
- if (other != DefaultInstance) {
- foreach(KeyValuePair<int, UnknownField> entry in other.fields) {
- MergeField(entry.Key, entry.Value);
- }
- }
- return this;
- }
-
- /// <summary>
- /// Checks if the given field number is present in the set.
- /// </summary>
- public bool HasField(int number) {
- if (number == 0) {
- throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
- }
- return number == lastFieldNumber || fields.ContainsKey(number);
- }
-
- /// <summary>
- /// Adds a field to the unknown field set. If a field with the same
- /// number already exists, the two are merged.
- /// </summary>
- public Builder MergeField(int number, UnknownField field) {
- if (number == 0) {
- throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
- }
- if (HasField(number)) {
- GetFieldBuilder(number).MergeFrom(field);
- } else {
- // Optimization: We could call getFieldBuilder(number).mergeFrom(field)
- // in this case, but that would create a copy of the Field object.
- // We'd rather reuse the one passed to us, so call AddField() instead.
- AddField(number, field);
- }
- return this;
- }
-
- internal void MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder) {
- while (true) {
- uint tag = input.ReadTag();
- if (tag == 0) {
- break;
- }
-
- if (!MergeFieldFrom(input, extensionRegistry, builder, tag)) {
- // end group tag
- break;
- }
- }
- }
-
- /// <summary>
- /// Like <see cref="MergeFrom(CodedInputStream, ExtensionRegistry, IBuilder)" />
- /// but parses a single field.
- /// </summary>
- /// <param name="input">The input to read the field from</param>
- /// <param name="extensionRegistry">Registry to use when an extension field is encountered</param>
- /// <param name="builder">Builder to merge field into, if it's a known field</param>
- /// <param name="tag">The tag, which should already have been read from the input</param>
- /// <returns>true unless the tag is an end-group tag</returns>
- internal bool MergeFieldFrom(CodedInputStream input,
- ExtensionRegistry extensionRegistry, IBuilder builder, uint tag) {
-
- MessageDescriptor type = builder.DescriptorForType;
- if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart) {
- MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder);
- return true;
- }
-
- WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
- int fieldNumber = WireFormat.GetTagFieldNumber(tag);
-
- FieldDescriptor field;
- IMessageLite defaultFieldInstance = null;
-
- if (type.IsExtensionNumber(fieldNumber)) {
- ExtensionInfo extension = extensionRegistry[type, fieldNumber];
- if (extension == null) {
- field = null;
- } else {
- field = extension.Descriptor;
- defaultFieldInstance = extension.DefaultInstance;
- }
- } else {
- field = type.FindFieldByNumber(fieldNumber);
- }
-
- // Unknown field or wrong wire type. Skip.
- if (field == null || wireType != WireFormat.GetWireType(field)) {
- return MergeFieldFrom(tag, input);
- }
-
- if (field.IsPacked) {
- int length = (int)input.ReadRawVarint32();
- int limit = input.PushLimit(length);
- if (field.FieldType == FieldType.Enum) {
- while (!input.ReachedLimit) {
- int rawValue = input.ReadEnum();
- object value = field.EnumType.FindValueByNumber(rawValue);
- if (value == null) {
- // If the number isn't recognized as a valid value for this
- // enum, drop it (don't even add it to unknownFields).
- return true;
- }
- builder.WeakAddRepeatedField(field, value);
- }
- } else {
- while (!input.ReachedLimit) {
- Object value = input.ReadPrimitiveField(field.FieldType);
- builder.WeakAddRepeatedField(field, value);
- }
- }
- input.PopLimit(limit);
- } else {
- object value;
- switch (field.FieldType) {
- case FieldType.Group:
- case FieldType.Message: {
- IBuilderLite subBuilder;
- if (defaultFieldInstance != null) {
- subBuilder = defaultFieldInstance.WeakCreateBuilderForType();
- } else {
- subBuilder = builder.CreateBuilderForField(field);
- }
- if (!field.IsRepeated) {
- subBuilder.WeakMergeFrom((IMessageLite)builder[field]);
- }
- if (field.FieldType == FieldType.Group) {
- input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
- } else {
- input.ReadMessage(subBuilder, extensionRegistry);
- }
- value = subBuilder.WeakBuild();
- break;
- }
- case FieldType.Enum: {
- int rawValue = input.ReadEnum();
- value = field.EnumType.FindValueByNumber(rawValue);
- // If the number isn't recognized as a valid value for this enum,
- // drop it.
- if (value == null) {
- MergeVarintField(fieldNumber, (ulong)rawValue);
- return true;
- }
- break;
- }
- default:
- value = input.ReadPrimitiveField(field.FieldType);
- break;
- }
- if (field.IsRepeated) {
- builder.WeakAddRepeatedField(field, value);
- } else {
- builder[field] = value;
- }
- }
- return true;
- }
-
- /// <summary>
- /// Called by MergeFieldFrom to parse a MessageSet extension.
- /// </summary>
- private void MergeMessageSetExtensionFromCodedStream(CodedInputStream input,
- ExtensionRegistry extensionRegistry, IBuilder builder) {
- MessageDescriptor type = builder.DescriptorForType;
-
- // The wire format for MessageSet is:
- // message MessageSet {
- // repeated group Item = 1 {
- // required int32 typeId = 2;
- // required bytes message = 3;
- // }
- // }
- // "typeId" is the extension's field number. The extension can only be
- // a message type, where "message" contains the encoded bytes of that
- // message.
- //
- // In practice, we will probably never see a MessageSet item in which
- // the message appears before the type ID, or where either field does not
- // appear exactly once. However, in theory such cases are valid, so we
- // should be prepared to accept them.
-
- int typeId = 0;
- ByteString rawBytes = null; // If we encounter "message" before "typeId"
- IBuilderLite subBuilder = null;
- FieldDescriptor field = null;
-
- while (true) {
- uint tag = input.ReadTag();
- if (tag == 0) {
- break;
- }
-
- if (tag == WireFormat.MessageSetTag.TypeID) {
- typeId = input.ReadInt32();
- // Zero is not a valid type ID.
- if (typeId != 0) {
- ExtensionInfo extension = extensionRegistry[type, typeId];
- if (extension != null) {
- field = extension.Descriptor;
- subBuilder = extension.DefaultInstance.WeakCreateBuilderForType();
- IMessageLite originalMessage = (IMessageLite)builder[field];
- if (originalMessage != null) {
- subBuilder.WeakMergeFrom(originalMessage);
- }
- if (rawBytes != null) {
- // We already encountered the message. Parse it now.
- // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
- // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
- subBuilder.WeakMergeFrom(rawBytes.CreateCodedInput());
- rawBytes = null;
- }
- } else {
- // Unknown extension number. If we already saw data, put it
- // in rawBytes.
- if (rawBytes != null) {
- MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
- rawBytes = null;
- }
- }
- }
- } else if (tag == WireFormat.MessageSetTag.Message) {
- if (typeId == 0) {
- // We haven't seen a type ID yet, so we have to store the raw bytes for now.
- rawBytes = input.ReadBytes();
- } else if (subBuilder == null) {
- // We don't know how to parse this. Ignore it.
- MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(input.ReadBytes()).Build());
- } else {
- // We already know the type, so we can parse directly from the input
- // with no copying. Hooray!
- input.ReadMessage(subBuilder, extensionRegistry);
- }
- } else {
- // Unknown tag. Skip it.
- if (!input.SkipField(tag)) {
- break; // end of group
- }
- }
- }
-
- input.CheckLastTagWas(WireFormat.MessageSetTag.ItemEnd);
-
- if (subBuilder != null) {
- builder[field] = subBuilder.WeakBuild();
- }
- }
-
- #region IBuilderLite Members
-
- bool IBuilderLite.IsInitialized {
- get { return fields != null; }
- }
-
- IBuilderLite IBuilderLite.WeakClear() {
- return Clear();
- }
-
- IBuilderLite IBuilderLite.WeakMergeFrom(IMessageLite message) {
- return MergeFrom((UnknownFieldSet)message);
- }
-
- IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data) {
- return MergeFrom(data);
- }
-
- IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data, ExtensionRegistry registry) {
- return MergeFrom(data);
- }
-
- IBuilderLite IBuilderLite.WeakMergeFrom(CodedInputStream input) {
- return MergeFrom(input);
- }
-
- IBuilderLite IBuilderLite.WeakMergeFrom(CodedInputStream input, ExtensionRegistry registry) {
- return MergeFrom(input);
- }
-
- IMessageLite IBuilderLite.WeakBuild() {
- return Build();
- }
-
- IMessageLite IBuilderLite.WeakBuildPartial() {
- return Build();
- }
-
- IBuilderLite IBuilderLite.WeakClone() {
- return Build().WeakToBuilder();
- }
-
- IMessageLite IBuilderLite.WeakDefaultInstanceForType {
- get { return DefaultInstance; }
- }
-
- #endregion
- }
- }
-}
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Google.ProtocolBuffers.Collections;
+using Google.ProtocolBuffers.Descriptors;
+using Google.ProtocolBuffers.DescriptorProtos;
+
+namespace Google.ProtocolBuffers {
+ /// <summary>
+ /// Used to keep track of fields which were seen when parsing a protocol message
+ /// but whose field numbers or types are unrecognized. This most frequently
+ /// occurs when new fields are added to a message type and then messages containing
+ /// those fields are read by old software that was built before the new types were
+ /// added.
+ ///
+ /// Every message contains an UnknownFieldSet.
+ ///
+ /// Most users will never need to use this class directly.
+ /// </summary>
+ public sealed class UnknownFieldSet : IMessageLite {
+
+ private static readonly UnknownFieldSet defaultInstance = new UnknownFieldSet(new Dictionary<int, UnknownField>());
+
+ private readonly IDictionary<int, UnknownField> fields;
+
+ private UnknownFieldSet(IDictionary<int, UnknownField> fields) {
+ this.fields = fields;
+ }
+
+ /// <summary>
+ /// Creates a new unknown field set builder.
+ /// </summary>
+ public static Builder CreateBuilder() {
+ return new Builder();
+ }
+
+ /// <summary>
+ /// Creates a new unknown field set builder
+ /// and initialize it from <paramref name="original"/>.
+ /// </summary>
+ public static Builder CreateBuilder(UnknownFieldSet original) {
+ return new Builder().MergeFrom(original);
+ }
+
+ public static UnknownFieldSet DefaultInstance {
+ get { return defaultInstance; }
+ }
+
+ /// <summary>
+ /// Returns a read-only view of the mapping from field numbers to values.
+ /// </summary>
+ public IDictionary<int, UnknownField> FieldDictionary {
+ get { return Dictionaries.AsReadOnly(fields); }
+ }
+
+ /// <summary>
+ /// Checks whether or not the given field number is present in the set.
+ /// </summary>
+ public bool HasField(int field) {
+ return fields.ContainsKey(field);
+ }
+
+ /// <summary>
+ /// Fetches a field by number, returning an empty field if not present.
+ /// Never returns null.
+ /// </summary>
+ public UnknownField this[int number] {
+ get {
+ UnknownField ret;
+ if (!fields.TryGetValue(number, out ret)) {
+ ret = UnknownField.DefaultInstance;
+ }
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Serializes the set and writes it to <paramref name="output"/>.
+ /// </summary>
+ public void WriteTo(CodedOutputStream output) {
+ foreach (KeyValuePair<int, UnknownField> entry in fields) {
+ entry.Value.WriteTo(entry.Key, output);
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of bytes required to encode this set.
+ /// </summary>
+ public int SerializedSize {
+ get {
+ int result = 0;
+ foreach (KeyValuePair<int, UnknownField> entry in fields) {
+ result += entry.Value.GetSerializedSize(entry.Key);
+ }
+ return result;
+ }
+ }
+
+ /// <summary>
+ /// Converts the set to a string in protocol buffer text format. This
+ /// is just a trivial wrapper around TextFormat.PrintToString.
+ /// </summary>
+ public override String ToString() {
+ return TextFormat.PrintToString(this);
+ }
+
+ /// <summary>
+ /// Converts the set to a string in protocol buffer text format. This
+ /// is just a trivial wrapper around TextFormat.PrintToString.
+ /// </summary>
+ public void PrintTo(TextWriter writer) {
+ TextFormat.Print(this, writer);
+ }
+
+ /// <summary>
+ /// Serializes the message to a ByteString and returns it. This is
+ /// just a trivial wrapper around WriteTo(CodedOutputStream).
+ /// </summary>
+ /// <returns></returns>
+ public ByteString ToByteString() {
+ ByteString.CodedBuilder codedBuilder = new ByteString.CodedBuilder(SerializedSize);
+ WriteTo(codedBuilder.CodedOutput);
+ return codedBuilder.Build();
+ }
+
+ /// <summary>
+ /// Serializes the message to a byte array and returns it. This is
+ /// just a trivial wrapper around WriteTo(CodedOutputStream).
+ /// </summary>
+ /// <returns></returns>
+ public byte[] ToByteArray() {
+ byte[] data = new byte[SerializedSize];
+ CodedOutputStream output = CodedOutputStream.CreateInstance(data);
+ WriteTo(output);
+ output.CheckNoSpaceLeft();
+ return data;
+ }
+
+ /// <summary>
+ /// Serializes the message and writes it to <paramref name="output"/>. This is
+ /// just a trivial wrapper around WriteTo(CodedOutputStream).
+ /// </summary>
+ /// <param name="output"></param>
+ public void WriteTo(Stream output) {
+ CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
+ WriteTo(codedOutput);
+ codedOutput.Flush();
+ }
+
+ /// <summary>
+ /// Serializes the set and writes it to <paramref name="output"/> using
+ /// the MessageSet wire format.
+ /// </summary>
+ public void WriteAsMessageSetTo(CodedOutputStream output) {
+ foreach (KeyValuePair<int, UnknownField> entry in fields) {
+ entry.Value.WriteAsMessageSetExtensionTo(entry.Key, output);
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of bytes required to encode this set using the MessageSet
+ /// wire format.
+ /// </summary>
+ public int SerializedSizeAsMessageSet {
+ get {
+ int result = 0;
+ foreach (KeyValuePair<int, UnknownField> entry in fields) {
+ result += entry.Value.GetSerializedSizeAsMessageSetExtension(entry.Key);
+ }
+ return result;
+ }
+ }
+
+ public override bool Equals(object other) {
+ if (ReferenceEquals(this, other)) {
+ return true;
+ }
+ UnknownFieldSet otherSet = other as UnknownFieldSet;
+ return otherSet != null && Dictionaries.Equals(fields, otherSet.fields);
+ }
+
+ public override int GetHashCode() {
+ return Dictionaries.GetHashCode(fields);
+ }
+
+ /// <summary>
+ /// Parses an UnknownFieldSet from the given input.
+ /// </summary>
+ public static UnknownFieldSet ParseFrom(CodedInputStream input) {
+ return CreateBuilder().MergeFrom(input).Build();
+ }
+
+ /// <summary>
+ /// Parses an UnknownFieldSet from the given data.
+ /// </summary>
+ public static UnknownFieldSet ParseFrom(ByteString data) {
+ return CreateBuilder().MergeFrom(data).Build();
+ }
+
+ /// <summary>
+ /// Parses an UnknownFieldSet from the given data.
+ /// </summary>
+ public static UnknownFieldSet ParseFrom(byte[] data) {
+ return CreateBuilder().MergeFrom(data).Build();
+ }
+
+ /// <summary>
+ /// Parses an UnknownFieldSet from the given input.
+ /// </summary>
+ public static UnknownFieldSet ParseFrom(Stream input) {
+ return CreateBuilder().MergeFrom(input).Build();
+ }
+
+ #region IMessageLite Members
+
+ public bool IsInitialized {
+ get { return fields != null; }
+ }
+
+ public void WriteDelimitedTo(Stream output) {
+ CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
+ codedOutput.WriteRawVarint32((uint) SerializedSize);
+ WriteTo(codedOutput);
+ codedOutput.Flush();
+ }
+
+ public IBuilderLite WeakCreateBuilderForType() {
+ return new Builder();
+ }
+
+ public IBuilderLite WeakToBuilder() {
+ return new Builder(fields);
+ }
+
+ public IMessageLite WeakDefaultInstanceForType {
+ get { return defaultInstance; }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Builder for UnknownFieldSets.
+ /// </summary>
+ public sealed class Builder : IBuilderLite
+ {
+ /// <summary>
+ /// Mapping from number to field. Note that by using a SortedList we ensure
+ /// that the fields will be serialized in ascending order.
+ /// </summary>
+ private IDictionary<int, UnknownField> fields;
+ // Optimization: We keep around a builder for the last field that was
+ // modified so that we can efficiently add to it multiple times in a
+ // row (important when parsing an unknown repeated field).
+ private int lastFieldNumber;
+ private UnknownField.Builder lastField;
+
+ internal Builder() {
+ fields = new SortedList<int, UnknownField>();
+ }
+
+ internal Builder(IDictionary<int, UnknownField> dictionary) {
+ fields = new SortedList<int, UnknownField>(dictionary);
+ }
+
+ /// <summary>
+ /// Returns a field builder for the specified field number, including any values
+ /// which already exist.
+ /// </summary>
+ private UnknownField.Builder GetFieldBuilder(int number) {
+ if (lastField != null) {
+ if (number == lastFieldNumber) {
+ return lastField;
+ }
+ // Note: AddField() will reset lastField and lastFieldNumber.
+ AddField(lastFieldNumber, lastField.Build());
+ }
+ if (number == 0) {
+ return null;
+ }
+
+ lastField = UnknownField.CreateBuilder();
+ UnknownField existing;
+ if (fields.TryGetValue(number, out existing)) {
+ lastField.MergeFrom(existing);
+ }
+ lastFieldNumber = number;
+ return lastField;
+ }
+
+ /// <summary>
+ /// Build the UnknownFieldSet and return it. Once this method has been called,
+ /// this instance will no longer be usable. Calling any method after this
+ /// will throw a NullReferenceException.
+ /// </summary>
+ public UnknownFieldSet Build() {
+ GetFieldBuilder(0); // Force lastField to be built.
+ UnknownFieldSet result = fields.Count == 0 ? DefaultInstance : new UnknownFieldSet(fields);
+ fields = null;
+ return result;
+ }
+
+ /// <summary>
+ /// Adds a field to the set. If a field with the same number already exists, it
+ /// is replaced.
+ /// </summary>
+ public Builder AddField(int number, UnknownField field) {
+ if (number == 0) {
+ throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
+ }
+ if (lastField != null && lastFieldNumber == number) {
+ // Discard this.
+ lastField = null;
+ lastFieldNumber = 0;
+ }
+ fields[number] = field;
+ return this;
+ }
+
+ /// <summary>
+ /// Resets the builder to an empty set.
+ /// </summary>
+ public Builder Clear() {
+ fields.Clear();
+ lastFieldNumber = 0;
+ lastField = null;
+ return this;
+ }
+
+ /// <summary>
+ /// Parse an entire message from <paramref name="input"/> and merge
+ /// its fields into this set.
+ /// </summary>
+ public Builder MergeFrom(CodedInputStream input) {
+ while (true) {
+ uint tag = input.ReadTag();
+ if (tag == 0 || !MergeFieldFrom(tag, input)) {
+ break;
+ }
+ }
+ return this;
+ }
+
+ /// <summary>
+ /// Parse a single field from <paramref name="input"/> and merge it
+ /// into this set.
+ /// </summary>
+ /// <param name="tag">The field's tag number, which was already parsed.</param>
+ /// <param name="input">The coded input stream containing the field</param>
+ /// <returns>false if the tag is an "end group" tag, true otherwise</returns>
+ [CLSCompliant(false)]
+ public bool MergeFieldFrom(uint tag, CodedInputStream input) {
+ int number = WireFormat.GetTagFieldNumber(tag);
+ switch (WireFormat.GetTagWireType(tag)) {
+ case WireFormat.WireType.Varint:
+ GetFieldBuilder(number).AddVarint(input.ReadUInt64());
+ return true;
+ case WireFormat.WireType.Fixed64:
+ GetFieldBuilder(number).AddFixed64(input.ReadFixed64());
+ return true;
+ case WireFormat.WireType.LengthDelimited:
+ GetFieldBuilder(number).AddLengthDelimited(input.ReadBytes());
+ return true;
+ case WireFormat.WireType.StartGroup: {
+ Builder subBuilder = CreateBuilder();
+#pragma warning disable 0612
+ input.ReadUnknownGroup(number, subBuilder);
+#pragma warning restore 0612
+ GetFieldBuilder(number).AddGroup(subBuilder.Build());
+ return true;
+ }
+ case WireFormat.WireType.EndGroup:
+ return false;
+ case WireFormat.WireType.Fixed32:
+ GetFieldBuilder(number).AddFixed32(input.ReadFixed32());
+ return true;
+ default:
+ throw InvalidProtocolBufferException.InvalidWireType();
+ }
+ }
+
+ /// <summary>
+ /// Parses <paramref name="input"/> as an UnknownFieldSet and merge it
+ /// with the set being built. This is just a small wrapper around
+ /// MergeFrom(CodedInputStream).
+ /// </summary>
+ public Builder MergeFrom(Stream input) {
+ CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
+ MergeFrom(codedInput);
+ codedInput.CheckLastTagWas(0);
+ return this;
+ }
+
+ /// <summary>
+ /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
+ /// with the set being built. This is just a small wrapper around
+ /// MergeFrom(CodedInputStream).
+ /// </summary>
+ public Builder MergeFrom(ByteString data) {
+ CodedInputStream input = data.CreateCodedInput();
+ MergeFrom(input);
+ input.CheckLastTagWas(0);
+ return this;
+ }
+
+ /// <summary>
+ /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
+ /// with the set being built. This is just a small wrapper around
+ /// MergeFrom(CodedInputStream).
+ /// </summary>
+ public Builder MergeFrom(byte[] data) {
+ CodedInputStream input = CodedInputStream.CreateInstance(data);
+ MergeFrom(input);
+ input.CheckLastTagWas(0);
+ return this;
+ }
+
+ /// <summary>
+ /// Convenience method for merging a new field containing a single varint
+ /// value. This is used in particular when an unknown enum value is
+ /// encountered.
+ /// </summary>
+ [CLSCompliant(false)]
+ public Builder MergeVarintField(int number, ulong value) {
+ if (number == 0) {
+ throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
+ }
+ GetFieldBuilder(number).AddVarint(value);
+ return this;
+ }
+
+ /// <summary>
+ /// Merges the fields from <paramref name="other"/> into this set.
+ /// If a field number exists in both sets, the values in <paramref name="other"/>
+ /// will be appended to the values in this set.
+ /// </summary>
+ public Builder MergeFrom(UnknownFieldSet other) {
+ if (other != DefaultInstance) {
+ foreach(KeyValuePair<int, UnknownField> entry in other.fields) {
+ MergeField(entry.Key, entry.Value);
+ }
+ }
+ return this;
+ }
+
+ /// <summary>
+ /// Checks if the given field number is present in the set.
+ /// </summary>
+ public bool HasField(int number) {
+ if (number == 0) {
+ throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
+ }
+ return number == lastFieldNumber || fields.ContainsKey(number);
+ }
+
+ /// <summary>
+ /// Adds a field to the unknown field set. If a field with the same
+ /// number already exists, the two are merged.
+ /// </summary>
+ public Builder MergeField(int number, UnknownField field) {
+ if (number == 0) {
+ throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
+ }
+ if (HasField(number)) {
+ GetFieldBuilder(number).MergeFrom(field);
+ } else {
+ // Optimization: We could call getFieldBuilder(number).mergeFrom(field)
+ // in this case, but that would create a copy of the Field object.
+ // We'd rather reuse the one passed to us, so call AddField() instead.
+ AddField(number, field);
+ }
+ return this;
+ }
+
+ internal void MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder) {
+ while (true) {
+ uint tag = input.ReadTag();
+ if (tag == 0) {
+ break;
+ }
+
+ if (!MergeFieldFrom(input, extensionRegistry, builder, tag)) {
+ // end group tag
+ break;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Like <see cref="MergeFrom(CodedInputStream, ExtensionRegistry, IBuilder)" />
+ /// but parses a single field.
+ /// </summary>
+ /// <param name="input">The input to read the field from</param>
+ /// <param name="extensionRegistry">Registry to use when an extension field is encountered</param>
+ /// <param name="builder">Builder to merge field into, if it's a known field</param>
+ /// <param name="tag">The tag, which should already have been read from the input</param>
+ /// <returns>true unless the tag is an end-group tag</returns>
+ internal bool MergeFieldFrom(CodedInputStream input,
+ ExtensionRegistry extensionRegistry, IBuilder builder, uint tag) {
+
+ MessageDescriptor type = builder.DescriptorForType;
+ if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart) {
+ MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder);
+ return true;
+ }
+
+ WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
+ int fieldNumber = WireFormat.GetTagFieldNumber(tag);
+
+ FieldDescriptor field;
+ IMessageLite defaultFieldInstance = null;
+
+ if (type.IsExtensionNumber(fieldNumber)) {
+ ExtensionInfo extension = extensionRegistry[type, fieldNumber];
+ if (extension == null) {
+ field = null;
+ } else {
+ field = extension.Descriptor;
+ defaultFieldInstance = extension.DefaultInstance;
+ }
+ } else {
+ field = type.FindFieldByNumber(fieldNumber);
+ }
+
+ // Unknown field or wrong wire type. Skip.
+ if (field == null || wireType != WireFormat.GetWireType(field)) {
+ return MergeFieldFrom(tag, input);
+ }
+
+ if (field.IsPacked) {
+ int length = (int)input.ReadRawVarint32();
+ int limit = input.PushLimit(length);
+ if (field.FieldType == FieldType.Enum) {
+ while (!input.ReachedLimit) {
+ int rawValue = input.ReadEnum();
+ object value = field.EnumType.FindValueByNumber(rawValue);
+ if (value == null) {
+ // If the number isn't recognized as a valid value for this
+ // enum, drop it (don't even add it to unknownFields).
+ return true;
+ }
+ builder.WeakAddRepeatedField(field, value);
+ }
+ } else {
+ while (!input.ReachedLimit) {
+ Object value = input.ReadPrimitiveField(field.FieldType);
+ builder.WeakAddRepeatedField(field, value);
+ }
+ }
+ input.PopLimit(limit);
+ } else {
+ object value;
+ switch (field.FieldType) {
+ case FieldType.Group:
+ case FieldType.Message: {
+ IBuilderLite subBuilder;
+ if (defaultFieldInstance != null) {
+ subBuilder = defaultFieldInstance.WeakCreateBuilderForType();
+ } else {
+ subBuilder = builder.CreateBuilderForField(field);
+ }
+ if (!field.IsRepeated) {
+ subBuilder.WeakMergeFrom((IMessageLite)builder[field]);
+ }
+ if (field.FieldType == FieldType.Group) {
+ input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
+ } else {
+ input.ReadMessage(subBuilder, extensionRegistry);
+ }
+ value = subBuilder.WeakBuild();
+ break;
+ }
+ case FieldType.Enum: {
+ int rawValue = input.ReadEnum();
+ value = field.EnumType.FindValueByNumber(rawValue);
+ // If the number isn't recognized as a valid value for this enum,
+ // drop it.
+ if (value == null) {
+ MergeVarintField(fieldNumber, (ulong)rawValue);
+ return true;
+ }
+ break;
+ }
+ default:
+ value = input.ReadPrimitiveField(field.FieldType);
+ break;
+ }
+ if (field.IsRepeated) {
+ builder.WeakAddRepeatedField(field, value);
+ } else {
+ builder[field] = value;
+ }
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Called by MergeFieldFrom to parse a MessageSet extension.
+ /// </summary>
+ private void MergeMessageSetExtensionFromCodedStream(CodedInputStream input,
+ ExtensionRegistry extensionRegistry, IBuilder builder) {
+ MessageDescriptor type = builder.DescriptorForType;
+
+ // The wire format for MessageSet is:
+ // message MessageSet {
+ // repeated group Item = 1 {
+ // required int32 typeId = 2;
+ // required bytes message = 3;
+ // }
+ // }
+ // "typeId" is the extension's field number. The extension can only be
+ // a message type, where "message" contains the encoded bytes of that
+ // message.
+ //
+ // In practice, we will probably never see a MessageSet item in which
+ // the message appears before the type ID, or where either field does not
+ // appear exactly once. However, in theory such cases are valid, so we
+ // should be prepared to accept them.
+
+ int typeId = 0;
+ ByteString rawBytes = null; // If we encounter "message" before "typeId"
+ IBuilderLite subBuilder = null;
+ FieldDescriptor field = null;
+
+ while (true) {
+ uint tag = input.ReadTag();
+ if (tag == 0) {
+ break;
+ }
+
+ if (tag == WireFormat.MessageSetTag.TypeID) {
+ typeId = input.ReadInt32();
+ // Zero is not a valid type ID.
+ if (typeId != 0) {
+ ExtensionInfo extension = extensionRegistry[type, typeId];
+ if (extension != null) {
+ field = extension.Descriptor;
+ subBuilder = extension.DefaultInstance.WeakCreateBuilderForType();
+ IMessageLite originalMessage = (IMessageLite)builder[field];
+ if (originalMessage != null) {
+ subBuilder.WeakMergeFrom(originalMessage);
+ }
+ if (rawBytes != null) {
+ // We already encountered the message. Parse it now.
+ // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
+ // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
+ subBuilder.WeakMergeFrom(rawBytes.CreateCodedInput());
+ rawBytes = null;
+ }
+ } else {
+ // Unknown extension number. If we already saw data, put it
+ // in rawBytes.
+ if (rawBytes != null) {
+ MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
+ rawBytes = null;
+ }
+ }
+ }
+ } else if (tag == WireFormat.MessageSetTag.Message) {
+ if (typeId == 0) {
+ // We haven't seen a type ID yet, so we have to store the raw bytes for now.
+ rawBytes = input.ReadBytes();
+ } else if (subBuilder == null) {
+ // We don't know how to parse this. Ignore it.
+ MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(input.ReadBytes()).Build());
+ } else {
+ // We already know the type, so we can parse directly from the input
+ // with no copying. Hooray!
+ input.ReadMessage(subBuilder, extensionRegistry);
+ }
+ } else {
+ // Unknown tag. Skip it.
+ if (!input.SkipField(tag)) {
+ break; // end of group
+ }
+ }
+ }
+
+ input.CheckLastTagWas(WireFormat.MessageSetTag.ItemEnd);
+
+ if (subBuilder != null) {
+ builder[field] = subBuilder.WeakBuild();
+ }
+ }
+
+ #region IBuilderLite Members
+
+ bool IBuilderLite.IsInitialized {
+ get { return fields != null; }
+ }
+
+ IBuilderLite IBuilderLite.WeakClear() {
+ return Clear();
+ }
+
+ IBuilderLite IBuilderLite.WeakMergeFrom(IMessageLite message) {
+ return MergeFrom((UnknownFieldSet)message);
+ }
+
+ IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data) {
+ return MergeFrom(data);
+ }
+
+ IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data, ExtensionRegistry registry) {
+ return MergeFrom(data);
+ }
+
+ IBuilderLite IBuilderLite.WeakMergeFrom(CodedInputStream input) {
+ return MergeFrom(input);
+ }
+
+ IBuilderLite IBuilderLite.WeakMergeFrom(CodedInputStream input, ExtensionRegistry registry) {
+ return MergeFrom(input);
+ }
+
+ IMessageLite IBuilderLite.WeakBuild() {
+ return Build();
+ }
+
+ IMessageLite IBuilderLite.WeakBuildPartial() {
+ return Build();
+ }
+
+ IBuilderLite IBuilderLite.WeakClone() {
+ return Build().WeakToBuilder();
+ }
+
+ IMessageLite IBuilderLite.WeakDefaultInstanceForType {
+ get { return DefaultInstance; }
+ }
+
+ #endregion
+ }
+ }
+}
diff --git a/src/ProtocolBuffers/WireFormat.cs b/src/ProtocolBuffers/WireFormat.cs
index b98d364c..953364ad 100644
--- a/src/ProtocolBuffers/WireFormat.cs
+++ b/src/ProtocolBuffers/WireFormat.cs
@@ -1,56 +1,56 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://github.com/jskeet/dotnet-protobufs/
-// Original C++/Java/Python code:
-// http://code.google.com/p/protobuf/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System;
-#if !LITE
-using Google.ProtocolBuffers.Descriptors;
-#endif
-
-namespace Google.ProtocolBuffers {
-
- /// <summary>
- /// This class is used internally by the Protocol Buffer Library and generated
- /// message implementations. It is public only for the sake of those generated
- /// messages. Others should not use this class directly.
- /// <para>
- /// This class contains constants and helper functions useful for dealing with
- /// the Protocol Buffer wire format.
- /// </para>
- /// </summary>
- public static class WireFormat {
-
-#region Fixed sizes.
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+#if !LITE
+using Google.ProtocolBuffers.Descriptors;
+#endif
+
+namespace Google.ProtocolBuffers {
+
+ /// <summary>
+ /// This class is used internally by the Protocol Buffer Library and generated
+ /// message implementations. It is public only for the sake of those generated
+ /// messages. Others should not use this class directly.
+ /// <para>
+ /// This class contains constants and helper functions useful for dealing with
+ /// the Protocol Buffer wire format.
+ /// </para>
+ /// </summary>
+ public static class WireFormat {
+
+#region Fixed sizes.
// TODO(jonskeet): Move these somewhere else. They're messy. Consider making FieldType a smarter kind of enum
public const int Fixed32Size = 4;
public const int Fixed64Size = 8;
@@ -58,121 +58,121 @@ namespace Google.ProtocolBuffers {
public const int SFixed64Size = 8;
public const int FloatSize = 4;
public const int DoubleSize = 8;
- public const int BoolSize = 1;
-#endregion
-
- [CLSCompliant(false)]
- public enum WireType : uint {
- Varint = 0,
- Fixed64 = 1,
- LengthDelimited = 2,
- StartGroup = 3,
- EndGroup = 4,
- Fixed32 = 5
- }
-
- internal static class MessageSetField {
- internal const int Item = 1;
- internal const int TypeID = 2;
- internal const int Message = 3;
- }
-
- internal static class MessageSetTag {
- internal static readonly uint ItemStart = MakeTag(MessageSetField.Item, WireType.StartGroup);
- internal static readonly uint ItemEnd = MakeTag(MessageSetField.Item, WireType.EndGroup);
- internal static readonly uint TypeID = MakeTag(MessageSetField.TypeID, WireType.Varint);
- internal static readonly uint Message = MakeTag(MessageSetField.Message, WireType.LengthDelimited);
- }
-
- private const int TagTypeBits = 3;
- private const uint TagTypeMask = (1 << TagTypeBits) - 1;
-
- /// <summary>
- /// Given a tag value, determines the wire type (lower 3 bits).
- /// </summary>
- [CLSCompliant(false)]
- public static WireType GetTagWireType(uint tag) {
- return (WireType) (tag & TagTypeMask);
- }
-
- [CLSCompliant(false)]
- public static bool IsEndGroupTag(uint tag) {
- return (WireType)(tag & TagTypeMask) == WireType.EndGroup;
- }
-
- /// <summary>
- /// Given a tag value, determines the field number (the upper 29 bits).
- /// </summary>
- [CLSCompliant(false)]
- public static int GetTagFieldNumber(uint tag) {
- return (int) tag >> TagTypeBits;
- }
-
- /// <summary>
- /// Makes a tag value given a field number and wire type.
- /// TODO(jonskeet): Should we just have a Tag structure?
- /// </summary>
- [CLSCompliant(false)]
- public static uint MakeTag(int fieldNumber, WireType wireType) {
- return (uint) (fieldNumber << TagTypeBits) | (uint) wireType;
- }
-
-#if !LITE
- [CLSCompliant(false)]
- public static uint MakeTag(FieldDescriptor field) {
- return MakeTag(field.FieldNumber, GetWireType(field));
- }
-
- /// <summary>
- /// Returns the wire type for the given field descriptor. This differs
- /// from GetWireType(FieldType) for packed repeated fields.
- /// </summary>
- internal static WireType GetWireType(FieldDescriptor descriptor) {
- return descriptor.IsPacked ? WireType.LengthDelimited : GetWireType(descriptor.FieldType);
- }
-
- /// <summary>
- /// Converts a field type to its wire type. Done with a switch for the sake
- /// of speed - this is significantly faster than a dictionary lookup.
- /// </summary>
- [CLSCompliant(false)]
- public static WireType GetWireType(FieldType fieldType) {
- switch (fieldType) {
- case FieldType.Double:
- return WireType.Fixed64;
- case FieldType.Float:
- return WireType.Fixed32;
- case FieldType.Int64:
- case FieldType.UInt64:
- case FieldType.Int32:
- return WireType.Varint;
- case FieldType.Fixed64:
- return WireType.Fixed64;
- case FieldType.Fixed32:
- return WireType.Fixed32;
- case FieldType.Bool:
- return WireType.Varint;
- case FieldType.String:
- return WireType.LengthDelimited;
- case FieldType.Group:
- return WireType.StartGroup;
- case FieldType.Message:
- case FieldType.Bytes:
- return WireType.LengthDelimited;
- case FieldType.UInt32:
- return WireType.Varint;
- case FieldType.SFixed32:
- return WireType.Fixed32;
- case FieldType.SFixed64:
- return WireType.Fixed64;
- case FieldType.SInt32:
- case FieldType.SInt64:
- case FieldType.Enum:
- return WireType.Varint;
- default:
- throw new ArgumentOutOfRangeException("No such field type");
- }
- }
-#endif
- }
-}
+ public const int BoolSize = 1;
+#endregion
+
+ [CLSCompliant(false)]
+ public enum WireType : uint {
+ Varint = 0,
+ Fixed64 = 1,
+ LengthDelimited = 2,
+ StartGroup = 3,
+ EndGroup = 4,
+ Fixed32 = 5
+ }
+
+ internal static class MessageSetField {
+ internal const int Item = 1;
+ internal const int TypeID = 2;
+ internal const int Message = 3;
+ }
+
+ internal static class MessageSetTag {
+ internal static readonly uint ItemStart = MakeTag(MessageSetField.Item, WireType.StartGroup);
+ internal static readonly uint ItemEnd = MakeTag(MessageSetField.Item, WireType.EndGroup);
+ internal static readonly uint TypeID = MakeTag(MessageSetField.TypeID, WireType.Varint);
+ internal static readonly uint Message = MakeTag(MessageSetField.Message, WireType.LengthDelimited);
+ }
+
+ private const int TagTypeBits = 3;
+ private const uint TagTypeMask = (1 << TagTypeBits) - 1;
+
+ /// <summary>
+ /// Given a tag value, determines the wire type (lower 3 bits).
+ /// </summary>
+ [CLSCompliant(false)]
+ public static WireType GetTagWireType(uint tag) {
+ return (WireType) (tag & TagTypeMask);
+ }
+
+ [CLSCompliant(false)]
+ public static bool IsEndGroupTag(uint tag) {
+ return (WireType)(tag & TagTypeMask) == WireType.EndGroup;
+ }
+
+ /// <summary>
+ /// Given a tag value, determines the field number (the upper 29 bits).
+ /// </summary>
+ [CLSCompliant(false)]
+ public static int GetTagFieldNumber(uint tag) {
+ return (int) tag >> TagTypeBits;
+ }
+
+ /// <summary>
+ /// Makes a tag value given a field number and wire type.
+ /// TODO(jonskeet): Should we just have a Tag structure?
+ /// </summary>
+ [CLSCompliant(false)]
+ public static uint MakeTag(int fieldNumber, WireType wireType) {
+ return (uint) (fieldNumber << TagTypeBits) | (uint) wireType;
+ }
+
+#if !LITE
+ [CLSCompliant(false)]
+ public static uint MakeTag(FieldDescriptor field) {
+ return MakeTag(field.FieldNumber, GetWireType(field));
+ }
+
+ /// <summary>
+ /// Returns the wire type for the given field descriptor. This differs
+ /// from GetWireType(FieldType) for packed repeated fields.
+ /// </summary>
+ internal static WireType GetWireType(FieldDescriptor descriptor) {
+ return descriptor.IsPacked ? WireType.LengthDelimited : GetWireType(descriptor.FieldType);
+ }
+
+ /// <summary>
+ /// Converts a field type to its wire type. Done with a switch for the sake
+ /// of speed - this is significantly faster than a dictionary lookup.
+ /// </summary>
+ [CLSCompliant(false)]
+ public static WireType GetWireType(FieldType fieldType) {
+ switch (fieldType) {
+ case FieldType.Double:
+ return WireType.Fixed64;
+ case FieldType.Float:
+ return WireType.Fixed32;
+ case FieldType.Int64:
+ case FieldType.UInt64:
+ case FieldType.Int32:
+ return WireType.Varint;
+ case FieldType.Fixed64:
+ return WireType.Fixed64;
+ case FieldType.Fixed32:
+ return WireType.Fixed32;
+ case FieldType.Bool:
+ return WireType.Varint;
+ case FieldType.String:
+ return WireType.LengthDelimited;
+ case FieldType.Group:
+ return WireType.StartGroup;
+ case FieldType.Message:
+ case FieldType.Bytes:
+ return WireType.LengthDelimited;
+ case FieldType.UInt32:
+ return WireType.Varint;
+ case FieldType.SFixed32:
+ return WireType.Fixed32;
+ case FieldType.SFixed64:
+ return WireType.Fixed64;
+ case FieldType.SInt32:
+ case FieldType.SInt64:
+ case FieldType.Enum:
+ return WireType.Varint;
+ default:
+ throw new ArgumentOutOfRangeException("No such field type");
+ }
+ }
+#endif
+ }
+}