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;
34
35/**
36 * Reads and decodes protocol message fields.
37 *
38 * This class contains two kinds of methods:  methods that read specific
39 * protocol message constructs and field types (e.g. {@link #readTag()} and
40 * {@link #readInt32()}) and methods that read low-level values (e.g.
41 * {@link #readRawVarint32()} and {@link #readRawBytes}).  If you are reading
42 * encoded protocol messages, you should use the former methods, but if you are
43 * reading some other format of your own design, use the latter.
44 *
45 * @author kenton@google.com Kenton Varda
46 */
47public final class CodedInputByteBufferNano {
48  /**
49   * Create a new CodedInputStream wrapping the given byte array.
50   */
51  public static CodedInputByteBufferNano newInstance(final byte[] buf) {
52    return newInstance(buf, 0, buf.length);
53  }
54
55  /**
56   * Create a new CodedInputStream wrapping the given byte array slice.
57   */
58  public static CodedInputByteBufferNano newInstance(final byte[] buf, final int off,
59                                             final int len) {
60    return new CodedInputByteBufferNano(buf, off, len);
61  }
62
63  // -----------------------------------------------------------------
64
65  /**
66   * Attempt to read a field tag, returning zero if we have reached EOF.
67   * Protocol message parsers use this to read tags, since a protocol message
68   * may legally end wherever a tag occurs, and zero is not a valid tag number.
69   */
70  public int readTag() throws IOException {
71    if (isAtEnd()) {
72      lastTag = 0;
73      return 0;
74    }
75
76    lastTag = readRawVarint32();
77    if (lastTag == 0) {
78      // If we actually read zero, that's not a valid tag.
79      throw InvalidProtocolBufferNanoException.invalidTag();
80    }
81    return lastTag;
82  }
83
84  /**
85   * Verifies that the last call to readTag() returned the given tag value.
86   * This is used to verify that a nested group ended with the correct
87   * end tag.
88   *
89   * @throws InvalidProtocolBufferNanoException {@code value} does not match the
90   *                                        last tag.
91   */
92  public void checkLastTagWas(final int value)
93                              throws InvalidProtocolBufferNanoException {
94    if (lastTag != value) {
95      throw InvalidProtocolBufferNanoException.invalidEndTag();
96    }
97  }
98
99  /**
100   * Reads and discards a single field, given its tag value.
101   *
102   * @return {@code false} if the tag is an endgroup tag, in which case
103   *         nothing is skipped.  Otherwise, returns {@code true}.
104   */
105  public boolean skipField(final int tag) throws IOException {
106    switch (WireFormatNano.getTagWireType(tag)) {
107      case WireFormatNano.WIRETYPE_VARINT:
108        readInt32();
109        return true;
110      case WireFormatNano.WIRETYPE_FIXED64:
111        readRawLittleEndian64();
112        return true;
113      case WireFormatNano.WIRETYPE_LENGTH_DELIMITED:
114        skipRawBytes(readRawVarint32());
115        return true;
116      case WireFormatNano.WIRETYPE_START_GROUP:
117        skipMessage();
118        checkLastTagWas(
119          WireFormatNano.makeTag(WireFormatNano.getTagFieldNumber(tag),
120                             WireFormatNano.WIRETYPE_END_GROUP));
121        return true;
122      case WireFormatNano.WIRETYPE_END_GROUP:
123        return false;
124      case WireFormatNano.WIRETYPE_FIXED32:
125        readRawLittleEndian32();
126        return true;
127      default:
128        throw InvalidProtocolBufferNanoException.invalidWireType();
129    }
130  }
131
132  /**
133   * Reads and discards an entire message.  This will read either until EOF
134   * or until an endgroup tag, whichever comes first.
135   */
136  public void skipMessage() throws IOException {
137    while (true) {
138      final int tag = readTag();
139      if (tag == 0 || !skipField(tag)) {
140        return;
141      }
142    }
143  }
144
145  // -----------------------------------------------------------------
146
147  /** Read a {@code double} field value from the stream. */
148  public double readDouble() throws IOException {
149    return Double.longBitsToDouble(readRawLittleEndian64());
150  }
151
152  /** Read a {@code float} field value from the stream. */
153  public float readFloat() throws IOException {
154    return Float.intBitsToFloat(readRawLittleEndian32());
155  }
156
157  /** Read a {@code uint64} field value from the stream. */
158  public long readUInt64() throws IOException {
159    return readRawVarint64();
160  }
161
162  /** Read an {@code int64} field value from the stream. */
163  public long readInt64() throws IOException {
164    return readRawVarint64();
165  }
166
167  /** Read an {@code int32} field value from the stream. */
168  public int readInt32() throws IOException {
169    return readRawVarint32();
170  }
171
172  /** Read a {@code fixed64} field value from the stream. */
173  public long readFixed64() throws IOException {
174    return readRawLittleEndian64();
175  }
176
177  /** Read a {@code fixed32} field value from the stream. */
178  public int readFixed32() throws IOException {
179    return readRawLittleEndian32();
180  }
181
182  /** Read a {@code bool} field value from the stream. */
183  public boolean readBool() throws IOException {
184    return readRawVarint32() != 0;
185  }
186
187  /** Read a {@code string} field value from the stream. */
188  public String readString() throws IOException {
189    final int size = readRawVarint32();
190    if (size < 0) {
191      throw InvalidProtocolBufferNanoException.negativeSize();
192    }
193    if (size > (bufferSize - bufferPos)) {
194      throw InvalidProtocolBufferNanoException.truncatedMessage();
195    }
196
197    final String result = new String(buffer, bufferPos, size, "UTF-8");
198    bufferPos += size;
199    return result;
200  }
201
202  /** Read a {@code group} field value from the stream. */
203  public void readGroup(final MessageNano msg, final int fieldNumber)
204      throws IOException {
205    if (recursionDepth >= recursionLimit) {
206      throw InvalidProtocolBufferNanoException.recursionLimitExceeded();
207    }
208    ++recursionDepth;
209    msg.mergeFrom(this);
210    checkLastTagWas(
211      WireFormatNano.makeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP));
212    --recursionDepth;
213  }
214
215  public void readMessage(final MessageNano msg)
216      throws IOException {
217    final int length = readRawVarint32();
218    if (recursionDepth >= recursionLimit) {
219      throw InvalidProtocolBufferNanoException.recursionLimitExceeded();
220    }
221    final int oldLimit = pushLimit(length);
222    ++recursionDepth;
223    msg.mergeFrom(this);
224    checkLastTagWas(0);
225    --recursionDepth;
226    popLimit(oldLimit);
227  }
228
229  /** Read a {@code bytes} field value from the stream. */
230  public byte[] readBytes() throws IOException {
231    final int size = readRawVarint32();
232    if (size < 0) {
233      throw InvalidProtocolBufferNanoException.negativeSize();
234    }
235    if (size == 0) {
236      return WireFormatNano.EMPTY_BYTES;
237    }
238    if (size > (bufferSize - bufferPos)) {
239      throw InvalidProtocolBufferNanoException.truncatedMessage();
240    }
241
242    final byte[] result = new byte[size];
243    System.arraycopy(buffer, bufferPos, result, 0, size);
244    bufferPos += size;
245    return result;
246  }
247
248  /** Read a {@code uint32} field value from the stream. */
249  public int readUInt32() throws IOException {
250    return readRawVarint32();
251  }
252
253  /**
254   * Read an enum field value from the stream.  Caller is responsible
255   * for converting the numeric value to an actual enum.
256   */
257  public int readEnum() throws IOException {
258    return readRawVarint32();
259  }
260
261  /** Read an {@code sfixed32} field value from the stream. */
262  public int readSFixed32() throws IOException {
263    return readRawLittleEndian32();
264  }
265
266  /** Read an {@code sfixed64} field value from the stream. */
267  public long readSFixed64() throws IOException {
268    return readRawLittleEndian64();
269  }
270
271  /** Read an {@code sint32} field value from the stream. */
272  public int readSInt32() throws IOException {
273    return decodeZigZag32(readRawVarint32());
274  }
275
276  /** Read an {@code sint64} field value from the stream. */
277  public long readSInt64() throws IOException {
278    return decodeZigZag64(readRawVarint64());
279  }
280
281  // =================================================================
282
283  /**
284   * Read a raw Varint from the stream.  If larger than 32 bits, discard the
285   * upper bits.
286   */
287  public int readRawVarint32() throws IOException {
288    byte tmp = readRawByte();
289    if (tmp >= 0) {
290      return tmp;
291    }
292    int result = tmp & 0x7f;
293    if ((tmp = readRawByte()) >= 0) {
294      result |= tmp << 7;
295    } else {
296      result |= (tmp & 0x7f) << 7;
297      if ((tmp = readRawByte()) >= 0) {
298        result |= tmp << 14;
299      } else {
300        result |= (tmp & 0x7f) << 14;
301        if ((tmp = readRawByte()) >= 0) {
302          result |= tmp << 21;
303        } else {
304          result |= (tmp & 0x7f) << 21;
305          result |= (tmp = readRawByte()) << 28;
306          if (tmp < 0) {
307            // Discard upper 32 bits.
308            for (int i = 0; i < 5; i++) {
309              if (readRawByte() >= 0) {
310                return result;
311              }
312            }
313            throw InvalidProtocolBufferNanoException.malformedVarint();
314          }
315        }
316      }
317    }
318    return result;
319  }
320
321  /** Read a raw Varint from the stream. */
322  public long readRawVarint64() throws IOException {
323    int shift = 0;
324    long result = 0;
325    while (shift < 64) {
326      final byte b = readRawByte();
327      result |= (long)(b & 0x7F) << shift;
328      if ((b & 0x80) == 0) {
329        return result;
330      }
331      shift += 7;
332    }
333    throw InvalidProtocolBufferNanoException.malformedVarint();
334  }
335
336  /** Read a 32-bit little-endian integer from the stream. */
337  public int readRawLittleEndian32() throws IOException {
338    final byte b1 = readRawByte();
339    final byte b2 = readRawByte();
340    final byte b3 = readRawByte();
341    final byte b4 = readRawByte();
342    return ((b1 & 0xff)      ) |
343           ((b2 & 0xff) <<  8) |
344           ((b3 & 0xff) << 16) |
345           ((b4 & 0xff) << 24);
346  }
347
348  /** Read a 64-bit little-endian integer from the stream. */
349  public long readRawLittleEndian64() throws IOException {
350    final byte b1 = readRawByte();
351    final byte b2 = readRawByte();
352    final byte b3 = readRawByte();
353    final byte b4 = readRawByte();
354    final byte b5 = readRawByte();
355    final byte b6 = readRawByte();
356    final byte b7 = readRawByte();
357    final byte b8 = readRawByte();
358    return (((long)b1 & 0xff)      ) |
359           (((long)b2 & 0xff) <<  8) |
360           (((long)b3 & 0xff) << 16) |
361           (((long)b4 & 0xff) << 24) |
362           (((long)b5 & 0xff) << 32) |
363           (((long)b6 & 0xff) << 40) |
364           (((long)b7 & 0xff) << 48) |
365           (((long)b8 & 0xff) << 56);
366  }
367
368  /**
369   * Decode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
370   * into values that can be efficiently encoded with varint.  (Otherwise,
371   * negative values must be sign-extended to 64 bits to be varint encoded,
372   * thus always taking 10 bytes on the wire.)
373   *
374   * @param n An unsigned 32-bit integer, stored in a signed int because
375   *          Java has no explicit unsigned support.
376   * @return A signed 32-bit integer.
377   */
378  public static int decodeZigZag32(final int n) {
379    return (n >>> 1) ^ -(n & 1);
380  }
381
382  /**
383   * Decode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
384   * into values that can be efficiently encoded with varint.  (Otherwise,
385   * negative values must be sign-extended to 64 bits to be varint encoded,
386   * thus always taking 10 bytes on the wire.)
387   *
388   * @param n An unsigned 64-bit integer, stored in a signed int because
389   *          Java has no explicit unsigned support.
390   * @return A signed 64-bit integer.
391   */
392  public static long decodeZigZag64(final long n) {
393    return (n >>> 1) ^ -(n & 1);
394  }
395
396  // -----------------------------------------------------------------
397
398  private final byte[] buffer;
399  private int bufferStart;
400  private int bufferSize;
401  private int bufferSizeAfterLimit;
402  private int bufferPos;
403  private int lastTag;
404
405  /** The absolute position of the end of the current message. */
406  private int currentLimit = Integer.MAX_VALUE;
407
408  /** See setRecursionLimit() */
409  private int recursionDepth;
410  private int recursionLimit = DEFAULT_RECURSION_LIMIT;
411
412  /** See setSizeLimit() */
413  private int sizeLimit = DEFAULT_SIZE_LIMIT;
414
415  private static final int DEFAULT_RECURSION_LIMIT = 64;
416  private static final int DEFAULT_SIZE_LIMIT = 64 << 20;  // 64MB
417
418  private CodedInputByteBufferNano(final byte[] buffer, final int off, final int len) {
419    this.buffer = buffer;
420    bufferStart = off;
421    bufferSize = off + len;
422    bufferPos = off;
423  }
424
425  /**
426   * Set the maximum message recursion depth.  In order to prevent malicious
427   * messages from causing stack overflows, {@code CodedInputStream} limits
428   * how deeply messages may be nested.  The default limit is 64.
429   *
430   * @return the old limit.
431   */
432  public int setRecursionLimit(final int limit) {
433    if (limit < 0) {
434      throw new IllegalArgumentException(
435        "Recursion limit cannot be negative: " + limit);
436    }
437    final int oldLimit = recursionLimit;
438    recursionLimit = limit;
439    return oldLimit;
440  }
441
442  /**
443   * Set the maximum message size.  In order to prevent malicious
444   * messages from exhausting memory or causing integer overflows,
445   * {@code CodedInputStream} limits how large a message may be.
446   * The default limit is 64MB.  You should set this limit as small
447   * as you can without harming your app's functionality.  Note that
448   * size limits only apply when reading from an {@code InputStream}, not
449   * when constructed around a raw byte array.
450   * <p>
451   * If you want to read several messages from a single CodedInputStream, you
452   * could call {@link #resetSizeCounter()} after each one to avoid hitting the
453   * size limit.
454   *
455   * @return the old limit.
456   */
457  public int setSizeLimit(final int limit) {
458    if (limit < 0) {
459      throw new IllegalArgumentException(
460        "Size limit cannot be negative: " + limit);
461    }
462    final int oldLimit = sizeLimit;
463    sizeLimit = limit;
464    return oldLimit;
465  }
466
467  /**
468   * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
469   */
470  public void resetSizeCounter() {
471  }
472
473  /**
474   * Sets {@code currentLimit} to (current position) + {@code byteLimit}.  This
475   * is called when descending into a length-delimited embedded message.
476   *
477   * @return the old limit.
478   */
479  public int pushLimit(int byteLimit) throws InvalidProtocolBufferNanoException {
480    if (byteLimit < 0) {
481      throw InvalidProtocolBufferNanoException.negativeSize();
482    }
483    byteLimit += bufferPos;
484    final int oldLimit = currentLimit;
485    if (byteLimit > oldLimit) {
486      throw InvalidProtocolBufferNanoException.truncatedMessage();
487    }
488    currentLimit = byteLimit;
489
490    recomputeBufferSizeAfterLimit();
491
492    return oldLimit;
493  }
494
495  private void recomputeBufferSizeAfterLimit() {
496    bufferSize += bufferSizeAfterLimit;
497    final int bufferEnd = bufferSize;
498    if (bufferEnd > currentLimit) {
499      // Limit is in current buffer.
500      bufferSizeAfterLimit = bufferEnd - currentLimit;
501      bufferSize -= bufferSizeAfterLimit;
502    } else {
503      bufferSizeAfterLimit = 0;
504    }
505  }
506
507  /**
508   * Discards the current limit, returning to the previous limit.
509   *
510   * @param oldLimit The old limit, as returned by {@code pushLimit}.
511   */
512  public void popLimit(final int oldLimit) {
513    currentLimit = oldLimit;
514    recomputeBufferSizeAfterLimit();
515  }
516
517  /**
518   * Returns the number of bytes to be read before the current limit.
519   * If no limit is set, returns -1.
520   */
521  public int getBytesUntilLimit() {
522    if (currentLimit == Integer.MAX_VALUE) {
523      return -1;
524    }
525
526    final int currentAbsolutePosition = bufferPos;
527    return currentLimit - currentAbsolutePosition;
528  }
529
530  /**
531   * Returns true if the stream has reached the end of the input.  This is the
532   * case if either the end of the underlying input source has been reached or
533   * if the stream has reached a limit created using {@link #pushLimit(int)}.
534   */
535  public boolean isAtEnd() {
536    return bufferPos == bufferSize;
537  }
538
539  /**
540   * Get current position in buffer relative to beginning offset.
541   */
542  public int getPosition() {
543    return bufferPos - bufferStart;
544  }
545
546  /**
547   * Get current (absolute) position in buffer.
548   */
549  public int getAbsolutePosition() {
550    return bufferPos;
551  }
552
553  /**
554   * Return the raw underlying data in the buffer, directly.
555   */
556  public byte[] getBuffer() {
557    return buffer;
558  }
559
560  /**
561   * Retrieves a subset of data in the buffer. The returned array is not backed by the original
562   * buffer array.
563   *
564   * @param offset the position (relative to the buffer start position) to start at.
565   * @param length the number of bytes to retrieve.
566   */
567  public byte[] getData(int offset, int length) {
568    if (length == 0) {
569      return WireFormatNano.EMPTY_BYTES;
570    }
571    byte[] copy = new byte[length];
572    int start = bufferStart + offset;
573    System.arraycopy(buffer, start, copy, 0, length);
574    return copy;
575  }
576
577  /**
578   * Rewind to previous position. Cannot go forward.
579   */
580  public void rewindToPosition(int position) {
581    if (position > bufferPos - bufferStart) {
582      throw new IllegalArgumentException(
583              "Position " + position + " is beyond current " + (bufferPos - bufferStart));
584    }
585    if (position < 0) {
586      throw new IllegalArgumentException("Bad position " + position);
587    }
588    bufferPos = bufferStart + position;
589  }
590
591  /**
592   * Read one byte from the input.
593   *
594   * @throws InvalidProtocolBufferNanoException The end of the stream or the current
595   *                                        limit was reached.
596   */
597  public byte readRawByte() throws IOException {
598    if (bufferPos == bufferSize) {
599      throw InvalidProtocolBufferNanoException.truncatedMessage();
600    }
601    return buffer[bufferPos++];
602  }
603
604  /**
605   * Read a fixed size of bytes from the input.
606   *
607   * @throws InvalidProtocolBufferNanoException The end of the stream or the current
608   *                                        limit was reached.
609   */
610  public byte[] readRawBytes(final int size) throws IOException {
611    if (size < 0) {
612      throw InvalidProtocolBufferNanoException.negativeSize();
613    }
614
615    if (bufferPos + size > currentLimit) {
616      // Read to the end of the stream anyway.
617      skipRawBytes(currentLimit - bufferPos);
618      // Then fail.
619      throw InvalidProtocolBufferNanoException.truncatedMessage();
620    }
621
622    if (size <= bufferSize - bufferPos) {
623      // We have all the bytes we need already.
624      final byte[] bytes = new byte[size];
625      System.arraycopy(buffer, bufferPos, bytes, 0, size);
626      bufferPos += size;
627      return bytes;
628    } else {
629      throw InvalidProtocolBufferNanoException.truncatedMessage();
630    }
631  }
632
633  /**
634   * Reads and discards {@code size} bytes.
635   *
636   * @throws InvalidProtocolBufferNanoException The end of the stream or the current
637   *                                        limit was reached.
638   */
639  public void skipRawBytes(final int size) throws IOException {
640    if (size < 0) {
641      throw InvalidProtocolBufferNanoException.negativeSize();
642    }
643
644    if (bufferPos + size > currentLimit) {
645      // Read to the end of the stream anyway.
646      skipRawBytes(currentLimit - bufferPos);
647      // Then fail.
648      throw InvalidProtocolBufferNanoException.truncatedMessage();
649    }
650
651    if (size <= bufferSize - bufferPos) {
652      // We have all the bytes we need already.
653      bufferPos += size;
654    } else {
655      throw InvalidProtocolBufferNanoException.truncatedMessage();
656    }
657  }
658}
659