Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
87 Kevin 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
 
31
package com.google.protobuf;
32
 
33
import java.io.IOException;
34
import java.io.InputStream;
35
import java.util.ArrayList;
36
import 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
 */
50
public 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
}