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