PageRenderTime 70ms CodeModel.GetById 20ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 1ms

/thirdparty/breakpad/third_party/protobuf/protobuf/java/src/main/java/com/google/protobuf/CodedInputStream.java

http://github.com/tomahawk-player/tomahawk
Java | 885 lines | 500 code | 88 blank | 297 comment | 95 complexity | 86120adb1fdd94852c4b73fbb1ba3431 MD5 | raw file
  1// Protocol Buffers - Google's data interchange format
  2// Copyright 2008 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;
 32
 33import java.io.IOException;
 34import java.io.InputStream;
 35import java.util.ArrayList;
 36import java.util.List;
 37
 38/**
 39 * Reads and decodes protocol message fields.
 40 *
 41 * This class contains two kinds of methods:  methods that read specific
 42 * protocol message constructs and field types (e.g. {@link #readTag()} and
 43 * {@link #readInt32()}) and methods that read low-level values (e.g.
 44 * {@link #readRawVarint32()} and {@link #readRawBytes}).  If you are reading
 45 * encoded protocol messages, you should use the former methods, but if you are
 46 * reading some other format of your own design, use the latter.
 47 *
 48 * @author kenton@google.com Kenton Varda
 49 */
 50public final class CodedInputStream {
 51  /**
 52   * Create a new CodedInputStream wrapping the given InputStream.
 53   */
 54  public static CodedInputStream newInstance(final InputStream input) {
 55    return new CodedInputStream(input);
 56  }
 57
 58  /**
 59   * Create a new CodedInputStream wrapping the given byte array.
 60   */
 61  public static CodedInputStream newInstance(final byte[] buf) {
 62    return newInstance(buf, 0, buf.length);
 63  }
 64
 65  /**
 66   * Create a new CodedInputStream wrapping the given byte array slice.
 67   */
 68  public static CodedInputStream newInstance(final byte[] buf, final int off,
 69                                             final int len) {
 70    CodedInputStream result = new CodedInputStream(buf, off, len);
 71    try {
 72      // Some uses of CodedInputStream can be more efficient if they know
 73      // exactly how many bytes are available.  By pushing the end point of the
 74      // buffer as a limit, we allow them to get this information via
 75      // getBytesUntilLimit().  Pushing a limit that we know is at the end of
 76      // the stream can never hurt, since we can never past that point anyway.
 77      result.pushLimit(len);
 78    } catch (InvalidProtocolBufferException ex) {
 79      // The only reason pushLimit() might throw an exception here is if len
 80      // is negative. Normally pushLimit()'s parameter comes directly off the
 81      // wire, so it's important to catch exceptions in case of corrupt or
 82      // malicious data. However, in this case, we expect that len is not a
 83      // user-supplied value, so we can assume that it being negative indicates
 84      // a programming error. Therefore, throwing an unchecked exception is
 85      // appropriate.
 86      throw new IllegalArgumentException(ex);
 87    }
 88    return result;
 89  }
 90
 91  // -----------------------------------------------------------------
 92
 93  /**
 94   * Attempt to read a field tag, returning zero if we have reached EOF.
 95   * Protocol message parsers use this to read tags, since a protocol message
 96   * may legally end wherever a tag occurs, and zero is not a valid tag number.
 97   */
 98  public int readTag() throws IOException {
 99    if (isAtEnd()) {
100      lastTag = 0;
101      return 0;
102    }
103
104    lastTag = readRawVarint32();
105    if (WireFormat.getTagFieldNumber(lastTag) == 0) {
106      // If we actually read zero (or any tag number corresponding to field
107      // number zero), that's not a valid tag.
108      throw InvalidProtocolBufferException.invalidTag();
109    }
110    return lastTag;
111  }
112
113  /**
114   * Verifies that the last call to readTag() returned the given tag value.
115   * This is used to verify that a nested group ended with the correct
116   * end tag.
117   *
118   * @throws InvalidProtocolBufferException {@code value} does not match the
119   *                                        last tag.
120   */
121  public void checkLastTagWas(final int value)
122                              throws InvalidProtocolBufferException {
123    if (lastTag != value) {
124      throw InvalidProtocolBufferException.invalidEndTag();
125    }
126  }
127
128  /**
129   * Reads and discards a single field, given its tag value.
130   *
131   * @return {@code false} if the tag is an endgroup tag, in which case
132   *         nothing is skipped.  Otherwise, returns {@code true}.
133   */
134  public boolean skipField(final int tag) throws IOException {
135    switch (WireFormat.getTagWireType(tag)) {
136      case WireFormat.WIRETYPE_VARINT:
137        readInt32();
138        return true;
139      case WireFormat.WIRETYPE_FIXED64:
140        readRawLittleEndian64();
141        return true;
142      case WireFormat.WIRETYPE_LENGTH_DELIMITED:
143        skipRawBytes(readRawVarint32());
144        return true;
145      case WireFormat.WIRETYPE_START_GROUP:
146        skipMessage();
147        checkLastTagWas(
148          WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
149                             WireFormat.WIRETYPE_END_GROUP));
150        return true;
151      case WireFormat.WIRETYPE_END_GROUP:
152        return false;
153      case WireFormat.WIRETYPE_FIXED32:
154        readRawLittleEndian32();
155        return true;
156      default:
157        throw InvalidProtocolBufferException.invalidWireType();
158    }
159  }
160
161  /**
162   * Reads and discards an entire message.  This will read either until EOF
163   * or until an endgroup tag, whichever comes first.
164   */
165  public void skipMessage() throws IOException {
166    while (true) {
167      final int tag = readTag();
168      if (tag == 0 || !skipField(tag)) {
169        return;
170      }
171    }
172  }
173
174  // -----------------------------------------------------------------
175
176  /** Read a {@code double} field value from the stream. */
177  public double readDouble() throws IOException {
178    return Double.longBitsToDouble(readRawLittleEndian64());
179  }
180
181  /** Read a {@code float} field value from the stream. */
182  public float readFloat() throws IOException {
183    return Float.intBitsToFloat(readRawLittleEndian32());
184  }
185
186  /** Read a {@code uint64} field value from the stream. */
187  public long readUInt64() throws IOException {
188    return readRawVarint64();
189  }
190
191  /** Read an {@code int64} field value from the stream. */
192  public long readInt64() throws IOException {
193    return readRawVarint64();
194  }
195
196  /** Read an {@code int32} field value from the stream. */
197  public int readInt32() throws IOException {
198    return readRawVarint32();
199  }
200
201  /** Read a {@code fixed64} field value from the stream. */
202  public long readFixed64() throws IOException {
203    return readRawLittleEndian64();
204  }
205
206  /** Read a {@code fixed32} field value from the stream. */
207  public int readFixed32() throws IOException {
208    return readRawLittleEndian32();
209  }
210
211  /** Read a {@code bool} field value from the stream. */
212  public boolean readBool() throws IOException {
213    return readRawVarint32() != 0;
214  }
215
216  /** Read a {@code string} field value from the stream. */
217  public String readString() throws IOException {
218    final int size = readRawVarint32();
219    if (size <= (bufferSize - bufferPos) && size > 0) {
220      // Fast path:  We already have the bytes in a contiguous buffer, so
221      //   just copy directly from it.
222      final String result = new String(buffer, bufferPos, size, "UTF-8");
223      bufferPos += size;
224      return result;
225    } else {
226      // Slow path:  Build a byte array first then copy it.
227      return new String(readRawBytes(size), "UTF-8");
228    }
229  }
230
231  /** Read a {@code group} field value from the stream. */
232  public void readGroup(final int fieldNumber,
233                        final MessageLite.Builder builder,
234                        final ExtensionRegistryLite extensionRegistry)
235      throws IOException {
236    if (recursionDepth >= recursionLimit) {
237      throw InvalidProtocolBufferException.recursionLimitExceeded();
238    }
239    ++recursionDepth;
240    builder.mergeFrom(this, extensionRegistry);
241    checkLastTagWas(
242      WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
243    --recursionDepth;
244  }
245
246  /**
247   * Reads a {@code group} field value from the stream and merges it into the
248   * given {@link UnknownFieldSet}.
249   *
250   * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so
251   *             you can just call {@link #readGroup}.
252   */
253  @Deprecated
254  public void readUnknownGroup(final int fieldNumber,
255                               final MessageLite.Builder builder)
256      throws IOException {
257    // We know that UnknownFieldSet will ignore any ExtensionRegistry so it
258    // is safe to pass null here.  (We can't call
259    // ExtensionRegistry.getEmptyRegistry() because that would make this
260    // class depend on ExtensionRegistry, which is not part of the lite
261    // library.)
262    readGroup(fieldNumber, builder, null);
263  }
264
265  /** Read an embedded message field value from the stream. */
266  public void readMessage(final MessageLite.Builder builder,
267                          final ExtensionRegistryLite extensionRegistry)
268      throws IOException {
269    final int length = readRawVarint32();
270    if (recursionDepth >= recursionLimit) {
271      throw InvalidProtocolBufferException.recursionLimitExceeded();
272    }
273    final int oldLimit = pushLimit(length);
274    ++recursionDepth;
275    builder.mergeFrom(this, extensionRegistry);
276    checkLastTagWas(0);
277    --recursionDepth;
278    popLimit(oldLimit);
279  }
280
281  /** Read a {@code bytes} field value from the stream. */
282  public ByteString readBytes() throws IOException {
283    final int size = readRawVarint32();
284    if (size == 0) {
285      return ByteString.EMPTY;
286    } else if (size <= (bufferSize - bufferPos) && size > 0) {
287      // Fast path:  We already have the bytes in a contiguous buffer, so
288      //   just copy directly from it.
289      final ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
290      bufferPos += size;
291      return result;
292    } else {
293      // Slow path:  Build a byte array first then copy it.
294      return ByteString.copyFrom(readRawBytes(size));
295    }
296  }
297
298  /** Read a {@code uint32} field value from the stream. */
299  public int readUInt32() throws IOException {
300    return readRawVarint32();
301  }
302
303  /**
304   * Read an enum field value from the stream.  Caller is responsible
305   * for converting the numeric value to an actual enum.
306   */
307  public int readEnum() throws IOException {
308    return readRawVarint32();
309  }
310
311  /** Read an {@code sfixed32} field value from the stream. */
312  public int readSFixed32() throws IOException {
313    return readRawLittleEndian32();
314  }
315
316  /** Read an {@code sfixed64} field value from the stream. */
317  public long readSFixed64() throws IOException {
318    return readRawLittleEndian64();
319  }
320
321  /** Read an {@code sint32} field value from the stream. */
322  public int readSInt32() throws IOException {
323    return decodeZigZag32(readRawVarint32());
324  }
325
326  /** Read an {@code sint64} field value from the stream. */
327  public long readSInt64() throws IOException {
328    return decodeZigZag64(readRawVarint64());
329  }
330
331  // =================================================================
332
333  /**
334   * Read a raw Varint from the stream.  If larger than 32 bits, discard the
335   * upper bits.
336   */
337  public int readRawVarint32() throws IOException {
338    byte tmp = readRawByte();
339    if (tmp >= 0) {
340      return tmp;
341    }
342    int result = tmp & 0x7f;
343    if ((tmp = readRawByte()) >= 0) {
344      result |= tmp << 7;
345    } else {
346      result |= (tmp & 0x7f) << 7;
347      if ((tmp = readRawByte()) >= 0) {
348        result |= tmp << 14;
349      } else {
350        result |= (tmp & 0x7f) << 14;
351        if ((tmp = readRawByte()) >= 0) {
352          result |= tmp << 21;
353        } else {
354          result |= (tmp & 0x7f) << 21;
355          result |= (tmp = readRawByte()) << 28;
356          if (tmp < 0) {
357            // Discard upper 32 bits.
358            for (int i = 0; i < 5; i++) {
359              if (readRawByte() >= 0) {
360                return result;
361              }
362            }
363            throw InvalidProtocolBufferException.malformedVarint();
364          }
365        }
366      }
367    }
368    return result;
369  }
370
371  /**
372   * Reads a varint from the input one byte at a time, so that it does not
373   * read any bytes after the end of the varint.  If you simply wrapped the
374   * stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)}
375   * then you would probably end up reading past the end of the varint since
376   * CodedInputStream buffers its input.
377   */
378  static int readRawVarint32(final InputStream input) throws IOException {
379    final int firstByte = input.read();
380    if (firstByte == -1) {
381      throw InvalidProtocolBufferException.truncatedMessage();
382    }
383    return readRawVarint32(firstByte, input);
384  }
385
386  /**
387   * Like {@link #readRawVarint32(InputStream)}, but expects that the caller
388   * has already read one byte.  This allows the caller to determine if EOF
389   * has been reached before attempting to read.
390   */
391  public static int readRawVarint32(
392      final int firstByte, final InputStream input) throws IOException {
393    if ((firstByte & 0x80) == 0) {
394      return firstByte;
395    }
396
397    int result = firstByte & 0x7f;
398    int offset = 7;
399    for (; offset < 32; offset += 7) {
400      final int b = input.read();
401      if (b == -1) {
402        throw InvalidProtocolBufferException.truncatedMessage();
403      }
404      result |= (b & 0x7f) << offset;
405      if ((b & 0x80) == 0) {
406        return result;
407      }
408    }
409    // Keep reading up to 64 bits.
410    for (; offset < 64; offset += 7) {
411      final int b = input.read();
412      if (b == -1) {
413        throw InvalidProtocolBufferException.truncatedMessage();
414      }
415      if ((b & 0x80) == 0) {
416        return result;
417      }
418    }
419    throw InvalidProtocolBufferException.malformedVarint();
420  }
421
422  /** Read a raw Varint from the stream. */
423  public long readRawVarint64() throws IOException {
424    int shift = 0;
425    long result = 0;
426    while (shift < 64) {
427      final byte b = readRawByte();
428      result |= (long)(b & 0x7F) << shift;
429      if ((b & 0x80) == 0) {
430        return result;
431      }
432      shift += 7;
433    }
434    throw InvalidProtocolBufferException.malformedVarint();
435  }
436
437  /** Read a 32-bit little-endian integer from the stream. */
438  public int readRawLittleEndian32() throws IOException {
439    final byte b1 = readRawByte();
440    final byte b2 = readRawByte();
441    final byte b3 = readRawByte();
442    final byte b4 = readRawByte();
443    return (((int)b1 & 0xff)      ) |
444           (((int)b2 & 0xff) <<  8) |
445           (((int)b3 & 0xff) << 16) |
446           (((int)b4 & 0xff) << 24);
447  }
448
449  /** Read a 64-bit little-endian integer from the stream. */
450  public long readRawLittleEndian64() throws IOException {
451    final byte b1 = readRawByte();
452    final byte b2 = readRawByte();
453    final byte b3 = readRawByte();
454    final byte b4 = readRawByte();
455    final byte b5 = readRawByte();
456    final byte b6 = readRawByte();
457    final byte b7 = readRawByte();
458    final byte b8 = readRawByte();
459    return (((long)b1 & 0xff)      ) |
460           (((long)b2 & 0xff) <<  8) |
461           (((long)b3 & 0xff) << 16) |
462           (((long)b4 & 0xff) << 24) |
463           (((long)b5 & 0xff) << 32) |
464           (((long)b6 & 0xff) << 40) |
465           (((long)b7 & 0xff) << 48) |
466           (((long)b8 & 0xff) << 56);
467  }
468
469  /**
470   * Decode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
471   * into values that can be efficiently encoded with varint.  (Otherwise,
472   * negative values must be sign-extended to 64 bits to be varint encoded,
473   * thus always taking 10 bytes on the wire.)
474   *
475   * @param n An unsigned 32-bit integer, stored in a signed int because
476   *          Java has no explicit unsigned support.
477   * @return A signed 32-bit integer.
478   */
479  public static int decodeZigZag32(final int n) {
480    return (n >>> 1) ^ -(n & 1);
481  }
482
483  /**
484   * Decode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
485   * into values that can be efficiently encoded with varint.  (Otherwise,
486   * negative values must be sign-extended to 64 bits to be varint encoded,
487   * thus always taking 10 bytes on the wire.)
488   *
489   * @param n An unsigned 64-bit integer, stored in a signed int because
490   *          Java has no explicit unsigned support.
491   * @return A signed 64-bit integer.
492   */
493  public static long decodeZigZag64(final long n) {
494    return (n >>> 1) ^ -(n & 1);
495  }
496
497  // -----------------------------------------------------------------
498
499  private final byte[] buffer;
500  private int bufferSize;
501  private int bufferSizeAfterLimit;
502  private int bufferPos;
503  private final InputStream input;
504  private int lastTag;
505
506  /**
507   * The total number of bytes read before the current buffer.  The total
508   * bytes read up to the current position can be computed as
509   * {@code totalBytesRetired + bufferPos}.  This value may be negative if
510   * reading started in the middle of the current buffer (e.g. if the
511   * constructor that takes a byte array and an offset was used).
512   */
513  private int totalBytesRetired;
514
515  /** The absolute position of the end of the current message. */
516  private int currentLimit = Integer.MAX_VALUE;
517
518  /** See setRecursionLimit() */
519  private int recursionDepth;
520  private int recursionLimit = DEFAULT_RECURSION_LIMIT;
521
522  /** See setSizeLimit() */
523  private int sizeLimit = DEFAULT_SIZE_LIMIT;
524
525  private static final int DEFAULT_RECURSION_LIMIT = 64;
526  private static final int DEFAULT_SIZE_LIMIT = 64 << 20;  // 64MB
527  private static final int BUFFER_SIZE = 4096;
528
529  private CodedInputStream(final byte[] buffer, final int off, final int len) {
530    this.buffer = buffer;
531    bufferSize = off + len;
532    bufferPos = off;
533    totalBytesRetired = -off;
534    input = null;
535  }
536
537  private CodedInputStream(final InputStream input) {
538    buffer = new byte[BUFFER_SIZE];
539    bufferSize = 0;
540    bufferPos = 0;
541    totalBytesRetired = 0;
542    this.input = input;
543  }
544
545  /**
546   * Set the maximum message recursion depth.  In order to prevent malicious
547   * messages from causing stack overflows, {@code CodedInputStream} limits
548   * how deeply messages may be nested.  The default limit is 64.
549   *
550   * @return the old limit.
551   */
552  public int setRecursionLimit(final int limit) {
553    if (limit < 0) {
554      throw new IllegalArgumentException(
555        "Recursion limit cannot be negative: " + limit);
556    }
557    final int oldLimit = recursionLimit;
558    recursionLimit = limit;
559    return oldLimit;
560  }
561
562  /**
563   * Set the maximum message size.  In order to prevent malicious
564   * messages from exhausting memory or causing integer overflows,
565   * {@code CodedInputStream} limits how large a message may be.
566   * The default limit is 64MB.  You should set this limit as small
567   * as you can without harming your app's functionality.  Note that
568   * size limits only apply when reading from an {@code InputStream}, not
569   * when constructed around a raw byte array (nor with
570   * {@link ByteString#newCodedInput}).
571   * <p>
572   * If you want to read several messages from a single CodedInputStream, you
573   * could call {@link #resetSizeCounter()} after each one to avoid hitting the
574   * size limit.
575   *
576   * @return the old limit.
577   */
578  public int setSizeLimit(final int limit) {
579    if (limit < 0) {
580      throw new IllegalArgumentException(
581        "Size limit cannot be negative: " + limit);
582    }
583    final int oldLimit = sizeLimit;
584    sizeLimit = limit;
585    return oldLimit;
586  }
587
588  /**
589   * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
590   */
591  public void resetSizeCounter() {
592    totalBytesRetired = -bufferPos;
593  }
594
595  /**
596   * Sets {@code currentLimit} to (current position) + {@code byteLimit}.  This
597   * is called when descending into a length-delimited embedded message.
598   *
599   * <p>Note that {@code pushLimit()} does NOT affect how many bytes the
600   * {@code CodedInputStream} reads from an underlying {@code InputStream} when
601   * refreshing its buffer.  If you need to prevent reading past a certain
602   * point in the underlying {@code InputStream} (e.g. because you expect it to
603   * contain more data after the end of the message which you need to handle
604   * differently) then you must place a wrapper around you {@code InputStream}
605   * which limits the amount of data that can be read from it.
606   *
607   * @return the old limit.
608   */
609  public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
610    if (byteLimit < 0) {
611      throw InvalidProtocolBufferException.negativeSize();
612    }
613    byteLimit += totalBytesRetired + bufferPos;
614    final int oldLimit = currentLimit;
615    if (byteLimit > oldLimit) {
616      throw InvalidProtocolBufferException.truncatedMessage();
617    }
618    currentLimit = byteLimit;
619
620    recomputeBufferSizeAfterLimit();
621
622    return oldLimit;
623  }
624
625  private void recomputeBufferSizeAfterLimit() {
626    bufferSize += bufferSizeAfterLimit;
627    final int bufferEnd = totalBytesRetired + bufferSize;
628    if (bufferEnd > currentLimit) {
629      // Limit is in current buffer.
630      bufferSizeAfterLimit = bufferEnd - currentLimit;
631      bufferSize -= bufferSizeAfterLimit;
632    } else {
633      bufferSizeAfterLimit = 0;
634    }
635  }
636
637  /**
638   * Discards the current limit, returning to the previous limit.
639   *
640   * @param oldLimit The old limit, as returned by {@code pushLimit}.
641   */
642  public void popLimit(final int oldLimit) {
643    currentLimit = oldLimit;
644    recomputeBufferSizeAfterLimit();
645  }
646
647  /**
648   * Returns the number of bytes to be read before the current limit.
649   * If no limit is set, returns -1.
650   */
651  public int getBytesUntilLimit() {
652    if (currentLimit == Integer.MAX_VALUE) {
653      return -1;
654    }
655
656    final int currentAbsolutePosition = totalBytesRetired + bufferPos;
657    return currentLimit - currentAbsolutePosition;
658  }
659
660  /**
661   * Returns true if the stream has reached the end of the input.  This is the
662   * case if either the end of the underlying input source has been reached or
663   * if the stream has reached a limit created using {@link #pushLimit(int)}.
664   */
665  public boolean isAtEnd() throws IOException {
666    return bufferPos == bufferSize && !refillBuffer(false);
667  }
668
669  /**
670   * The total bytes read up to the current position. Calling
671   * {@link #resetSizeCounter()} resets this value to zero.
672   */
673  public int getTotalBytesRead() {
674      return totalBytesRetired + bufferPos;
675  }
676
677  /**
678   * Called with {@code this.buffer} is empty to read more bytes from the
679   * input.  If {@code mustSucceed} is true, refillBuffer() gurantees that
680   * either there will be at least one byte in the buffer when it returns
681   * or it will throw an exception.  If {@code mustSucceed} is false,
682   * refillBuffer() returns false if no more bytes were available.
683   */
684  private boolean refillBuffer(final boolean mustSucceed) throws IOException {
685    if (bufferPos < bufferSize) {
686      throw new IllegalStateException(
687        "refillBuffer() called when buffer wasn't empty.");
688    }
689
690    if (totalBytesRetired + bufferSize == currentLimit) {
691      // Oops, we hit a limit.
692      if (mustSucceed) {
693        throw InvalidProtocolBufferException.truncatedMessage();
694      } else {
695        return false;
696      }
697    }
698
699    totalBytesRetired += bufferSize;
700
701    bufferPos = 0;
702    bufferSize = (input == null) ? -1 : input.read(buffer);
703    if (bufferSize == 0 || bufferSize < -1) {
704      throw new IllegalStateException(
705          "InputStream#read(byte[]) returned invalid result: " + bufferSize +
706          "\nThe InputStream implementation is buggy.");
707    }
708    if (bufferSize == -1) {
709      bufferSize = 0;
710      if (mustSucceed) {
711        throw InvalidProtocolBufferException.truncatedMessage();
712      } else {
713        return false;
714      }
715    } else {
716      recomputeBufferSizeAfterLimit();
717      final int totalBytesRead =
718        totalBytesRetired + bufferSize + bufferSizeAfterLimit;
719      if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
720        throw InvalidProtocolBufferException.sizeLimitExceeded();
721      }
722      return true;
723    }
724  }
725
726  /**
727   * Read one byte from the input.
728   *
729   * @throws InvalidProtocolBufferException The end of the stream or the current
730   *                                        limit was reached.
731   */
732  public byte readRawByte() throws IOException {
733    if (bufferPos == bufferSize) {
734      refillBuffer(true);
735    }
736    return buffer[bufferPos++];
737  }
738
739  /**
740   * Read a fixed size of bytes from the input.
741   *
742   * @throws InvalidProtocolBufferException The end of the stream or the current
743   *                                        limit was reached.
744   */
745  public byte[] readRawBytes(final int size) throws IOException {
746    if (size < 0) {
747      throw InvalidProtocolBufferException.negativeSize();
748    }
749
750    if (totalBytesRetired + bufferPos + size > currentLimit) {
751      // Read to the end of the stream anyway.
752      skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
753      // Then fail.
754      throw InvalidProtocolBufferException.truncatedMessage();
755    }
756
757    if (size <= bufferSize - bufferPos) {
758      // We have all the bytes we need already.
759      final byte[] bytes = new byte[size];
760      System.arraycopy(buffer, bufferPos, bytes, 0, size);
761      bufferPos += size;
762      return bytes;
763    } else if (size < BUFFER_SIZE) {
764      // Reading more bytes than are in the buffer, but not an excessive number
765      // of bytes.  We can safely allocate the resulting array ahead of time.
766
767      // First copy what we have.
768      final byte[] bytes = new byte[size];
769      int pos = bufferSize - bufferPos;
770      System.arraycopy(buffer, bufferPos, bytes, 0, pos);
771      bufferPos = bufferSize;
772
773      // We want to use refillBuffer() and then copy from the buffer into our
774      // byte array rather than reading directly into our byte array because
775      // the input may be unbuffered.
776      refillBuffer(true);
777
778      while (size - pos > bufferSize) {
779        System.arraycopy(buffer, 0, bytes, pos, bufferSize);
780        pos += bufferSize;
781        bufferPos = bufferSize;
782        refillBuffer(true);
783      }
784
785      System.arraycopy(buffer, 0, bytes, pos, size - pos);
786      bufferPos = size - pos;
787
788      return bytes;
789    } else {
790      // The size is very large.  For security reasons, we can't allocate the
791      // entire byte array yet.  The size comes directly from the input, so a
792      // maliciously-crafted message could provide a bogus very large size in
793      // order to trick the app into allocating a lot of memory.  We avoid this
794      // by allocating and reading only a small chunk at a time, so that the
795      // malicious message must actually *be* extremely large to cause
796      // problems.  Meanwhile, we limit the allowed size of a message elsewhere.
797
798      // Remember the buffer markers since we'll have to copy the bytes out of
799      // it later.
800      final int originalBufferPos = bufferPos;
801      final int originalBufferSize = bufferSize;
802
803      // Mark the current buffer consumed.
804      totalBytesRetired += bufferSize;
805      bufferPos = 0;
806      bufferSize = 0;
807
808      // Read all the rest of the bytes we need.
809      int sizeLeft = size - (originalBufferSize - originalBufferPos);
810      final List<byte[]> chunks = new ArrayList<byte[]>();
811
812      while (sizeLeft > 0) {
813        final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
814        int pos = 0;
815        while (pos < chunk.length) {
816          final int n = (input == null) ? -1 :
817            input.read(chunk, pos, chunk.length - pos);
818          if (n == -1) {
819            throw InvalidProtocolBufferException.truncatedMessage();
820          }
821          totalBytesRetired += n;
822          pos += n;
823        }
824        sizeLeft -= chunk.length;
825        chunks.add(chunk);
826      }
827
828      // OK, got everything.  Now concatenate it all into one buffer.
829      final byte[] bytes = new byte[size];
830
831      // Start by copying the leftover bytes from this.buffer.
832      int pos = originalBufferSize - originalBufferPos;
833      System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
834
835      // And now all the chunks.
836      for (final byte[] chunk : chunks) {
837        System.arraycopy(chunk, 0, bytes, pos, chunk.length);
838        pos += chunk.length;
839      }
840
841      // Done.
842      return bytes;
843    }
844  }
845
846  /**
847   * Reads and discards {@code size} bytes.
848   *
849   * @throws InvalidProtocolBufferException The end of the stream or the current
850   *                                        limit was reached.
851   */
852  public void skipRawBytes(final int size) throws IOException {
853    if (size < 0) {
854      throw InvalidProtocolBufferException.negativeSize();
855    }
856
857    if (totalBytesRetired + bufferPos + size > currentLimit) {
858      // Read to the end of the stream anyway.
859      skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
860      // Then fail.
861      throw InvalidProtocolBufferException.truncatedMessage();
862    }
863
864    if (size <= bufferSize - bufferPos) {
865      // We have all the bytes we need already.
866      bufferPos += size;
867    } else {
868      // Skipping more bytes than are in the buffer.  First skip what we have.
869      int pos = bufferSize - bufferPos;
870      bufferPos = bufferSize;
871
872      // Keep refilling the buffer until we get to the point we wanted to skip
873      // to.  This has the side effect of ensuring the limits are updated
874      // correctly.
875      refillBuffer(true);
876      while (size - pos > bufferSize) {
877        pos += bufferSize;
878        bufferPos = bufferSize;
879        refillBuffer(true);
880      }
881
882      bufferPos = size - pos; 
883    }
884  }
885}