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