1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file or at 6 // https://developers.google.com/open-source/licenses/bsd 7 8 package com.google.protobuf; 9 10 import java.io.IOException; 11 import java.util.Arrays; 12 13 /** 14 * {@code UnknownFieldSetLite} is used to keep track of fields which were seen when parsing a 15 * protocol message but whose field numbers or types are unrecognized. This most frequently occurs 16 * when new fields are added to a message type and then messages containing those fields are read by 17 * old software that was compiled before the new types were added. 18 * 19 * <p>For use by generated code only. 20 * 21 * @author dweis@google.com (Daniel Weis) 22 */ 23 public final class UnknownFieldSetLite { 24 25 // Arbitrarily chosen. 26 // TODO: Tune this number? 27 private static final int MIN_CAPACITY = 8; 28 29 private static final UnknownFieldSetLite DEFAULT_INSTANCE = 30 new UnknownFieldSetLite(0, new int[0], new Object[0], /* isMutable= */ false); 31 32 /** 33 * Get an empty {@code UnknownFieldSetLite}. 34 * 35 * <p>For use by generated code only. 36 */ getDefaultInstance()37 public static UnknownFieldSetLite getDefaultInstance() { 38 return DEFAULT_INSTANCE; 39 } 40 41 /** Returns a new mutable instance. */ newInstance()42 static UnknownFieldSetLite newInstance() { 43 return new UnknownFieldSetLite(); 44 } 45 46 /** 47 * Returns a mutable {@code UnknownFieldSetLite} that is the composite of {@code first} and {@code 48 * second}. 49 */ mutableCopyOf(UnknownFieldSetLite first, UnknownFieldSetLite second)50 static UnknownFieldSetLite mutableCopyOf(UnknownFieldSetLite first, UnknownFieldSetLite second) { 51 int count = first.count + second.count; 52 int[] tags = Arrays.copyOf(first.tags, count); 53 System.arraycopy(second.tags, 0, tags, first.count, second.count); 54 Object[] objects = Arrays.copyOf(first.objects, count); 55 System.arraycopy(second.objects, 0, objects, first.count, second.count); 56 return new UnknownFieldSetLite(count, tags, objects, /* isMutable= */ true); 57 } 58 59 /** The number of elements in the set. */ 60 private int count; 61 62 /** The tag numbers for the elements in the set. */ 63 private int[] tags; 64 65 /** The boxed values of the elements in the set. */ 66 private Object[] objects; 67 68 /** The lazily computed serialized size of the set. */ 69 private int memoizedSerializedSize = -1; 70 71 /** Indicates that this object is mutable. */ 72 private boolean isMutable; 73 74 /** Constructs a mutable {@code UnknownFieldSetLite}. */ UnknownFieldSetLite()75 private UnknownFieldSetLite() { 76 this(0, new int[MIN_CAPACITY], new Object[MIN_CAPACITY], /* isMutable= */ true); 77 } 78 79 /** Constructs the {@code UnknownFieldSetLite}. */ UnknownFieldSetLite(int count, int[] tags, Object[] objects, boolean isMutable)80 private UnknownFieldSetLite(int count, int[] tags, Object[] objects, boolean isMutable) { 81 this.count = count; 82 this.tags = tags; 83 this.objects = objects; 84 this.isMutable = isMutable; 85 } 86 87 /** 88 * Marks this object as immutable. 89 * 90 * <p>Future calls to methods that attempt to modify this object will throw. 91 */ makeImmutable()92 public void makeImmutable() { 93 if (this.isMutable) { 94 this.isMutable = false; 95 } 96 } 97 98 /** Throws an {@link UnsupportedOperationException} if immutable. */ checkMutable()99 void checkMutable() { 100 if (!isMutable) { 101 throw new UnsupportedOperationException(); 102 } 103 } 104 105 /** 106 * Serializes the set and writes it to {@code output}. 107 * 108 * <p>For use by generated code only. 109 */ writeTo(CodedOutputStream output)110 public void writeTo(CodedOutputStream output) throws IOException { 111 for (int i = 0; i < count; i++) { 112 int tag = tags[i]; 113 int fieldNumber = WireFormat.getTagFieldNumber(tag); 114 switch (WireFormat.getTagWireType(tag)) { 115 case WireFormat.WIRETYPE_VARINT: 116 output.writeUInt64(fieldNumber, (Long) objects[i]); 117 break; 118 case WireFormat.WIRETYPE_FIXED32: 119 output.writeFixed32(fieldNumber, (Integer) objects[i]); 120 break; 121 case WireFormat.WIRETYPE_FIXED64: 122 output.writeFixed64(fieldNumber, (Long) objects[i]); 123 break; 124 case WireFormat.WIRETYPE_LENGTH_DELIMITED: 125 output.writeBytes(fieldNumber, (ByteString) objects[i]); 126 break; 127 case WireFormat.WIRETYPE_START_GROUP: 128 output.writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); 129 ((UnknownFieldSetLite) objects[i]).writeTo(output); 130 output.writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); 131 break; 132 default: 133 throw InvalidProtocolBufferException.invalidWireType(); 134 } 135 } 136 } 137 138 /** 139 * Serializes the set and writes it to {@code output} using {@code MessageSet} wire format. 140 * 141 * <p>For use by generated code only. 142 */ writeAsMessageSetTo(CodedOutputStream output)143 public void writeAsMessageSetTo(CodedOutputStream output) throws IOException { 144 for (int i = 0; i < count; i++) { 145 int fieldNumber = WireFormat.getTagFieldNumber(tags[i]); 146 output.writeRawMessageSetExtension(fieldNumber, (ByteString) objects[i]); 147 } 148 } 149 150 /** Serializes the set and writes it to {@code writer} using {@code MessageSet} wire format. */ writeAsMessageSetTo(Writer writer)151 void writeAsMessageSetTo(Writer writer) throws IOException { 152 if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) { 153 // Write fields in descending order. 154 for (int i = count - 1; i >= 0; i--) { 155 int fieldNumber = WireFormat.getTagFieldNumber(tags[i]); 156 writer.writeMessageSetItem(fieldNumber, objects[i]); 157 } 158 } else { 159 // Write fields in ascending order. 160 for (int i = 0; i < count; i++) { 161 int fieldNumber = WireFormat.getTagFieldNumber(tags[i]); 162 writer.writeMessageSetItem(fieldNumber, objects[i]); 163 } 164 } 165 } 166 167 /** Serializes the set and writes it to {@code writer}. */ writeTo(Writer writer)168 public void writeTo(Writer writer) throws IOException { 169 if (count == 0) { 170 return; 171 } 172 173 // TODO: tags are not sorted, so there's no write order guarantees 174 if (writer.fieldOrder() == Writer.FieldOrder.ASCENDING) { 175 for (int i = 0; i < count; ++i) { 176 writeField(tags[i], objects[i], writer); 177 } 178 } else { 179 for (int i = count - 1; i >= 0; --i) { 180 writeField(tags[i], objects[i], writer); 181 } 182 } 183 } 184 writeField(int tag, Object object, Writer writer)185 private static void writeField(int tag, Object object, Writer writer) throws IOException { 186 int fieldNumber = WireFormat.getTagFieldNumber(tag); 187 switch (WireFormat.getTagWireType(tag)) { 188 case WireFormat.WIRETYPE_VARINT: 189 writer.writeInt64(fieldNumber, (Long) object); 190 break; 191 case WireFormat.WIRETYPE_FIXED32: 192 writer.writeFixed32(fieldNumber, (Integer) object); 193 break; 194 case WireFormat.WIRETYPE_FIXED64: 195 writer.writeFixed64(fieldNumber, (Long) object); 196 break; 197 case WireFormat.WIRETYPE_LENGTH_DELIMITED: 198 writer.writeBytes(fieldNumber, (ByteString) object); 199 break; 200 case WireFormat.WIRETYPE_START_GROUP: 201 if (writer.fieldOrder() == Writer.FieldOrder.ASCENDING) { 202 writer.writeStartGroup(fieldNumber); 203 ((UnknownFieldSetLite) object).writeTo(writer); 204 writer.writeEndGroup(fieldNumber); 205 } else { 206 writer.writeEndGroup(fieldNumber); 207 ((UnknownFieldSetLite) object).writeTo(writer); 208 writer.writeStartGroup(fieldNumber); 209 } 210 break; 211 default: 212 // TODO: Change writeTo to throw IOException? 213 throw new RuntimeException(InvalidProtocolBufferException.invalidWireType()); 214 } 215 } 216 217 /** 218 * Get the number of bytes required to encode this field, including field number, using {@code 219 * MessageSet} wire format. 220 */ getSerializedSizeAsMessageSet()221 public int getSerializedSizeAsMessageSet() { 222 int size = memoizedSerializedSize; 223 if (size != -1) { 224 return size; 225 } 226 227 size = 0; 228 for (int i = 0; i < count; i++) { 229 int tag = tags[i]; 230 int fieldNumber = WireFormat.getTagFieldNumber(tag); 231 size += 232 CodedOutputStream.computeRawMessageSetExtensionSize(fieldNumber, (ByteString) objects[i]); 233 } 234 235 memoizedSerializedSize = size; 236 237 return size; 238 } 239 240 /** 241 * Get the number of bytes required to encode this set. 242 * 243 * <p>For use by generated code only. 244 */ getSerializedSize()245 public int getSerializedSize() { 246 int size = memoizedSerializedSize; 247 if (size != -1) { 248 return size; 249 } 250 251 size = 0; 252 for (int i = 0; i < count; i++) { 253 int tag = tags[i]; 254 int fieldNumber = WireFormat.getTagFieldNumber(tag); 255 switch (WireFormat.getTagWireType(tag)) { 256 case WireFormat.WIRETYPE_VARINT: 257 size += CodedOutputStream.computeUInt64Size(fieldNumber, (Long) objects[i]); 258 break; 259 case WireFormat.WIRETYPE_FIXED32: 260 size += CodedOutputStream.computeFixed32Size(fieldNumber, (Integer) objects[i]); 261 break; 262 case WireFormat.WIRETYPE_FIXED64: 263 size += CodedOutputStream.computeFixed64Size(fieldNumber, (Long) objects[i]); 264 break; 265 case WireFormat.WIRETYPE_LENGTH_DELIMITED: 266 size += CodedOutputStream.computeBytesSize(fieldNumber, (ByteString) objects[i]); 267 break; 268 case WireFormat.WIRETYPE_START_GROUP: 269 size += 270 CodedOutputStream.computeTagSize(fieldNumber) * 2 271 + ((UnknownFieldSetLite) objects[i]).getSerializedSize(); 272 break; 273 default: 274 throw new IllegalStateException(InvalidProtocolBufferException.invalidWireType()); 275 } 276 } 277 278 memoizedSerializedSize = size; 279 280 return size; 281 } 282 tagsEquals(int[] tags1, int[] tags2, int count)283 private static boolean tagsEquals(int[] tags1, int[] tags2, int count) { 284 for (int i = 0; i < count; ++i) { 285 if (tags1[i] != tags2[i]) { 286 return false; 287 } 288 } 289 return true; 290 } 291 objectsEquals(Object[] objects1, Object[] objects2, int count)292 private static boolean objectsEquals(Object[] objects1, Object[] objects2, int count) { 293 for (int i = 0; i < count; ++i) { 294 if (!objects1[i].equals(objects2[i])) { 295 return false; 296 } 297 } 298 return true; 299 } 300 301 @Override equals(Object obj)302 public boolean equals(Object obj) { 303 if (this == obj) { 304 return true; 305 } 306 307 if (obj == null) { 308 return false; 309 } 310 311 if (!(obj instanceof UnknownFieldSetLite)) { 312 return false; 313 } 314 315 UnknownFieldSetLite other = (UnknownFieldSetLite) obj; 316 if (count != other.count 317 || !tagsEquals(tags, other.tags, count) 318 || !objectsEquals(objects, other.objects, count)) { 319 return false; 320 } 321 322 return true; 323 } 324 hashCode(int[] tags, int count)325 private static int hashCode(int[] tags, int count) { 326 int hashCode = 17; 327 for (int i = 0; i < count; ++i) { 328 hashCode = 31 * hashCode + tags[i]; 329 } 330 return hashCode; 331 } 332 hashCode(Object[] objects, int count)333 private static int hashCode(Object[] objects, int count) { 334 int hashCode = 17; 335 for (int i = 0; i < count; ++i) { 336 hashCode = 31 * hashCode + objects[i].hashCode(); 337 } 338 return hashCode; 339 } 340 341 @Override hashCode()342 public int hashCode() { 343 int hashCode = 17; 344 345 hashCode = 31 * hashCode + count; 346 hashCode = 31 * hashCode + hashCode(tags, count); 347 hashCode = 31 * hashCode + hashCode(objects, count); 348 349 return hashCode; 350 } 351 352 /** 353 * Prints a String representation of the unknown field set. 354 * 355 * <p>For use by generated code only. 356 * 357 * @param buffer the buffer to write to 358 * @param indent the number of spaces the fields should be indented by 359 */ printWithIndent(StringBuilder buffer, int indent)360 final void printWithIndent(StringBuilder buffer, int indent) { 361 for (int i = 0; i < count; i++) { 362 int fieldNumber = WireFormat.getTagFieldNumber(tags[i]); 363 MessageLiteToString.printField(buffer, indent, String.valueOf(fieldNumber), objects[i]); 364 } 365 } 366 367 // Package private for unsafe experimental runtime. storeField(int tag, Object value)368 void storeField(int tag, Object value) { 369 checkMutable(); 370 ensureCapacity(count + 1); 371 372 tags[count] = tag; 373 objects[count] = value; 374 count++; 375 } 376 377 /** Ensures that our arrays are long enough to store more metadata. */ ensureCapacity(int minCapacity)378 private void ensureCapacity(int minCapacity) { 379 if (minCapacity > this.tags.length) { 380 // Increase by at least 50% 381 int newCapacity = count + count / 2; 382 383 // Or new capacity if higher 384 if (newCapacity < minCapacity) { 385 newCapacity = minCapacity; 386 } 387 388 // And never less than MIN_CAPACITY 389 if (newCapacity < MIN_CAPACITY) { 390 newCapacity = MIN_CAPACITY; 391 } 392 393 this.tags = Arrays.copyOf(this.tags, newCapacity); 394 this.objects = Arrays.copyOf(this.objects, newCapacity); 395 } 396 } 397 398 /** 399 * Parse a single field from {@code input} and merge it into this set. 400 * 401 * <p>For use by generated code only. 402 * 403 * @param tag The field's tag number, which was already parsed. 404 * @return {@code false} if the tag is an end group tag. 405 */ mergeFieldFrom(final int tag, final CodedInputStream input)406 boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException { 407 checkMutable(); 408 final int fieldNumber = WireFormat.getTagFieldNumber(tag); 409 switch (WireFormat.getTagWireType(tag)) { 410 case WireFormat.WIRETYPE_VARINT: 411 storeField(tag, input.readInt64()); 412 return true; 413 case WireFormat.WIRETYPE_FIXED32: 414 storeField(tag, input.readFixed32()); 415 return true; 416 case WireFormat.WIRETYPE_FIXED64: 417 storeField(tag, input.readFixed64()); 418 return true; 419 case WireFormat.WIRETYPE_LENGTH_DELIMITED: 420 storeField(tag, input.readBytes()); 421 return true; 422 case WireFormat.WIRETYPE_START_GROUP: 423 final UnknownFieldSetLite subFieldSet = new UnknownFieldSetLite(); 424 subFieldSet.mergeFrom(input); 425 input.checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); 426 storeField(tag, subFieldSet); 427 return true; 428 case WireFormat.WIRETYPE_END_GROUP: 429 return false; 430 default: 431 throw InvalidProtocolBufferException.invalidWireType(); 432 } 433 } 434 435 /** 436 * Convenience method for merging a new field containing a single varint value. This is used in 437 * particular when an unknown enum value is encountered. 438 * 439 * <p>For use by generated code only. 440 */ mergeVarintField(int fieldNumber, int value)441 UnknownFieldSetLite mergeVarintField(int fieldNumber, int value) { 442 checkMutable(); 443 if (fieldNumber == 0) { 444 throw new IllegalArgumentException("Zero is not a valid field number."); 445 } 446 447 storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_VARINT), (long) value); 448 449 return this; 450 } 451 452 /** 453 * Convenience method for merging a length-delimited field. 454 * 455 * <p>For use by generated code only. 456 */ mergeLengthDelimitedField(final int fieldNumber, final ByteString value)457 UnknownFieldSetLite mergeLengthDelimitedField(final int fieldNumber, final ByteString value) { 458 checkMutable(); 459 if (fieldNumber == 0) { 460 throw new IllegalArgumentException("Zero is not a valid field number."); 461 } 462 463 storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED), value); 464 465 return this; 466 } 467 468 /** Parse an entire message from {@code input} and merge its fields into this set. */ mergeFrom(final CodedInputStream input)469 private UnknownFieldSetLite mergeFrom(final CodedInputStream input) throws IOException { 470 // Ensures initialization in mergeFieldFrom. 471 while (true) { 472 final int tag = input.readTag(); 473 if (tag == 0 || !mergeFieldFrom(tag, input)) { 474 break; 475 } 476 } 477 return this; 478 } 479 480 @CanIgnoreReturnValue mergeFrom(UnknownFieldSetLite other)481 UnknownFieldSetLite mergeFrom(UnknownFieldSetLite other) { 482 if (other.equals(getDefaultInstance())) { 483 return this; 484 } 485 486 checkMutable(); 487 int newCount = this.count + other.count; 488 ensureCapacity(newCount); 489 System.arraycopy(other.tags, 0, tags, this.count, other.count); 490 System.arraycopy(other.objects, 0, objects, this.count, other.count); 491 this.count = newCount; 492 return this; 493 } 494 } 495