1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf.nano; 32 33 import com.google.protobuf.nano.MapFactories.MapFactory; 34 35 import java.io.IOException; 36 import java.nio.charset.Charset; 37 import java.util.Arrays; 38 import java.util.Map; 39 import java.util.Map.Entry; 40 41 /** 42 * The classes contained within are used internally by the Protocol Buffer 43 * library and generated message implementations. They are public only because 44 * those generated messages do not reside in the {@code protobuf} package. 45 * Others should not use this class directly. 46 * 47 * @author kenton@google.com (Kenton Varda) 48 */ 49 public final class InternalNano { 50 51 public static final int TYPE_DOUBLE = 1; 52 public static final int TYPE_FLOAT = 2; 53 public static final int TYPE_INT64 = 3; 54 public static final int TYPE_UINT64 = 4; 55 public static final int TYPE_INT32 = 5; 56 public static final int TYPE_FIXED64 = 6; 57 public static final int TYPE_FIXED32 = 7; 58 public static final int TYPE_BOOL = 8; 59 public static final int TYPE_STRING = 9; 60 public static final int TYPE_GROUP = 10; 61 public static final int TYPE_MESSAGE = 11; 62 public static final int TYPE_BYTES = 12; 63 public static final int TYPE_UINT32 = 13; 64 public static final int TYPE_ENUM = 14; 65 public static final int TYPE_SFIXED32 = 15; 66 public static final int TYPE_SFIXED64 = 16; 67 public static final int TYPE_SINT32 = 17; 68 public static final int TYPE_SINT64 = 18; 69 70 protected static final Charset UTF_8 = Charset.forName("UTF-8"); 71 protected static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); 72 InternalNano()73 private InternalNano() {} 74 75 /** 76 * An object to provide synchronization when lazily initializing static fields 77 * of {@link MessageNano} subclasses. 78 * <p> 79 * To enable earlier versions of ProGuard to inline short methods from a 80 * generated MessageNano subclass to the call sites, that class must not have 81 * a class initializer, which will be created if there is any static variable 82 * initializers. To lazily initialize the static variables in a thread-safe 83 * manner, the initialization code will synchronize on this object. 84 */ 85 public static final Object LAZY_INIT_LOCK = new Object(); 86 87 /** 88 * Helper called by generated code to construct default values for string 89 * fields. 90 * <p> 91 * The protocol compiler does not actually contain a UTF-8 decoder -- it 92 * just pushes UTF-8-encoded text around without touching it. The one place 93 * where this presents a problem is when generating Java string literals. 94 * Unicode characters in the string literal would normally need to be encoded 95 * using a Unicode escape sequence, which would require decoding them. 96 * To get around this, protoc instead embeds the UTF-8 bytes into the 97 * generated code and leaves it to the runtime library to decode them. 98 * <p> 99 * It gets worse, though. If protoc just generated a byte array, like: 100 * new byte[] {0x12, 0x34, 0x56, 0x78} 101 * Java actually generates *code* which allocates an array and then fills 102 * in each value. This is much less efficient than just embedding the bytes 103 * directly into the bytecode. To get around this, we need another 104 * work-around. String literals are embedded directly, so protoc actually 105 * generates a string literal corresponding to the bytes. The easiest way 106 * to do this is to use the ISO-8859-1 character set, which corresponds to 107 * the first 256 characters of the Unicode range. Protoc can then use 108 * good old CEscape to generate the string. 109 * <p> 110 * So we have a string literal which represents a set of bytes which 111 * represents another string. This function -- stringDefaultValue -- 112 * converts from the generated string to the string we actually want. The 113 * generated code calls this automatically. 114 */ stringDefaultValue(String bytes)115 public static String stringDefaultValue(String bytes) { 116 return new String(bytes.getBytes(ISO_8859_1), InternalNano.UTF_8); 117 } 118 119 /** 120 * Helper called by generated code to construct default values for bytes 121 * fields. 122 * <p> 123 * This is a lot like {@link #stringDefaultValue}, but for bytes fields. 124 * In this case we only need the second of the two hacks -- allowing us to 125 * embed raw bytes as a string literal with ISO-8859-1 encoding. 126 */ bytesDefaultValue(String bytes)127 public static byte[] bytesDefaultValue(String bytes) { 128 return bytes.getBytes(ISO_8859_1); 129 } 130 131 /** 132 * Helper function to convert a string into UTF-8 while turning the 133 * UnsupportedEncodingException to a RuntimeException. 134 */ copyFromUtf8(final String text)135 public static byte[] copyFromUtf8(final String text) { 136 return text.getBytes(InternalNano.UTF_8); 137 } 138 139 /** 140 * Checks repeated int field equality; null-value and 0-length fields are 141 * considered equal. 142 */ equals(int[] field1, int[] field2)143 public static boolean equals(int[] field1, int[] field2) { 144 if (field1 == null || field1.length == 0) { 145 return field2 == null || field2.length == 0; 146 } else { 147 return Arrays.equals(field1, field2); 148 } 149 } 150 151 /** 152 * Checks repeated long field equality; null-value and 0-length fields are 153 * considered equal. 154 */ equals(long[] field1, long[] field2)155 public static boolean equals(long[] field1, long[] field2) { 156 if (field1 == null || field1.length == 0) { 157 return field2 == null || field2.length == 0; 158 } else { 159 return Arrays.equals(field1, field2); 160 } 161 } 162 163 /** 164 * Checks repeated float field equality; null-value and 0-length fields are 165 * considered equal. 166 */ equals(float[] field1, float[] field2)167 public static boolean equals(float[] field1, float[] field2) { 168 if (field1 == null || field1.length == 0) { 169 return field2 == null || field2.length == 0; 170 } else { 171 return Arrays.equals(field1, field2); 172 } 173 } 174 175 /** 176 * Checks repeated double field equality; null-value and 0-length fields are 177 * considered equal. 178 */ equals(double[] field1, double[] field2)179 public static boolean equals(double[] field1, double[] field2) { 180 if (field1 == null || field1.length == 0) { 181 return field2 == null || field2.length == 0; 182 } else { 183 return Arrays.equals(field1, field2); 184 } 185 } 186 187 /** 188 * Checks repeated boolean field equality; null-value and 0-length fields are 189 * considered equal. 190 */ equals(boolean[] field1, boolean[] field2)191 public static boolean equals(boolean[] field1, boolean[] field2) { 192 if (field1 == null || field1.length == 0) { 193 return field2 == null || field2.length == 0; 194 } else { 195 return Arrays.equals(field1, field2); 196 } 197 } 198 199 /** 200 * Checks repeated bytes field equality. Only non-null elements are tested. 201 * Returns true if the two fields have the same sequence of non-null 202 * elements. Null-value fields and fields of any length with only null 203 * elements are considered equal. 204 */ equals(byte[][] field1, byte[][] field2)205 public static boolean equals(byte[][] field1, byte[][] field2) { 206 int index1 = 0; 207 int length1 = field1 == null ? 0 : field1.length; 208 int index2 = 0; 209 int length2 = field2 == null ? 0 : field2.length; 210 while (true) { 211 while (index1 < length1 && field1[index1] == null) { 212 index1++; 213 } 214 while (index2 < length2 && field2[index2] == null) { 215 index2++; 216 } 217 boolean atEndOf1 = index1 >= length1; 218 boolean atEndOf2 = index2 >= length2; 219 if (atEndOf1 && atEndOf2) { 220 // no more non-null elements to test in both arrays 221 return true; 222 } else if (atEndOf1 != atEndOf2) { 223 // one of the arrays have extra non-null elements 224 return false; 225 } else if (!Arrays.equals(field1[index1], field2[index2])) { 226 // element mismatch 227 return false; 228 } 229 index1++; 230 index2++; 231 } 232 } 233 234 /** 235 * Checks repeated string/message field equality. Only non-null elements are 236 * tested. Returns true if the two fields have the same sequence of non-null 237 * elements. Null-value fields and fields of any length with only null 238 * elements are considered equal. 239 */ equals(Object[] field1, Object[] field2)240 public static boolean equals(Object[] field1, Object[] field2) { 241 int index1 = 0; 242 int length1 = field1 == null ? 0 : field1.length; 243 int index2 = 0; 244 int length2 = field2 == null ? 0 : field2.length; 245 while (true) { 246 while (index1 < length1 && field1[index1] == null) { 247 index1++; 248 } 249 while (index2 < length2 && field2[index2] == null) { 250 index2++; 251 } 252 boolean atEndOf1 = index1 >= length1; 253 boolean atEndOf2 = index2 >= length2; 254 if (atEndOf1 && atEndOf2) { 255 // no more non-null elements to test in both arrays 256 return true; 257 } else if (atEndOf1 != atEndOf2) { 258 // one of the arrays have extra non-null elements 259 return false; 260 } else if (!field1[index1].equals(field2[index2])) { 261 // element mismatch 262 return false; 263 } 264 index1++; 265 index2++; 266 } 267 } 268 269 /** 270 * Computes the hash code of a repeated int field. Null-value and 0-length 271 * fields have the same hash code. 272 */ hashCode(int[] field)273 public static int hashCode(int[] field) { 274 return field == null || field.length == 0 ? 0 : Arrays.hashCode(field); 275 } 276 277 /** 278 * Computes the hash code of a repeated long field. Null-value and 0-length 279 * fields have the same hash code. 280 */ hashCode(long[] field)281 public static int hashCode(long[] field) { 282 return field == null || field.length == 0 ? 0 : Arrays.hashCode(field); 283 } 284 285 /** 286 * Computes the hash code of a repeated float field. Null-value and 0-length 287 * fields have the same hash code. 288 */ hashCode(float[] field)289 public static int hashCode(float[] field) { 290 return field == null || field.length == 0 ? 0 : Arrays.hashCode(field); 291 } 292 293 /** 294 * Computes the hash code of a repeated double field. Null-value and 0-length 295 * fields have the same hash code. 296 */ hashCode(double[] field)297 public static int hashCode(double[] field) { 298 return field == null || field.length == 0 ? 0 : Arrays.hashCode(field); 299 } 300 301 /** 302 * Computes the hash code of a repeated boolean field. Null-value and 0-length 303 * fields have the same hash code. 304 */ hashCode(boolean[] field)305 public static int hashCode(boolean[] field) { 306 return field == null || field.length == 0 ? 0 : Arrays.hashCode(field); 307 } 308 309 /** 310 * Computes the hash code of a repeated bytes field. Only the sequence of all 311 * non-null elements are used in the computation. Null-value fields and fields 312 * of any length with only null elements have the same hash code. 313 */ hashCode(byte[][] field)314 public static int hashCode(byte[][] field) { 315 int result = 0; 316 for (int i = 0, size = field == null ? 0 : field.length; i < size; i++) { 317 byte[] element = field[i]; 318 if (element != null) { 319 result = 31 * result + Arrays.hashCode(element); 320 } 321 } 322 return result; 323 } 324 325 /** 326 * Computes the hash code of a repeated string/message field. Only the 327 * sequence of all non-null elements are used in the computation. Null-value 328 * fields and fields of any length with only null elements have the same hash 329 * code. 330 */ hashCode(Object[] field)331 public static int hashCode(Object[] field) { 332 int result = 0; 333 for (int i = 0, size = field == null ? 0 : field.length; i < size; i++) { 334 Object element = field[i]; 335 if (element != null) { 336 result = 31 * result + element.hashCode(); 337 } 338 } 339 return result; 340 } primitiveDefaultValue(int type)341 private static Object primitiveDefaultValue(int type) { 342 switch (type) { 343 case TYPE_BOOL: 344 return Boolean.FALSE; 345 case TYPE_BYTES: 346 return WireFormatNano.EMPTY_BYTES; 347 case TYPE_STRING: 348 return ""; 349 case TYPE_FLOAT: 350 return Float.valueOf(0); 351 case TYPE_DOUBLE: 352 return Double.valueOf(0); 353 case TYPE_ENUM: 354 case TYPE_FIXED32: 355 case TYPE_INT32: 356 case TYPE_UINT32: 357 case TYPE_SINT32: 358 case TYPE_SFIXED32: 359 return Integer.valueOf(0); 360 case TYPE_INT64: 361 case TYPE_UINT64: 362 case TYPE_SINT64: 363 case TYPE_FIXED64: 364 case TYPE_SFIXED64: 365 return Long.valueOf(0L); 366 case TYPE_MESSAGE: 367 case TYPE_GROUP: 368 default: 369 throw new IllegalArgumentException( 370 "Type: " + type + " is not a primitive type."); 371 } 372 } 373 374 /** 375 * Merges the map entry into the map field. Note this is only supposed to 376 * be called by generated messages. 377 * 378 * @param map the map field; may be null, in which case a map will be 379 * instantiated using the {@link MapFactories.MapFactory} 380 * @param input the input byte buffer 381 * @param keyType key type, as defined in InternalNano.TYPE_* 382 * @param valueType value type, as defined in InternalNano.TYPE_* 383 * @param value an new instance of the value, if the value is a TYPE_MESSAGE; 384 * otherwise this parameter can be null and will be ignored. 385 * @param keyTag wire tag for the key 386 * @param valueTag wire tag for the value 387 * @return the map field 388 * @throws IOException 389 */ 390 @SuppressWarnings("unchecked") mergeMapEntry( CodedInputByteBufferNano input, Map<K, V> map, MapFactory mapFactory, int keyType, int valueType, V value, int keyTag, int valueTag)391 public static final <K, V> Map<K, V> mergeMapEntry( 392 CodedInputByteBufferNano input, 393 Map<K, V> map, 394 MapFactory mapFactory, 395 int keyType, 396 int valueType, 397 V value, 398 int keyTag, 399 int valueTag) throws IOException { 400 map = mapFactory.forMap(map); 401 final int length = input.readRawVarint32(); 402 final int oldLimit = input.pushLimit(length); 403 K key = null; 404 while (true) { 405 int tag = input.readTag(); 406 if (tag == 0) { 407 break; 408 } 409 if (tag == keyTag) { 410 key = (K) input.readPrimitiveField(keyType); 411 } else if (tag == valueTag) { 412 if (valueType == TYPE_MESSAGE) { 413 input.readMessage((MessageNano) value); 414 } else { 415 value = (V) input.readPrimitiveField(valueType); 416 } 417 } else { 418 if (!input.skipField(tag)) { 419 break; 420 } 421 } 422 } 423 input.checkLastTagWas(0); 424 input.popLimit(oldLimit); 425 426 if (key == null) { 427 // key can only be primitive types. 428 key = (K) primitiveDefaultValue(keyType); 429 } 430 431 if (value == null) { 432 // message type value will be initialized by code-gen. 433 value = (V) primitiveDefaultValue(valueType); 434 } 435 436 map.put(key, value); 437 return map; 438 } 439 serializeMapField( CodedOutputByteBufferNano output, Map<K, V> map, int number, int keyType, int valueType)440 public static <K, V> void serializeMapField( 441 CodedOutputByteBufferNano output, 442 Map<K, V> map, int number, int keyType, int valueType) 443 throws IOException { 444 for (Entry<K, V> entry: map.entrySet()) { 445 K key = entry.getKey(); 446 V value = entry.getValue(); 447 if (key == null || value == null) { 448 throw new IllegalStateException( 449 "keys and values in maps cannot be null"); 450 } 451 int entrySize = 452 CodedOutputByteBufferNano.computeFieldSize(1, keyType, key) + 453 CodedOutputByteBufferNano.computeFieldSize(2, valueType, value); 454 output.writeTag(number, WireFormatNano.WIRETYPE_LENGTH_DELIMITED); 455 output.writeRawVarint32(entrySize); 456 output.writeField(1, keyType, key); 457 output.writeField(2, valueType, value); 458 } 459 } 460 computeMapFieldSize( Map<K, V> map, int number, int keyType, int valueType)461 public static <K, V> int computeMapFieldSize( 462 Map<K, V> map, int number, int keyType, int valueType) { 463 int size = 0; 464 int tagSize = CodedOutputByteBufferNano.computeTagSize(number); 465 for (Entry<K, V> entry: map.entrySet()) { 466 K key = entry.getKey(); 467 V value = entry.getValue(); 468 if (key == null || value == null) { 469 throw new IllegalStateException( 470 "keys and values in maps cannot be null"); 471 } 472 int entrySize = 473 CodedOutputByteBufferNano.computeFieldSize(1, keyType, key) + 474 CodedOutputByteBufferNano.computeFieldSize(2, valueType, value); 475 size += tagSize + entrySize 476 + CodedOutputByteBufferNano.computeRawVarint32Size(entrySize); 477 } 478 return size; 479 } 480 481 /** 482 * Checks whether two {@link Map} are equal. We don't use the default equals 483 * method of {@link Map} because it compares by identity not by content for 484 * byte arrays. 485 */ equals(Map<K, V> a, Map<K, V> b)486 public static <K, V> boolean equals(Map<K, V> a, Map<K, V> b) { 487 if (a == b) { 488 return true; 489 } 490 if (a == null) { 491 return b.size() == 0; 492 } 493 if (b == null) { 494 return a.size() == 0; 495 } 496 if (a.size() != b.size()) { 497 return false; 498 } 499 for (Entry<K, V> entry : a.entrySet()) { 500 if (!b.containsKey(entry.getKey())) { 501 return false; 502 } 503 if (!equalsMapValue(entry.getValue(), b.get(entry.getKey()))) { 504 return false; 505 } 506 } 507 return true; 508 } 509 equalsMapValue(Object a, Object b)510 private static boolean equalsMapValue(Object a, Object b) { 511 if (a == null || b == null) { 512 throw new IllegalStateException( 513 "keys and values in maps cannot be null"); 514 } 515 if (a instanceof byte[] && b instanceof byte[]) { 516 return Arrays.equals((byte[]) a, (byte[]) b); 517 } 518 return a.equals(b); 519 } 520 hashCode(Map<K, V> map)521 public static <K, V> int hashCode(Map<K, V> map) { 522 if (map == null) { 523 return 0; 524 } 525 int result = 0; 526 for (Entry<K, V> entry : map.entrySet()) { 527 result += hashCodeForMap(entry.getKey()) 528 ^ hashCodeForMap(entry.getValue()); 529 } 530 return result; 531 } 532 hashCodeForMap(Object o)533 private static int hashCodeForMap(Object o) { 534 if (o instanceof byte[]) { 535 return Arrays.hashCode((byte[]) o); 536 } 537 return o.hashCode(); 538 } 539 540 // This avoids having to make FieldArray public. cloneUnknownFieldData(ExtendableMessageNano original, ExtendableMessageNano cloned)541 public static void cloneUnknownFieldData(ExtendableMessageNano original, 542 ExtendableMessageNano cloned) { 543 if (original.unknownFieldData != null) { 544 cloned.unknownFieldData = (FieldArray) original.unknownFieldData.clone(); 545 } 546 } 547 } 548