1// Protocol Buffers - Google's data interchange format 2// Copyright 2013 Google Inc. All rights reserved. 3// http://code.google.com/p/protobuf/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are 7// met: 8// 9// * Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above 12// copyright notice, this list of conditions and the following disclaimer 13// in the documentation and/or other materials provided with the 14// distribution. 15// * Neither the name of Google Inc. nor the names of its 16// contributors may be used to endorse or promote products derived from 17// this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31package com.google.protobuf.nano; 32 33import java.io.IOException; 34import java.util.ArrayList; 35import java.util.Iterator; 36import java.util.List; 37 38/** 39 * This class is used internally by the Protocol Buffer library and generated 40 * message implementations. It is public only because those generated messages 41 * do not reside in the {@code protobuf} package. Others should not use this 42 * class directly. 43 * 44 * This class contains constants and helper functions useful for dealing with 45 * the Protocol Buffer wire format. 46 * 47 * @author kenton@google.com Kenton Varda 48 */ 49public final class WireFormatNano { 50 // Do not allow instantiation. 51 private WireFormatNano() {} 52 53 static final int WIRETYPE_VARINT = 0; 54 static final int WIRETYPE_FIXED64 = 1; 55 static final int WIRETYPE_LENGTH_DELIMITED = 2; 56 static final int WIRETYPE_START_GROUP = 3; 57 static final int WIRETYPE_END_GROUP = 4; 58 static final int WIRETYPE_FIXED32 = 5; 59 60 static final int TAG_TYPE_BITS = 3; 61 static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1; 62 63 /** Given a tag value, determines the wire type (the lower 3 bits). */ 64 static int getTagWireType(final int tag) { 65 return tag & TAG_TYPE_MASK; 66 } 67 68 /** Given a tag value, determines the field number (the upper 29 bits). */ 69 public static int getTagFieldNumber(final int tag) { 70 return tag >>> TAG_TYPE_BITS; 71 } 72 73 /** Makes a tag value given a field number and wire type. */ 74 static int makeTag(final int fieldNumber, final int wireType) { 75 return (fieldNumber << TAG_TYPE_BITS) | wireType; 76 } 77 78 // Field numbers for feilds in MessageSet wire format. 79 static final int MESSAGE_SET_ITEM = 1; 80 static final int MESSAGE_SET_TYPE_ID = 2; 81 static final int MESSAGE_SET_MESSAGE = 3; 82 83 // Tag numbers. 84 static final int MESSAGE_SET_ITEM_TAG = 85 makeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP); 86 static final int MESSAGE_SET_ITEM_END_TAG = 87 makeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP); 88 static final int MESSAGE_SET_TYPE_ID_TAG = 89 makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT); 90 static final int MESSAGE_SET_MESSAGE_TAG = 91 makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED); 92 93 public static final int EMPTY_INT_ARRAY[] = {}; 94 public static final long EMPTY_LONG_ARRAY[] = {}; 95 public static final float EMPTY_FLOAT_ARRAY[] = {}; 96 public static final double EMPTY_DOUBLE_ARRAY[] = {}; 97 public static final boolean EMPTY_BOOLEAN_ARRAY[] = {}; 98 public static final String EMPTY_STRING_ARRAY[] = {}; 99 public static final byte[] EMPTY_BYTES_ARRAY[] = {}; 100 public static final byte[] EMPTY_BYTES = {}; 101 102 /** 103 * Parses an unknown field. This implementation skips the field. 104 * 105 * <p>Generated messages will call this for unknown fields if the store_unknown_fields 106 * option is off. 107 * 108 * @return {@literal true} unless the tag is an end-group tag. 109 */ 110 public static boolean parseUnknownField( 111 final CodedInputByteBufferNano input, 112 final int tag) throws IOException { 113 return input.skipField(tag); 114 } 115 116 /** 117 * Stores the binary data of an unknown field. 118 * 119 * <p>Generated messages will call this for unknown fields if the store_unknown_fields 120 * option is on. 121 * 122 * @param data a Collection in which to store the data. 123 * @param input the input buffer. 124 * @param tag the tag of the field. 125 126 * @return {@literal true} unless the tag is an end-group tag. 127 */ 128 public static boolean storeUnknownField( 129 final List<UnknownFieldData> data, 130 final CodedInputByteBufferNano input, 131 final int tag) throws IOException { 132 int startPos = input.getPosition(); 133 boolean skip = input.skipField(tag); 134 int endPos = input.getPosition(); 135 byte[] bytes = input.getData(startPos, endPos - startPos); 136 data.add(new UnknownFieldData(tag, bytes)); 137 return skip; 138 } 139 140 /** 141 * Computes the array length of a repeated field. We assume that in the common case repeated 142 * fields are contiguously serialized but we still correctly handle interspersed values of a 143 * repeated field (but with extra allocations). 144 * 145 * Rewinds to current input position before returning. 146 * 147 * @param input stream input, pointing to the byte after the first tag 148 * @param tag repeated field tag just read 149 * @return length of array 150 * @throws IOException 151 */ 152 public static final int getRepeatedFieldArrayLength( 153 final CodedInputByteBufferNano input, 154 final int tag) throws IOException { 155 int arrayLength = 1; 156 int startPos = input.getPosition(); 157 input.skipField(tag); 158 while (input.getBytesUntilLimit() > 0) { 159 int thisTag = input.readTag(); 160 if (thisTag != tag) { 161 break; 162 } 163 input.skipField(tag); 164 arrayLength++; 165 } 166 input.rewindToPosition(startPos); 167 return arrayLength; 168 } 169 170 /** 171 * Decodes the value of an extension. 172 */ 173 public static <T> T getExtension(Extension<T> extension, List<UnknownFieldData> unknownFields) { 174 if (unknownFields == null) { 175 return null; 176 } 177 List<UnknownFieldData> dataForField = new ArrayList<UnknownFieldData>(); 178 for (UnknownFieldData data : unknownFields) { 179 if (getTagFieldNumber(data.tag) == extension.fieldNumber) { 180 dataForField.add(data); 181 } 182 } 183 if (dataForField.isEmpty()) { 184 return null; 185 } 186 187 if (extension.isRepeatedField) { 188 List<Object> result = new ArrayList<Object>(dataForField.size()); 189 for (UnknownFieldData data : dataForField) { 190 result.add(readData(extension.fieldType, data.bytes)); 191 } 192 return extension.listType.cast(result); 193 } 194 195 // Normal fields. Note that the protobuf docs require us to handle multiple instances 196 // of the same field even for fields that are not repeated. 197 UnknownFieldData lastData = dataForField.get(dataForField.size() - 1); 198 return readData(extension.fieldType, lastData.bytes); 199 } 200 201 /** 202 * Reads (extension) data of the specified type from the specified byte array. 203 * 204 * @throws IllegalArgumentException if an error occurs while reading the data. 205 */ 206 private static <T> T readData(Class<T> clazz, byte[] data) { 207 if (data.length == 0) { 208 return null; 209 } 210 CodedInputByteBufferNano buffer = CodedInputByteBufferNano.newInstance(data); 211 try { 212 if (clazz == String.class) { 213 return clazz.cast(buffer.readString()); 214 } else if (clazz == Integer.class) { 215 return clazz.cast(buffer.readInt32()); 216 } else if (clazz == Long.class) { 217 return clazz.cast(buffer.readInt64()); 218 } else if (clazz == Boolean.class) { 219 return clazz.cast(buffer.readBool()); 220 } else if (clazz == Float.class) { 221 return clazz.cast(buffer.readFloat()); 222 } else if (clazz == Double.class) { 223 return clazz.cast(buffer.readDouble()); 224 } else if (clazz == byte[].class) { 225 return clazz.cast(buffer.readBytes()); 226 } else if (MessageNano.class.isAssignableFrom(clazz)) { 227 try { 228 MessageNano message = (MessageNano) clazz.newInstance(); 229 buffer.readMessage(message); 230 return clazz.cast(message); 231 } catch (IllegalAccessException e) { 232 throw new IllegalArgumentException("Error creating instance of class " + clazz, e); 233 } catch (InstantiationException e) { 234 throw new IllegalArgumentException("Error creating instance of class " + clazz, e); 235 } 236 } else { 237 throw new IllegalArgumentException("Unhandled extension field type: " + clazz); 238 } 239 } catch (IOException e) { 240 throw new IllegalArgumentException("Error reading extension field", e); 241 } 242 } 243 244 public static <T> void setExtension(Extension<T> extension, T value, 245 List<UnknownFieldData> unknownFields) { 246 // First, remove all unknown fields with this tag. 247 for (Iterator<UnknownFieldData> i = unknownFields.iterator(); i.hasNext();) { 248 UnknownFieldData data = i.next(); 249 if (extension.fieldNumber == getTagFieldNumber(data.tag)) { 250 i.remove(); 251 } 252 } 253 if (value == null) { 254 return; 255 } 256 // Repeated field. 257 if (value instanceof List) { 258 for (Object item : (List<?>) value) { 259 unknownFields.add(write(extension.fieldNumber, item)); 260 } 261 } else { 262 unknownFields.add(write(extension.fieldNumber, value)); 263 } 264 } 265 266 /** 267 * Writes extension data and returns an {@link UnknownFieldData} containing 268 * bytes and a tag. 269 * 270 * @throws IllegalArgumentException if an error occurs while writing. 271 */ 272 private static UnknownFieldData write(int fieldNumber, Object object) { 273 byte[] data; 274 int tag; 275 Class<?> clazz = object.getClass(); 276 try { 277 if (clazz == String.class) { 278 String str = (String) object; 279 data = new byte[CodedOutputByteBufferNano.computeStringSizeNoTag(str)]; 280 CodedOutputByteBufferNano.newInstance(data).writeStringNoTag(str); 281 tag = makeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); 282 } else if (clazz == Integer.class) { 283 Integer integer = (Integer) object; 284 data = new byte[CodedOutputByteBufferNano.computeInt32SizeNoTag(integer)]; 285 CodedOutputByteBufferNano.newInstance(data).writeInt32NoTag(integer); 286 tag = makeTag(fieldNumber, WIRETYPE_VARINT); 287 } else if (clazz == Long.class) { 288 Long longValue = (Long) object; 289 data = new byte[CodedOutputByteBufferNano.computeInt64SizeNoTag(longValue)]; 290 CodedOutputByteBufferNano.newInstance(data).writeInt64NoTag(longValue); 291 tag = makeTag(fieldNumber, WIRETYPE_VARINT); 292 } else if (clazz == Boolean.class) { 293 Boolean boolValue = (Boolean) object; 294 data = new byte[CodedOutputByteBufferNano.computeBoolSizeNoTag(boolValue)]; 295 CodedOutputByteBufferNano.newInstance(data).writeBoolNoTag(boolValue); 296 tag = makeTag(fieldNumber, WIRETYPE_VARINT); 297 } else if (clazz == Float.class) { 298 Float floatValue = (Float) object; 299 data = new byte[CodedOutputByteBufferNano.computeFloatSizeNoTag(floatValue)]; 300 CodedOutputByteBufferNano.newInstance(data).writeFloatNoTag(floatValue); 301 tag = makeTag(fieldNumber, WIRETYPE_FIXED32); 302 } else if (clazz == Double.class) { 303 Double doubleValue = (Double) object; 304 data = new byte[CodedOutputByteBufferNano.computeDoubleSizeNoTag(doubleValue)]; 305 CodedOutputByteBufferNano.newInstance(data).writeDoubleNoTag(doubleValue); 306 tag = makeTag(fieldNumber, WIRETYPE_FIXED64); 307 } else if (clazz == byte[].class) { 308 byte[] byteArrayValue = (byte[]) object; 309 data = new byte[CodedOutputByteBufferNano.computeByteArraySizeNoTag(byteArrayValue)]; 310 CodedOutputByteBufferNano.newInstance(data).writeByteArrayNoTag(byteArrayValue); 311 tag = makeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); 312 } else if (MessageNano.class.isAssignableFrom(clazz)) { 313 MessageNano messageValue = (MessageNano) object; 314 315 int messageSize = messageValue.getSerializedSize(); 316 int delimiterSize = CodedOutputByteBufferNano.computeRawVarint32Size(messageSize); 317 data = new byte[messageSize + delimiterSize]; 318 CodedOutputByteBufferNano buffer = CodedOutputByteBufferNano.newInstance(data); 319 buffer.writeRawVarint32(messageSize); 320 buffer.writeRawBytes(MessageNano.toByteArray(messageValue)); 321 tag = makeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); 322 } else { 323 throw new IllegalArgumentException("Unhandled extension field type: " + clazz); 324 } 325 } catch (IOException e) { 326 throw new IllegalArgumentException(e); 327 } 328 return new UnknownFieldData(tag, data); 329 } 330 331 /** 332 * Given a set of unknown field data, compute the wire size. 333 */ 334 public static int computeWireSize(List<UnknownFieldData> unknownFields) { 335 if (unknownFields == null) { 336 return 0; 337 } 338 int size = 0; 339 for (UnknownFieldData unknownField : unknownFields) { 340 size += CodedOutputByteBufferNano.computeRawVarint32Size(unknownField.tag); 341 size += unknownField.bytes.length; 342 } 343 return size; 344 } 345 346 /** 347 * Write unknown fields. 348 */ 349 public static void writeUnknownFields(List<UnknownFieldData> unknownFields, 350 CodedOutputByteBufferNano outBuffer) throws IOException { 351 if (unknownFields == null) { 352 return; 353 } 354 for (UnknownFieldData data : unknownFields) { 355 outBuffer.writeTag(getTagFieldNumber(data.tag), getTagWireType(data.tag)); 356 outBuffer.writeRawBytes(data.bytes); 357 } 358 } 359} 360