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 /** 11 * RawMessageInfo stores the same amount of information as {@link MessageInfo} but in a more compact 12 * format. 13 */ 14 @CheckReturnValue 15 final class RawMessageInfo implements MessageInfo { 16 private static final int IS_PROTO2_BIT = 0x1; 17 private static final int IS_EDITION_BIT = 0x4; 18 19 private final MessageLite defaultInstance; 20 21 /** 22 * The compact format packs everything in a String object and a Object[] array. The String object 23 * is encoded with field number, field type, hasbits offset, oneof index, etc., whereas the 24 * Object[] array contains field references, class references, instance references, etc. 25 * 26 * <p>The String object encodes a sequence of integers into UTF-16 characters. For each int, it 27 * will be encoding into 1 to 3 UTF-16 characters depending on its unsigned value: 28 * 29 * <ul> 30 * <li>1 char: [c1: 0x0000 - 0xD7FF] = int of the same value. 31 * <li>2 chars: [c1: 0xE000 - 0xFFFF], [c2: 0x0000 - 0xD7FF] = (c2 << 13) | (c1 & 0x1FFF) 32 * <li>3 chars: [c1: 0xE000 - 0xFFFF], [c2: 0xE000 - 0xFFFF], [c3: 0x0000 - 0xD7FF] = (c3 << 26) 33 * | ((c2 & 0x1FFF) << 13) | (c1 & 0x1FFF) 34 * </ul> 35 * 36 * <p>Note that we don't use UTF-16 surrogate pairs [0xD800 - 0xDFFF] because they have to come in 37 * pairs to form a valid UTF-16char sequence and don't help us encode values more efficiently. 38 * 39 * <p>The integer sequence encoded in the String object has the following layout: 40 * 41 * <ul> 42 * <li>[0]: flags, flags & 0x1 = is proto2?, flags & 0x2 = is message?, flags & 0x4 = is 43 * edition? 44 * <li>[1]: field count, if 0, this is the end of the integer sequence and the corresponding 45 * Object[] array should be null. 46 * <li>[2]: oneof count 47 * <li>[3]: hasbits count, how many hasbits integers are generated. 48 * <li>[4]: min field number 49 * <li>[5]: max field number 50 * <li>[6]: total number of entries need to allocate 51 * <li>[7]: map field count 52 * <li>[8]: repeated field count, this doesn't include map fields. 53 * <li>[9]: size of checkInitialized array 54 * <li>[...]: field entries 55 * </ul> 56 * 57 * <p>Each field entry starts with a field number and the field type: 58 * 59 * <ul> 60 * <li>[0]: field number 61 * <li>[1]: field type with extra bits: 62 * <ul> 63 * <li>v & 0xFF = field type as defined in the FieldType class 64 * <li>v & 0x0100 = is required? 65 * <li>v & 0x0200 = is checkUtf8? 66 * <li>v & 0x0400 = needs isInitialized check? 67 * <li>v & 0x0800 = is enum field or map field enum value with legacy closedness? 68 * <li>v & 0x1000 = supports presence checking? 69 * </ul> 70 * </ul> 71 * 72 * If the (singular) field supports presence checking: 73 * 74 * <ul> 75 * <li>[2]: hasbits offset 76 * </ul> 77 * 78 * If the field is in an oneof: 79 * 80 * <ul> 81 * <li>[2]: oneof index 82 * </ul> 83 * 84 * For other types, the field entry only has field number and field type. 85 * 86 * <p>The Object[] array has 3 sections: 87 * 88 * <ul> 89 * <li>---- oneof section ---- 90 * <ul> 91 * <li>[0]: value field for oneof 1. 92 * <li>[1]: case field for oneof 1. 93 * <li>... 94 * <li>[.]: value field for oneof n. 95 * <li>[.]: case field for oneof n. 96 * </ul> 97 * <li>---- hasbits section ---- 98 * <ul> 99 * <li>[.]: hasbits field 1 100 * <li>[.]: hasbits field 2 101 * <li>... 102 * <li>[.]: hasbits field n 103 * </ul> 104 * <li>---- field section ---- 105 * <ul> 106 * <li>[...]: field entries 107 * </ul> 108 * </ul> 109 * 110 * <p>In the Object[] array, field entries are ordered in the same way as field entries in the 111 * String object. The size of each entry is determined by the field type. 112 * 113 * <ul> 114 * <li>Oneof field: 115 * <ul> 116 * <li>Oneof message field: 117 * <ul> 118 * <li>[0]: message class reference. 119 * </ul> 120 * <li>Oneof enum fieldin proto2: 121 * <ul> 122 * <li>[0]: EnumLiteMap 123 * </ul> 124 * <li>For all other oneof fields, field entry in the Object[] array is empty. 125 * </ul> 126 * <li>Repeated message field: 127 * <ul> 128 * <li>[0]: field reference 129 * <li>[1]: message class reference 130 * </ul> 131 * <li>Proto2 singular/repeated enum field: 132 * <ul> 133 * <li>[0]: field reference 134 * <li>[1]: EnumLiteMap 135 * </ul> 136 * <li>Map field with a proto2 enum value: 137 * <ul> 138 * <li>[0]: field reference 139 * <li>[1]: map default entry instance 140 * <li>[2]: EnumLiteMap 141 * </ul> 142 * <li>Map field with other value types: 143 * <ul> 144 * <li>[0]: field reference 145 * <li>[1]: map default entry instance 146 * </ul> 147 * <li>All other field type: 148 * <ul> 149 * <li>[0]: field reference 150 * </ul> 151 * </ul> 152 * 153 * <p>In order to read the field info from this compact format, a reader needs to progress through 154 * the String object and the Object[] array simultaneously. 155 */ 156 private final String info; 157 158 private final Object[] objects; 159 private final int flags; 160 RawMessageInfo(MessageLite defaultInstance, String info, Object[] objects)161 RawMessageInfo(MessageLite defaultInstance, String info, Object[] objects) { 162 this.defaultInstance = defaultInstance; 163 this.info = info; 164 this.objects = objects; 165 int position = 0; 166 int value = (int) info.charAt(position++); 167 if (value < 0xD800) { 168 flags = value; 169 } else { 170 int result = value & 0x1FFF; 171 int shift = 13; 172 while ((value = info.charAt(position++)) >= 0xD800) { 173 result |= (value & 0x1FFF) << shift; 174 shift += 13; 175 } 176 flags = result | (value << shift); 177 } 178 } 179 getStringInfo()180 String getStringInfo() { 181 return info; 182 } 183 getObjects()184 Object[] getObjects() { 185 return objects; 186 } 187 188 @Override getDefaultInstance()189 public MessageLite getDefaultInstance() { 190 return defaultInstance; 191 } 192 193 @Override getSyntax()194 public ProtoSyntax getSyntax() { 195 if ((flags & IS_PROTO2_BIT) != 0) { 196 return ProtoSyntax.PROTO2; 197 } else if ((flags & IS_EDITION_BIT) == 0x4) { 198 return ProtoSyntax.EDITIONS; 199 } else { 200 return ProtoSyntax.PROTO3; 201 } 202 } 203 204 @Override isMessageSetWireFormat()205 public boolean isMessageSetWireFormat() { 206 return (flags & 0x2) == 0x2; 207 } 208 } 209