1 #region Copyright notice and license 2 // Protocol Buffers - Google's data interchange format 3 // Copyright 2017 Google Inc. All rights reserved. 4 // https://developers.google.com/protocol-buffers/ 5 // 6 // Redistribution and use in source and binary forms, with or without 7 // modification, are permitted provided that the following conditions are 8 // met: 9 // 10 // * Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // * Redistributions in binary form must reproduce the above 13 // copyright notice, this list of conditions and the following disclaimer 14 // in the documentation and/or other materials provided with the 15 // distribution. 16 // * Neither the name of Google Inc. nor the names of its 17 // contributors may be used to endorse or promote products derived from 18 // this software without specific prior written permission. 19 // 20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 #endregion 32 33 using System; 34 using System.Collections.Generic; 35 using System.Collections.ObjectModel; 36 using Google.Protobuf.Collections; 37 38 namespace Google.Protobuf 39 { 40 /// <summary> 41 /// Represents a single field in an UnknownFieldSet. 42 /// 43 /// An UnknownField consists of four lists of values. The lists correspond 44 /// to the four "wire types" used in the protocol buffer binary format. 45 /// Normally, only one of the four lists will contain any values, since it 46 /// is impossible to define a valid message type that declares two different 47 /// types for the same field number. However, the code is designed to allow 48 /// for the case where the same unknown field number is encountered using 49 /// multiple different wire types. 50 /// 51 /// </summary> 52 internal sealed class UnknownField 53 { 54 private List<ulong> varintList; 55 private List<uint> fixed32List; 56 private List<ulong> fixed64List; 57 private List<ByteString> lengthDelimitedList; 58 private List<UnknownFieldSet> groupList; 59 60 /// <summary> 61 /// Creates a new UnknownField. 62 /// </summary> UnknownField()63 public UnknownField() 64 { 65 } 66 67 /// <summary> 68 /// Checks if two unknown field are equal. 69 /// </summary> Equals(object other)70 public override bool Equals(object other) 71 { 72 if (ReferenceEquals(this, other)) 73 { 74 return true; 75 } 76 UnknownField otherField = other as UnknownField; 77 return otherField != null 78 && Lists.Equals(varintList, otherField.varintList) 79 && Lists.Equals(fixed32List, otherField.fixed32List) 80 && Lists.Equals(fixed64List, otherField.fixed64List) 81 && Lists.Equals(lengthDelimitedList, otherField.lengthDelimitedList) 82 && Lists.Equals(groupList, otherField.groupList); 83 } 84 85 /// <summary> 86 /// Get the hash code of the unknown field. 87 /// </summary> GetHashCode()88 public override int GetHashCode() 89 { 90 int hash = 43; 91 hash = hash * 47 + Lists.GetHashCode(varintList); 92 hash = hash * 47 + Lists.GetHashCode(fixed32List); 93 hash = hash * 47 + Lists.GetHashCode(fixed64List); 94 hash = hash * 47 + Lists.GetHashCode(lengthDelimitedList); 95 hash = hash * 47 + Lists.GetHashCode(groupList); 96 return hash; 97 } 98 99 /// <summary> 100 /// Serializes the field, including the field number, and writes it to 101 /// <paramref name="output"/> 102 /// </summary> 103 /// <param name="fieldNumber">The unknown field number.</param> 104 /// <param name="output">The write context to write to.</param> WriteTo(int fieldNumber, ref WriteContext output)105 internal void WriteTo(int fieldNumber, ref WriteContext output) 106 { 107 if (varintList != null) 108 { 109 foreach (ulong value in varintList) 110 { 111 output.WriteTag(fieldNumber, WireFormat.WireType.Varint); 112 output.WriteUInt64(value); 113 } 114 } 115 if (fixed32List != null) 116 { 117 foreach (uint value in fixed32List) 118 { 119 output.WriteTag(fieldNumber, WireFormat.WireType.Fixed32); 120 output.WriteFixed32(value); 121 } 122 } 123 if (fixed64List != null) 124 { 125 foreach (ulong value in fixed64List) 126 { 127 output.WriteTag(fieldNumber, WireFormat.WireType.Fixed64); 128 output.WriteFixed64(value); 129 } 130 } 131 if (lengthDelimitedList != null) 132 { 133 foreach (ByteString value in lengthDelimitedList) 134 { 135 output.WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited); 136 output.WriteBytes(value); 137 } 138 } 139 if (groupList != null) 140 { 141 foreach (UnknownFieldSet value in groupList) 142 { 143 output.WriteTag(fieldNumber, WireFormat.WireType.StartGroup); 144 value.WriteTo(ref output); 145 output.WriteTag(fieldNumber, WireFormat.WireType.EndGroup); 146 } 147 } 148 } 149 150 /// <summary> 151 /// Computes the number of bytes required to encode this field, including field 152 /// number. 153 /// </summary> GetSerializedSize(int fieldNumber)154 internal int GetSerializedSize(int fieldNumber) 155 { 156 int result = 0; 157 if (varintList != null) 158 { 159 result += CodedOutputStream.ComputeTagSize(fieldNumber) * varintList.Count; 160 foreach (ulong value in varintList) 161 { 162 result += CodedOutputStream.ComputeUInt64Size(value); 163 } 164 } 165 if (fixed32List != null) 166 { 167 result += CodedOutputStream.ComputeTagSize(fieldNumber) * fixed32List.Count; 168 result += CodedOutputStream.ComputeFixed32Size(1) * fixed32List.Count; 169 } 170 if (fixed64List != null) 171 { 172 result += CodedOutputStream.ComputeTagSize(fieldNumber) * fixed64List.Count; 173 result += CodedOutputStream.ComputeFixed64Size(1) * fixed64List.Count; 174 } 175 if (lengthDelimitedList != null) 176 { 177 result += CodedOutputStream.ComputeTagSize(fieldNumber) * lengthDelimitedList.Count; 178 foreach (ByteString value in lengthDelimitedList) 179 { 180 result += CodedOutputStream.ComputeBytesSize(value); 181 } 182 } 183 if (groupList != null) 184 { 185 result += CodedOutputStream.ComputeTagSize(fieldNumber) * 2 * groupList.Count; 186 foreach (UnknownFieldSet value in groupList) 187 { 188 result += value.CalculateSize(); 189 } 190 } 191 return result; 192 } 193 194 /// <summary> 195 /// Merge the values in <paramref name="other" /> into this field. For each list 196 /// of values, <paramref name="other"/>'s values are append to the ones in this 197 /// field. 198 /// </summary> MergeFrom(UnknownField other)199 internal UnknownField MergeFrom(UnknownField other) 200 { 201 varintList = AddAll(varintList, other.varintList); 202 fixed32List = AddAll(fixed32List, other.fixed32List); 203 fixed64List = AddAll(fixed64List, other.fixed64List); 204 lengthDelimitedList = AddAll(lengthDelimitedList, other.lengthDelimitedList); 205 groupList = AddAll(groupList, other.groupList); 206 return this; 207 } 208 209 /// <summary> 210 /// Returns a new list containing all of the given specified values from 211 /// both the <paramref name="current"/> and <paramref name="extras"/> lists. 212 /// If <paramref name="current" /> is null and <paramref name="extras"/> is null or empty, 213 /// null is returned. Otherwise, either a new list is created (if <paramref name="current" /> 214 /// is null) or the elements of <paramref name="extras"/> are added to <paramref name="current" />. 215 /// </summary> AddAll(List<T> current, IList<T> extras)216 private static List<T> AddAll<T>(List<T> current, IList<T> extras) 217 { 218 if (extras == null || extras.Count == 0) 219 { 220 return current; 221 } 222 if (current == null) 223 { 224 current = new List<T>(extras); 225 } 226 else 227 { 228 current.AddRange(extras); 229 } 230 return current; 231 } 232 233 /// <summary> 234 /// Adds a varint value. 235 /// </summary> AddVarint(ulong value)236 internal UnknownField AddVarint(ulong value) 237 { 238 varintList = Add(varintList, value); 239 return this; 240 } 241 242 /// <summary> 243 /// Adds a fixed32 value. 244 /// </summary> AddFixed32(uint value)245 internal UnknownField AddFixed32(uint value) 246 { 247 fixed32List = Add(fixed32List, value); 248 return this; 249 } 250 251 /// <summary> 252 /// Adds a fixed64 value. 253 /// </summary> AddFixed64(ulong value)254 internal UnknownField AddFixed64(ulong value) 255 { 256 fixed64List = Add(fixed64List, value); 257 return this; 258 } 259 260 /// <summary> 261 /// Adds a length-delimited value. 262 /// </summary> AddLengthDelimited(ByteString value)263 internal UnknownField AddLengthDelimited(ByteString value) 264 { 265 lengthDelimitedList = Add(lengthDelimitedList, value); 266 return this; 267 } 268 AddGroup(UnknownFieldSet value)269 internal UnknownField AddGroup(UnknownFieldSet value) 270 { 271 groupList = Add(groupList, value); 272 return this; 273 } 274 275 /// <summary> 276 /// Adds <paramref name="value"/> to the <paramref name="list"/>, creating 277 /// a new list if <paramref name="list"/> is null. The list is returned - either 278 /// the original reference or the new list. 279 /// </summary> Add(List<T> list, T value)280 private static List<T> Add<T>(List<T> list, T value) 281 { 282 if (list == null) 283 { 284 list = new List<T>(); 285 } 286 list.Add(value); 287 return list; 288 } 289 } 290 } 291