1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2014 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 java.io.IOException; 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.List; 37 38 /** 39 * Stores unknown fields. These might be extensions or fields that the generated API doesn't 40 * know about yet. 41 */ 42 class FieldData implements Cloneable { 43 private Extension<?, ?> cachedExtension; 44 private Object value; 45 /** The serialised values for this object. Will be cleared if getValue is called */ 46 private List<UnknownFieldData> unknownFieldData; 47 FieldData(Extension<?, T> extension, T newValue)48 <T> FieldData(Extension<?, T> extension, T newValue) { 49 cachedExtension = extension; 50 value = newValue; 51 } 52 FieldData()53 FieldData() { 54 unknownFieldData = new ArrayList<UnknownFieldData>(); 55 } 56 addUnknownField(UnknownFieldData unknownField)57 void addUnknownField(UnknownFieldData unknownField) { 58 unknownFieldData.add(unknownField); 59 } 60 getUnknownField(int index)61 UnknownFieldData getUnknownField(int index) { 62 if (unknownFieldData == null) { 63 return null; 64 } 65 if (index < unknownFieldData.size()) { 66 return unknownFieldData.get(index); 67 } 68 return null; 69 } 70 getUnknownFieldSize()71 int getUnknownFieldSize() { 72 if (unknownFieldData == null) { 73 return 0; 74 } 75 return unknownFieldData.size(); 76 } 77 getValue(Extension<?, T> extension)78 <T> T getValue(Extension<?, T> extension) { 79 if (value != null){ 80 if (cachedExtension != extension) { // Extension objects are singletons. 81 throw new IllegalStateException( 82 "Tried to getExtension with a differernt Extension."); 83 } 84 } else { 85 cachedExtension = extension; 86 value = extension.getValueFrom(unknownFieldData); 87 unknownFieldData = null; 88 } 89 return (T) value; 90 } 91 setValue(Extension<?, T> extension, T newValue)92 <T> void setValue(Extension<?, T> extension, T newValue) { 93 cachedExtension = extension; 94 value = newValue; 95 unknownFieldData = null; 96 } 97 computeSerializedSize()98 int computeSerializedSize() { 99 int size = 0; 100 if (value != null) { 101 size = cachedExtension.computeSerializedSize(value); 102 } else { 103 for (UnknownFieldData unknownField : unknownFieldData) { 104 size += unknownField.computeSerializedSize(); 105 } 106 } 107 return size; 108 } 109 writeTo(CodedOutputByteBufferNano output)110 void writeTo(CodedOutputByteBufferNano output) throws IOException { 111 if (value != null) { 112 cachedExtension.writeTo(value, output); 113 } else { 114 for (UnknownFieldData unknownField : unknownFieldData) { 115 unknownField.writeTo(output); 116 } 117 } 118 } 119 120 @Override equals(Object o)121 public boolean equals(Object o) { 122 if (o == this) { 123 return true; 124 } 125 if (!(o instanceof FieldData)) { 126 return false; 127 } 128 129 FieldData other = (FieldData) o; 130 if (value != null && other.value != null) { 131 // If both objects have deserialized values, compare those. 132 // Since unknown fields are only compared if messages have generated equals methods 133 // we know this will be a meaningful comparison (not identity) for all values. 134 if (cachedExtension != other.cachedExtension) { // Extension objects are singletons. 135 return false; 136 } 137 if (!cachedExtension.clazz.isArray()) { 138 // Can't test (!cachedExtension.repeated) due to 'bytes' -> 'byte[]' 139 return value.equals(other.value); 140 } 141 if (value instanceof byte[]) { 142 return Arrays.equals((byte[]) value, (byte[]) other.value); 143 } else if (value instanceof int[]) { 144 return Arrays.equals((int[]) value, (int[]) other.value); 145 } else if (value instanceof long[]) { 146 return Arrays.equals((long[]) value, (long[]) other.value); 147 } else if (value instanceof float[]) { 148 return Arrays.equals((float[]) value, (float[]) other.value); 149 } else if (value instanceof double[]) { 150 return Arrays.equals((double[]) value, (double[]) other.value); 151 } else if (value instanceof boolean[]) { 152 return Arrays.equals((boolean[]) value, (boolean[]) other.value); 153 } else { 154 return Arrays.deepEquals((Object[]) value, (Object[]) other.value); 155 } 156 } 157 if (unknownFieldData != null && other.unknownFieldData != null) { 158 // If both objects have byte arrays compare those directly. 159 return unknownFieldData.equals(other.unknownFieldData); 160 } 161 try { 162 // As a last resort, serialize and compare the resulting byte arrays. 163 return Arrays.equals(toByteArray(), other.toByteArray()); 164 } catch (IOException e) { 165 // Should not happen. 166 throw new IllegalStateException(e); 167 } 168 } 169 170 @Override hashCode()171 public int hashCode() { 172 int result = 17; 173 try { 174 // The only way to generate a consistent hash is to use the serialized form. 175 result = 31 * result + Arrays.hashCode(toByteArray()); 176 } catch (IOException e) { 177 // Should not happen. 178 throw new IllegalStateException(e); 179 } 180 return result; 181 } 182 toByteArray()183 private byte[] toByteArray() throws IOException { 184 byte[] result = new byte[computeSerializedSize()]; 185 CodedOutputByteBufferNano output = CodedOutputByteBufferNano.newInstance(result); 186 writeTo(output); 187 return result; 188 } 189 190 @Override clone()191 public final FieldData clone() { 192 FieldData clone = new FieldData(); 193 try { 194 clone.cachedExtension = cachedExtension; 195 if (unknownFieldData == null) { 196 clone.unknownFieldData = null; 197 } else { 198 clone.unknownFieldData.addAll(unknownFieldData); 199 } 200 201 // Whether we need to deep clone value depends on its type. Primitive reference types 202 // (e.g. Integer, Long etc.) are ok, since they're immutable. We need to clone arrays 203 // and messages. 204 if (value == null) { 205 // No cloning required. 206 } else if (value instanceof MessageNano) { 207 clone.value = ((MessageNano) value).clone(); 208 } else if (value instanceof byte[]) { 209 clone.value = ((byte[]) value).clone(); 210 } else if (value instanceof byte[][]) { 211 byte[][] valueArray = (byte[][]) value; 212 byte[][] cloneArray = new byte[valueArray.length][]; 213 clone.value = cloneArray; 214 for (int i = 0; i < valueArray.length; i++) { 215 cloneArray[i] = valueArray[i].clone(); 216 } 217 } else if (value instanceof boolean[]) { 218 clone.value = ((boolean[]) value).clone(); 219 } else if (value instanceof int[]) { 220 clone.value = ((int[]) value).clone(); 221 } else if (value instanceof long[]) { 222 clone.value = ((long[]) value).clone(); 223 } else if (value instanceof float[]) { 224 clone.value = ((float[]) value).clone(); 225 } else if (value instanceof double[]) { 226 clone.value = ((double[]) value).clone(); 227 } else if (value instanceof MessageNano[]) { 228 MessageNano[] valueArray = (MessageNano[]) value; 229 MessageNano[] cloneArray = new MessageNano[valueArray.length]; 230 clone.value = cloneArray; 231 for (int i = 0; i < valueArray.length; i++) { 232 cloneArray[i] = valueArray[i].clone(); 233 } 234 } 235 return clone; 236 } catch (CloneNotSupportedException e) { 237 throw new AssertionError(e); 238 } 239 } 240 } 241