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