1 #region Copyright notice and license 2 // Protocol Buffers - Google's data interchange format 3 // Copyright 2017 Google Inc. All rights reserved. 4 // 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file or at 7 // https://developers.google.com/open-source/licenses/bsd 8 #endregion 9 10 using System.Collections.Generic; 11 using Google.Protobuf.Collections; 12 13 namespace Google.Protobuf 14 { 15 /// <summary> 16 /// Represents a single field in an UnknownFieldSet. 17 /// 18 /// An UnknownField consists of four lists of values. The lists correspond 19 /// to the four "wire types" used in the protocol buffer binary format. 20 /// Normally, only one of the four lists will contain any values, since it 21 /// is impossible to define a valid message type that declares two different 22 /// types for the same field number. However, the code is designed to allow 23 /// for the case where the same unknown field number is encountered using 24 /// multiple different wire types. 25 /// 26 /// </summary> 27 internal sealed class UnknownField 28 { 29 private List<ulong> varintList; 30 private List<uint> fixed32List; 31 private List<ulong> fixed64List; 32 private List<ByteString> lengthDelimitedList; 33 private List<UnknownFieldSet> groupList; 34 35 /// <summary> 36 /// Creates a new UnknownField. 37 /// </summary> UnknownField()38 public UnknownField() 39 { 40 } 41 42 /// <summary> 43 /// Checks if two unknown field are equal. 44 /// </summary> Equals(object other)45 public override bool Equals(object other) 46 { 47 if (ReferenceEquals(this, other)) 48 { 49 return true; 50 } 51 return other is UnknownField otherField 52 && Lists.Equals(varintList, otherField.varintList) 53 && Lists.Equals(fixed32List, otherField.fixed32List) 54 && Lists.Equals(fixed64List, otherField.fixed64List) 55 && Lists.Equals(lengthDelimitedList, otherField.lengthDelimitedList) 56 && Lists.Equals(groupList, otherField.groupList); 57 } 58 59 /// <summary> 60 /// Get the hash code of the unknown field. 61 /// </summary> GetHashCode()62 public override int GetHashCode() 63 { 64 int hash = 43; 65 hash = hash * 47 + Lists.GetHashCode(varintList); 66 hash = hash * 47 + Lists.GetHashCode(fixed32List); 67 hash = hash * 47 + Lists.GetHashCode(fixed64List); 68 hash = hash * 47 + Lists.GetHashCode(lengthDelimitedList); 69 hash = hash * 47 + Lists.GetHashCode(groupList); 70 return hash; 71 } 72 73 /// <summary> 74 /// Serializes the field, including the field number, and writes it to 75 /// <paramref name="output"/> 76 /// </summary> 77 /// <param name="fieldNumber">The unknown field number.</param> 78 /// <param name="output">The write context to write to.</param> WriteTo(int fieldNumber, ref WriteContext output)79 internal void WriteTo(int fieldNumber, ref WriteContext output) 80 { 81 if (varintList != null) 82 { 83 foreach (ulong value in varintList) 84 { 85 output.WriteTag(fieldNumber, WireFormat.WireType.Varint); 86 output.WriteUInt64(value); 87 } 88 } 89 if (fixed32List != null) 90 { 91 foreach (uint value in fixed32List) 92 { 93 output.WriteTag(fieldNumber, WireFormat.WireType.Fixed32); 94 output.WriteFixed32(value); 95 } 96 } 97 if (fixed64List != null) 98 { 99 foreach (ulong value in fixed64List) 100 { 101 output.WriteTag(fieldNumber, WireFormat.WireType.Fixed64); 102 output.WriteFixed64(value); 103 } 104 } 105 if (lengthDelimitedList != null) 106 { 107 foreach (ByteString value in lengthDelimitedList) 108 { 109 output.WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited); 110 output.WriteBytes(value); 111 } 112 } 113 if (groupList != null) 114 { 115 foreach (UnknownFieldSet value in groupList) 116 { 117 output.WriteTag(fieldNumber, WireFormat.WireType.StartGroup); 118 value.WriteTo(ref output); 119 output.WriteTag(fieldNumber, WireFormat.WireType.EndGroup); 120 } 121 } 122 } 123 124 /// <summary> 125 /// Computes the number of bytes required to encode this field, including field 126 /// number. 127 /// </summary> GetSerializedSize(int fieldNumber)128 internal int GetSerializedSize(int fieldNumber) 129 { 130 int result = 0; 131 if (varintList != null) 132 { 133 result += CodedOutputStream.ComputeTagSize(fieldNumber) * varintList.Count; 134 foreach (ulong value in varintList) 135 { 136 result += CodedOutputStream.ComputeUInt64Size(value); 137 } 138 } 139 if (fixed32List != null) 140 { 141 result += CodedOutputStream.ComputeTagSize(fieldNumber) * fixed32List.Count; 142 result += CodedOutputStream.ComputeFixed32Size(1) * fixed32List.Count; 143 } 144 if (fixed64List != null) 145 { 146 result += CodedOutputStream.ComputeTagSize(fieldNumber) * fixed64List.Count; 147 result += CodedOutputStream.ComputeFixed64Size(1) * fixed64List.Count; 148 } 149 if (lengthDelimitedList != null) 150 { 151 result += CodedOutputStream.ComputeTagSize(fieldNumber) * lengthDelimitedList.Count; 152 foreach (ByteString value in lengthDelimitedList) 153 { 154 result += CodedOutputStream.ComputeBytesSize(value); 155 } 156 } 157 if (groupList != null) 158 { 159 result += CodedOutputStream.ComputeTagSize(fieldNumber) * 2 * groupList.Count; 160 foreach (UnknownFieldSet value in groupList) 161 { 162 result += value.CalculateSize(); 163 } 164 } 165 return result; 166 } 167 168 /// <summary> 169 /// Merge the values in <paramref name="other" /> into this field. For each list 170 /// of values, <paramref name="other"/>'s values are append to the ones in this 171 /// field. 172 /// </summary> MergeFrom(UnknownField other)173 internal UnknownField MergeFrom(UnknownField other) 174 { 175 varintList = AddAll(varintList, other.varintList); 176 fixed32List = AddAll(fixed32List, other.fixed32List); 177 fixed64List = AddAll(fixed64List, other.fixed64List); 178 lengthDelimitedList = AddAll(lengthDelimitedList, other.lengthDelimitedList); 179 groupList = AddAll(groupList, other.groupList); 180 return this; 181 } 182 183 /// <summary> 184 /// Returns a new list containing all of the given specified values from 185 /// both the <paramref name="current"/> and <paramref name="extras"/> lists. 186 /// If <paramref name="current" /> is null and <paramref name="extras"/> is null or empty, 187 /// null is returned. Otherwise, either a new list is created (if <paramref name="current" /> 188 /// is null) or the elements of <paramref name="extras"/> are added to <paramref name="current" />. 189 /// </summary> AddAll(List<T> current, IList<T> extras)190 private static List<T> AddAll<T>(List<T> current, IList<T> extras) 191 { 192 if (extras == null || extras.Count == 0) 193 { 194 return current; 195 } 196 if (current == null) 197 { 198 current = new List<T>(extras); 199 } 200 else 201 { 202 current.AddRange(extras); 203 } 204 return current; 205 } 206 207 /// <summary> 208 /// Adds a varint value. 209 /// </summary> AddVarint(ulong value)210 internal UnknownField AddVarint(ulong value) 211 { 212 varintList = Add(varintList, value); 213 return this; 214 } 215 216 /// <summary> 217 /// Adds a fixed32 value. 218 /// </summary> AddFixed32(uint value)219 internal UnknownField AddFixed32(uint value) 220 { 221 fixed32List = Add(fixed32List, value); 222 return this; 223 } 224 225 /// <summary> 226 /// Adds a fixed64 value. 227 /// </summary> AddFixed64(ulong value)228 internal UnknownField AddFixed64(ulong value) 229 { 230 fixed64List = Add(fixed64List, value); 231 return this; 232 } 233 234 /// <summary> 235 /// Adds a length-delimited value. 236 /// </summary> AddLengthDelimited(ByteString value)237 internal UnknownField AddLengthDelimited(ByteString value) 238 { 239 lengthDelimitedList = Add(lengthDelimitedList, value); 240 return this; 241 } 242 AddGroup(UnknownFieldSet value)243 internal UnknownField AddGroup(UnknownFieldSet value) 244 { 245 groupList = Add(groupList, value); 246 return this; 247 } 248 249 /// <summary> 250 /// Adds <paramref name="value"/> to the <paramref name="list"/>, creating 251 /// a new list if <paramref name="list"/> is null. The list is returned - either 252 /// the original reference or the new list. 253 /// </summary> Add(List<T> list, T value)254 private static List<T> Add<T>(List<T> list, T value) 255 { 256 if (list == null) 257 { 258 list = new List<T>(); 259 } 260 list.Add(value); 261 return list; 262 } 263 } 264 } 265