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; 32 33 import java.io.IOException; 34 import java.util.Iterator; 35 import java.util.Map.Entry; 36 37 /** Schema used for proto2 messages using message_set_wireformat. */ 38 final class MessageSetSchema<T> implements Schema<T> { 39 private final MessageLite defaultInstance; 40 private final UnknownFieldSchema<?, ?> unknownFieldSchema; 41 private final boolean hasExtensions; 42 private final ExtensionSchema<?> extensionSchema; 43 MessageSetSchema( UnknownFieldSchema<?, ?> unknownFieldSchema, ExtensionSchema<?> extensionSchema, MessageLite defaultInstance)44 private MessageSetSchema( 45 UnknownFieldSchema<?, ?> unknownFieldSchema, 46 ExtensionSchema<?> extensionSchema, 47 MessageLite defaultInstance) { 48 this.unknownFieldSchema = unknownFieldSchema; 49 this.hasExtensions = extensionSchema.hasExtensions(defaultInstance); 50 this.extensionSchema = extensionSchema; 51 this.defaultInstance = defaultInstance; 52 } 53 newSchema( UnknownFieldSchema<?, ?> unknownFieldSchema, ExtensionSchema<?> extensionSchema, MessageLite defaultInstance)54 static <T> MessageSetSchema<T> newSchema( 55 UnknownFieldSchema<?, ?> unknownFieldSchema, 56 ExtensionSchema<?> extensionSchema, 57 MessageLite defaultInstance) { 58 return new MessageSetSchema<T>(unknownFieldSchema, extensionSchema, defaultInstance); 59 } 60 61 @SuppressWarnings("unchecked") 62 @Override newInstance()63 public T newInstance() { 64 return (T) defaultInstance.newBuilderForType().buildPartial(); 65 } 66 67 @Override equals(T message, T other)68 public boolean equals(T message, T other) { 69 Object messageUnknown = unknownFieldSchema.getFromMessage(message); 70 Object otherUnknown = unknownFieldSchema.getFromMessage(other); 71 if (!messageUnknown.equals(otherUnknown)) { 72 return false; 73 } 74 if (hasExtensions) { 75 FieldSet<?> messageExtensions = extensionSchema.getExtensions(message); 76 FieldSet<?> otherExtensions = extensionSchema.getExtensions(other); 77 return messageExtensions.equals(otherExtensions); 78 } 79 return true; 80 } 81 82 @Override hashCode(T message)83 public int hashCode(T message) { 84 int hashCode = unknownFieldSchema.getFromMessage(message).hashCode(); 85 if (hasExtensions) { 86 FieldSet<?> extensions = extensionSchema.getExtensions(message); 87 hashCode = (hashCode * 53) + extensions.hashCode(); 88 } 89 return hashCode; 90 } 91 92 @Override mergeFrom(T message, T other)93 public void mergeFrom(T message, T other) { 94 SchemaUtil.mergeUnknownFields(unknownFieldSchema, message, other); 95 if (hasExtensions) { 96 SchemaUtil.mergeExtensions(extensionSchema, message, other); 97 } 98 } 99 100 @SuppressWarnings("unchecked") 101 @Override writeTo(T message, Writer writer)102 public void writeTo(T message, Writer writer) throws IOException { 103 FieldSet<?> extensions = extensionSchema.getExtensions(message); 104 Iterator<?> iterator = extensions.iterator(); 105 while (iterator.hasNext()) { 106 Entry<?, ?> extension = (Entry<?, ?>) iterator.next(); 107 FieldSet.FieldDescriptorLite<?> fd = (FieldSet.FieldDescriptorLite<?>) extension.getKey(); 108 if (fd.getLiteJavaType() != WireFormat.JavaType.MESSAGE || fd.isRepeated() || fd.isPacked()) { 109 throw new IllegalStateException("Found invalid MessageSet item."); 110 } 111 if (extension instanceof LazyField.LazyEntry) { 112 writer.writeMessageSetItem( 113 fd.getNumber(), ((LazyField.LazyEntry) extension).getField().toByteString()); 114 } else { 115 writer.writeMessageSetItem(fd.getNumber(), extension.getValue()); 116 } 117 } 118 writeUnknownFieldsHelper(unknownFieldSchema, message, writer); 119 } 120 121 /** 122 * A helper method for wildcard capture of {@code unknownFieldSchema}. See: 123 * https://docs.oracle.com/javase/tutorial/java/generics/capture.html 124 */ writeUnknownFieldsHelper( UnknownFieldSchema<UT, UB> unknownFieldSchema, T message, Writer writer)125 private <UT, UB> void writeUnknownFieldsHelper( 126 UnknownFieldSchema<UT, UB> unknownFieldSchema, T message, Writer writer) throws IOException { 127 unknownFieldSchema.writeAsMessageSetTo(unknownFieldSchema.getFromMessage(message), writer); 128 } 129 130 @SuppressWarnings("ReferenceEquality") 131 @Override mergeFrom( T message, byte[] data, int position, int limit, ArrayDecoders.Registers registers)132 public void mergeFrom( 133 T message, byte[] data, int position, int limit, ArrayDecoders.Registers registers) 134 throws IOException { 135 UnknownFieldSetLite unknownFields = ((GeneratedMessageLite) message).unknownFields; 136 if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) { 137 unknownFields = UnknownFieldSetLite.newInstance(); 138 ((GeneratedMessageLite) message).unknownFields = unknownFields; 139 } 140 final FieldSet<GeneratedMessageLite.ExtensionDescriptor> extensions = 141 ((GeneratedMessageLite.ExtendableMessage<?, ?>) message).ensureExtensionsAreMutable(); 142 GeneratedMessageLite.GeneratedExtension<?, ?> extension = null; 143 while (position < limit) { 144 position = ArrayDecoders.decodeVarint32(data, position, registers); 145 final int startTag = registers.int1; 146 if (startTag != WireFormat.MESSAGE_SET_ITEM_TAG) { 147 if (WireFormat.getTagWireType(startTag) == WireFormat.WIRETYPE_LENGTH_DELIMITED) { 148 extension = 149 (GeneratedMessageLite.GeneratedExtension<?, ?>) extensionSchema.findExtensionByNumber( 150 registers.extensionRegistry, defaultInstance, 151 WireFormat.getTagFieldNumber(startTag)); 152 if (extension != null) { 153 position = 154 ArrayDecoders.decodeMessageField( 155 Protobuf.getInstance().schemaFor( 156 extension.getMessageDefaultInstance().getClass()), 157 data, position, limit, registers); 158 extensions.setField(extension.descriptor, registers.object1); 159 } else { 160 position = 161 ArrayDecoders.decodeUnknownField( 162 startTag, data, position, limit, unknownFields, registers); 163 } 164 } else { 165 position = ArrayDecoders.skipField(startTag, data, position, limit, registers); 166 } 167 continue; 168 } 169 170 int typeId = 0; 171 ByteString rawBytes = null; 172 173 while (position < limit) { 174 position = ArrayDecoders.decodeVarint32(data, position, registers); 175 final int tag = registers.int1; 176 final int number = WireFormat.getTagFieldNumber(tag); 177 final int wireType = WireFormat.getTagWireType(tag); 178 switch (number) { 179 case WireFormat.MESSAGE_SET_TYPE_ID: 180 if (wireType == WireFormat.WIRETYPE_VARINT) { 181 position = ArrayDecoders.decodeVarint32(data, position, registers); 182 typeId = registers.int1; 183 extension = 184 (GeneratedMessageLite.GeneratedExtension<?, ?>) extensionSchema 185 .findExtensionByNumber(registers.extensionRegistry, defaultInstance, typeId); 186 continue; 187 } 188 break; 189 case WireFormat.MESSAGE_SET_MESSAGE: 190 if (extension != null) { 191 position = ArrayDecoders.decodeMessageField( 192 Protobuf.getInstance().schemaFor( 193 extension.getMessageDefaultInstance().getClass()), 194 data, position, limit, registers); 195 extensions.setField(extension.descriptor, registers.object1); 196 continue; 197 } else { 198 if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { 199 position = ArrayDecoders.decodeBytes(data, position, registers); 200 rawBytes = (ByteString) registers.object1; 201 continue; 202 } 203 break; 204 } 205 default: 206 break; 207 } 208 if (tag == WireFormat.MESSAGE_SET_ITEM_END_TAG) { 209 break; 210 } 211 position = ArrayDecoders.skipField(tag, data, position, limit, registers); 212 } 213 214 if (rawBytes != null) { 215 unknownFields.storeField( 216 WireFormat.makeTag(typeId, WireFormat.WIRETYPE_LENGTH_DELIMITED), rawBytes); 217 } 218 } 219 if (position != limit) { 220 throw InvalidProtocolBufferException.parseFailure(); 221 } 222 } 223 224 @Override mergeFrom(T message, Reader reader, ExtensionRegistryLite extensionRegistry)225 public void mergeFrom(T message, Reader reader, ExtensionRegistryLite extensionRegistry) 226 throws IOException { 227 mergeFromHelper(unknownFieldSchema, extensionSchema, message, reader, extensionRegistry); 228 } 229 230 /** 231 * A helper method for wildcard capture of {@code unknownFieldSchema}. See: 232 * https://docs.oracle.com/javase/tutorial/java/generics/capture.html 233 */ 234 @SuppressWarnings("unchecked") mergeFromHelper( UnknownFieldSchema<UT, UB> unknownFieldSchema, ExtensionSchema<ET> extensionSchema, T message, Reader reader, ExtensionRegistryLite extensionRegistry)235 private <UT, UB, ET extends FieldSet.FieldDescriptorLite<ET>> void mergeFromHelper( 236 UnknownFieldSchema<UT, UB> unknownFieldSchema, 237 ExtensionSchema<ET> extensionSchema, 238 T message, 239 Reader reader, 240 ExtensionRegistryLite extensionRegistry) 241 throws IOException { 242 UB unknownFields = unknownFieldSchema.getBuilderFromMessage(message); 243 FieldSet<ET> extensions = extensionSchema.getMutableExtensions(message); 244 try { 245 while (true) { 246 final int number = reader.getFieldNumber(); 247 if (number == Reader.READ_DONE) { 248 return; 249 } 250 if (parseMessageSetItemOrUnknownField( 251 reader, 252 extensionRegistry, 253 extensionSchema, 254 extensions, 255 unknownFieldSchema, 256 unknownFields)) { 257 continue; 258 } 259 // Done reading. 260 return; 261 } 262 } finally { 263 unknownFieldSchema.setBuilderToMessage(message, unknownFields); 264 } 265 } 266 267 @Override makeImmutable(T message)268 public void makeImmutable(T message) { 269 unknownFieldSchema.makeImmutable(message); 270 extensionSchema.makeImmutable(message); 271 } 272 273 private <UT, UB, ET extends FieldSet.FieldDescriptorLite<ET>> parseMessageSetItemOrUnknownField( Reader reader, ExtensionRegistryLite extensionRegistry, ExtensionSchema<ET> extensionSchema, FieldSet<ET> extensions, UnknownFieldSchema<UT, UB> unknownFieldSchema, UB unknownFields)274 boolean parseMessageSetItemOrUnknownField( 275 Reader reader, 276 ExtensionRegistryLite extensionRegistry, 277 ExtensionSchema<ET> extensionSchema, 278 FieldSet<ET> extensions, 279 UnknownFieldSchema<UT, UB> unknownFieldSchema, 280 UB unknownFields) 281 throws IOException { 282 int startTag = reader.getTag(); 283 if (startTag != WireFormat.MESSAGE_SET_ITEM_TAG) { 284 if (WireFormat.getTagWireType(startTag) == WireFormat.WIRETYPE_LENGTH_DELIMITED) { 285 Object extension = 286 extensionSchema.findExtensionByNumber( 287 extensionRegistry, defaultInstance, WireFormat.getTagFieldNumber(startTag)); 288 if (extension != null) { 289 extensionSchema.parseLengthPrefixedMessageSetItem( 290 reader, extension, extensionRegistry, extensions); 291 return true; 292 } else { 293 return unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader); 294 } 295 } else { 296 return reader.skipField(); 297 } 298 } 299 300 // The wire format for MessageSet is: 301 // message MessageSet { 302 // repeated group Item = 1 { 303 // required int32 typeId = 2; 304 // required bytes message = 3; 305 // } 306 // } 307 // "typeId" is the extension's field number. The extension can only be 308 // a message type, where "message" contains the encoded bytes of that 309 // message. 310 // 311 // In practice, we will probably never see a MessageSet item in which 312 // the message appears before the type ID, or where either field does not 313 // appear exactly once. However, in theory such cases are valid, so we 314 // should be prepared to accept them. 315 316 int typeId = 0; 317 ByteString rawBytes = null; // If we encounter "message" before "typeId" 318 Object extension = null; 319 320 // Read bytes from input, if we get it's type first then parse it eagerly, 321 // otherwise we store the raw bytes in a local variable. 322 loop: 323 while (true) { 324 final int number = reader.getFieldNumber(); 325 if (number == Reader.READ_DONE) { 326 break; 327 } 328 329 final int tag = reader.getTag(); 330 if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) { 331 typeId = reader.readUInt32(); 332 extension = 333 extensionSchema.findExtensionByNumber(extensionRegistry, defaultInstance, typeId); 334 continue; 335 } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) { 336 if (extension != null) { 337 extensionSchema.parseLengthPrefixedMessageSetItem( 338 reader, extension, extensionRegistry, extensions); 339 continue; 340 } 341 // We haven't seen a type ID yet or we want parse message lazily. 342 rawBytes = reader.readBytes(); 343 continue; 344 } else { 345 if (!reader.skipField()) { 346 break loop; // End of group 347 } 348 } 349 } 350 351 if (reader.getTag() != WireFormat.MESSAGE_SET_ITEM_END_TAG) { 352 throw InvalidProtocolBufferException.invalidEndTag(); 353 } 354 355 // If there are any rawBytes left, it means the message content appears before the type ID. 356 if (rawBytes != null) { 357 if (extension != null) { // We known the type 358 // TODO(xiaofeng): Instead of reading into a temporary ByteString, maybe there is a way 359 // to read directly from Reader to the submessage? 360 extensionSchema.parseMessageSetItem(rawBytes, extension, extensionRegistry, extensions); 361 } else { 362 unknownFieldSchema.addLengthDelimited(unknownFields, typeId, rawBytes); 363 } 364 } 365 return true; 366 } 367 368 @Override isInitialized(T message)369 public final boolean isInitialized(T message) { 370 FieldSet<?> extensions = extensionSchema.getExtensions(message); 371 return extensions.isInitialized(); 372 } 373 374 @Override getSerializedSize(T message)375 public int getSerializedSize(T message) { 376 int size = 0; 377 378 size += getUnknownFieldsSerializedSize(unknownFieldSchema, message); 379 380 if (hasExtensions) { 381 size += extensionSchema.getExtensions(message).getMessageSetSerializedSize(); 382 } 383 384 return size; 385 } 386 getUnknownFieldsSerializedSize( UnknownFieldSchema<UT, UB> schema, T message)387 private <UT, UB> int getUnknownFieldsSerializedSize( 388 UnknownFieldSchema<UT, UB> schema, T message) { 389 UT unknowns = schema.getFromMessage(message); 390 return schema.getSerializedSizeAsMessageSet(unknowns); 391 } 392 } 393