• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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