diff options
Diffstat (limited to 'csharp/ProtocolBuffers/UnknownFieldSet.cs')
-rw-r--r-- | csharp/ProtocolBuffers/UnknownFieldSet.cs | 626 |
1 files changed, 0 insertions, 626 deletions
diff --git a/csharp/ProtocolBuffers/UnknownFieldSet.cs b/csharp/ProtocolBuffers/UnknownFieldSet.cs deleted file mode 100644 index 18eacbe8..00000000 --- a/csharp/ProtocolBuffers/UnknownFieldSet.cs +++ /dev/null @@ -1,626 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. -// http://code.google.com/p/protobuf/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -using System; -using System.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 { - - 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> - /// 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; - } - } - - /// <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(); - } - - /// <summary> - /// Builder for UnknownFieldSets. - /// </summary> - public sealed class Builder - { - /// <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 = new SortedList<int, UnknownField>(); - - // 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). - int lastFieldNumber; - UnknownField.Builder lastField; - - internal Builder() { - } - - /// <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> - 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(); - input.ReadUnknownGroup(number, subBuilder); - 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> - 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) { - - if (DescriptorProtoFile.Bootstrapping) { - return MergeFieldFrom(tag, input); - } - - 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; - IMessage 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.FieldType)) { - return MergeFieldFrom(tag, input); - } - - object value; - switch (field.FieldType) { - case FieldType.Group: - case FieldType.Message: { - IBuilder subBuilder; - if (defaultFieldInstance != null) { - subBuilder = defaultFieldInstance.WeakCreateBuilderForType(); - } else { - subBuilder = builder.CreateBuilderForField(field); - } - if (!field.IsRepeated) { - subBuilder.WeakMergeFrom((IMessage)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" - IBuilder 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(); - IMessage originalMessage = (IMessage)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(); - } - } - } - } -} |