• 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 import java.io.IOException;
11 
12 /**
13  * This class is used internally by the Protocol Buffer library and generated message
14  * implementations. It is public only because those generated messages do not reside in the {@code
15  * protobuf} package. Others should not use this class directly.
16  *
17  * <p>This class contains constants and helper functions useful for dealing with the Protocol Buffer
18  * wire format.
19  *
20  * @author kenton@google.com Kenton Varda
21  */
22 public final class WireFormat {
23   // Do not allow instantiation.
WireFormat()24   private WireFormat() {}
25 
26   static final int FIXED32_SIZE = 4;
27   static final int FIXED64_SIZE = 8;
28   static final int MAX_VARINT32_SIZE = 5;
29   static final int MAX_VARINT64_SIZE = 10;
30   static final int MAX_VARINT_SIZE = 10;
31 
32   public static final int WIRETYPE_VARINT = 0;
33   public static final int WIRETYPE_FIXED64 = 1;
34   public static final int WIRETYPE_LENGTH_DELIMITED = 2;
35   public static final int WIRETYPE_START_GROUP = 3;
36   public static final int WIRETYPE_END_GROUP = 4;
37   public static final int WIRETYPE_FIXED32 = 5;
38 
39   static final int TAG_TYPE_BITS = 3;
40   static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
41 
42   /** Given a tag value, determines the wire type (the lower 3 bits). */
getTagWireType(final int tag)43   public static int getTagWireType(final int tag) {
44     return tag & TAG_TYPE_MASK;
45   }
46 
47   /** Given a tag value, determines the field number (the upper 29 bits). */
getTagFieldNumber(final int tag)48   public static int getTagFieldNumber(final int tag) {
49     return tag >>> TAG_TYPE_BITS;
50   }
51 
52   /** Makes a tag value given a field number and wire type. */
makeTag(final int fieldNumber, final int wireType)53   static int makeTag(final int fieldNumber, final int wireType) {
54     return (fieldNumber << TAG_TYPE_BITS) | wireType;
55   }
56 
57   /**
58    * Lite equivalent to {@link Descriptors.FieldDescriptor.JavaType}. This is only here to support
59    * the lite runtime and should not be used by users.
60    */
61   public enum JavaType {
62     INT(0),
63     LONG(0L),
64     FLOAT(0F),
65     DOUBLE(0D),
66     BOOLEAN(false),
67     STRING(""),
68     BYTE_STRING(ByteString.EMPTY),
69     ENUM(null),
70     MESSAGE(null);
71 
JavaType(final Object defaultDefault)72     JavaType(final Object defaultDefault) {
73       this.defaultDefault = defaultDefault;
74     }
75 
76     /** The default default value for fields of this type, if it's a primitive type. */
getDefaultDefault()77     Object getDefaultDefault() {
78       return defaultDefault;
79     }
80 
81     private final Object defaultDefault;
82   }
83 
84   /**
85    * Lite equivalent to {@link Descriptors.FieldDescriptor.Type}. This is only here to support the
86    * lite runtime and should not be used by users.
87    */
88   public enum FieldType {
89     DOUBLE(JavaType.DOUBLE, WIRETYPE_FIXED64),
90     FLOAT(JavaType.FLOAT, WIRETYPE_FIXED32),
91     INT64(JavaType.LONG, WIRETYPE_VARINT),
92     UINT64(JavaType.LONG, WIRETYPE_VARINT),
93     INT32(JavaType.INT, WIRETYPE_VARINT),
94     FIXED64(JavaType.LONG, WIRETYPE_FIXED64),
95     FIXED32(JavaType.INT, WIRETYPE_FIXED32),
96     BOOL(JavaType.BOOLEAN, WIRETYPE_VARINT),
STRING(JavaType.STRING, WIRETYPE_LENGTH_DELIMITED)97     STRING(JavaType.STRING, WIRETYPE_LENGTH_DELIMITED) {
98       @Override
99       public boolean isPackable() {
100         return false;
101       }
102     },
GROUP(JavaType.MESSAGE, WIRETYPE_START_GROUP)103     GROUP(JavaType.MESSAGE, WIRETYPE_START_GROUP) {
104       @Override
105       public boolean isPackable() {
106         return false;
107       }
108     },
MESSAGE(JavaType.MESSAGE, WIRETYPE_LENGTH_DELIMITED)109     MESSAGE(JavaType.MESSAGE, WIRETYPE_LENGTH_DELIMITED) {
110       @Override
111       public boolean isPackable() {
112         return false;
113       }
114     },
BYTES(JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED)115     BYTES(JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED) {
116       @Override
117       public boolean isPackable() {
118         return false;
119       }
120     },
121     UINT32(JavaType.INT, WIRETYPE_VARINT),
122     ENUM(JavaType.ENUM, WIRETYPE_VARINT),
123     SFIXED32(JavaType.INT, WIRETYPE_FIXED32),
124     SFIXED64(JavaType.LONG, WIRETYPE_FIXED64),
125     SINT32(JavaType.INT, WIRETYPE_VARINT),
126     SINT64(JavaType.LONG, WIRETYPE_VARINT);
127 
FieldType(final JavaType javaType, final int wireType)128     FieldType(final JavaType javaType, final int wireType) {
129       this.javaType = javaType;
130       this.wireType = wireType;
131     }
132 
133     private final JavaType javaType;
134     private final int wireType;
135 
getJavaType()136     public JavaType getJavaType() {
137       return javaType;
138     }
139 
getWireType()140     public int getWireType() {
141       return wireType;
142     }
143 
isPackable()144     public boolean isPackable() {
145       return true;
146     }
147   }
148 
149   // Field numbers for fields in MessageSet wire format.
150   static final int MESSAGE_SET_ITEM = 1;
151   static final int MESSAGE_SET_TYPE_ID = 2;
152   static final int MESSAGE_SET_MESSAGE = 3;
153 
154   // Tag numbers.
155   static final int MESSAGE_SET_ITEM_TAG = makeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP);
156   static final int MESSAGE_SET_ITEM_END_TAG = makeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP);
157   static final int MESSAGE_SET_TYPE_ID_TAG = makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
158   static final int MESSAGE_SET_MESSAGE_TAG =
159       makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
160 
161   /**
162    * Validation level for handling incoming string field data which potentially contain non-UTF8
163    * bytes.
164    */
165   enum Utf8Validation {
166     /** Eagerly parses to String; silently accepts invalid UTF8 bytes. */
167     LOOSE {
168       @Override
readString(CodedInputStream input)169       Object readString(CodedInputStream input) throws IOException {
170         return input.readString();
171       }
172     },
173     /** Eagerly parses to String; throws an IOException on invalid bytes. */
174     STRICT {
175       @Override
readString(CodedInputStream input)176       Object readString(CodedInputStream input) throws IOException {
177         return input.readStringRequireUtf8();
178       }
179     },
180     /** Keep data as ByteString; validation/conversion to String is lazy. */
181     LAZY {
182       @Override
readString(CodedInputStream input)183       Object readString(CodedInputStream input) throws IOException {
184         return input.readBytes();
185       }
186     };
187 
188     /** Read a string field from the input with the proper UTF8 validation. */
readString(CodedInputStream input)189     abstract Object readString(CodedInputStream input) throws IOException;
190   }
191 
192   /**
193    * Read a field of any primitive type for immutable messages from a CodedInputStream. Enums,
194    * groups, and embedded messages are not handled by this method.
195    *
196    * @param input The stream from which to read.
197    * @param type Declared type of the field.
198    * @param utf8Validation Different string UTF8 validation level for handling string fields.
199    * @return An object representing the field's value, of the exact type which would be returned by
200    *     {@link Message#getField(Descriptors.FieldDescriptor)} for this field.
201    */
readPrimitiveField( CodedInputStream input, FieldType type, Utf8Validation utf8Validation)202   static Object readPrimitiveField(
203       CodedInputStream input, FieldType type, Utf8Validation utf8Validation) throws IOException {
204     switch (type) {
205       case DOUBLE:
206         return input.readDouble();
207       case FLOAT:
208         return input.readFloat();
209       case INT64:
210         return input.readInt64();
211       case UINT64:
212         return input.readUInt64();
213       case INT32:
214         return input.readInt32();
215       case FIXED64:
216         return input.readFixed64();
217       case FIXED32:
218         return input.readFixed32();
219       case BOOL:
220         return input.readBool();
221       case BYTES:
222         return input.readBytes();
223       case UINT32:
224         return input.readUInt32();
225       case SFIXED32:
226         return input.readSFixed32();
227       case SFIXED64:
228         return input.readSFixed64();
229       case SINT32:
230         return input.readSInt32();
231       case SINT64:
232         return input.readSInt64();
233 
234       case STRING:
235         return utf8Validation.readString(input);
236       case GROUP:
237         throw new IllegalArgumentException("readPrimitiveField() cannot handle nested groups.");
238       case MESSAGE:
239         throw new IllegalArgumentException("readPrimitiveField() cannot handle embedded messages.");
240       case ENUM:
241         // We don't handle enums because we don't know what to do if the
242         // value is not recognized.
243         throw new IllegalArgumentException("readPrimitiveField() cannot handle enums.");
244     }
245 
246     throw new RuntimeException("There is no way to get here, but the compiler thinks otherwise.");
247   }
248 }
249