1e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// Protocol Buffers - Google's data interchange format 2e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// Copyright 2008 Google Inc. All rights reserved. 3e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// http://code.google.com/p/protobuf/ 4e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// 5e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// Redistribution and use in source and binary forms, with or without 6e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// modification, are permitted provided that the following conditions are 7e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// met: 8e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// 9e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// * Redistributions of source code must retain the above copyright 10e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// notice, this list of conditions and the following disclaimer. 11e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// * Redistributions in binary form must reproduce the above 12e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// copyright notice, this list of conditions and the following disclaimer 13e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// in the documentation and/or other materials provided with the 14e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// distribution. 15e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// * Neither the name of Google Inc. nor the names of its 16e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// contributors may be used to endorse or promote products derived from 17e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// this software without specific prior written permission. 18e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// 19e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 31e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Savillepackage com.google.protobuf.micro; 32e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 33e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Savilleimport java.io.IOException; 34e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Savilleimport java.io.InputStream; 35e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 36e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville/** 37e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Reads and decodes protocol message fields. 38e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * 39e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * This class contains two kinds of methods: methods that read specific 40e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * protocol message constructs and field types (e.g. {@link #readTag()} and 41e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * {@link #readInt32()}) and methods that read low-level values (e.g. 42e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading 43e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * encoded protocol messages, you should use the former methods, but if you are 44e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * reading some other format of your own design, use the latter. 45e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * 46e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @author kenton@google.com Kenton Varda 47e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 48e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Savillepublic final class CodedInputStreamMicro { 49e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 50e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Create a new CodedInputStream wrapping the given InputStream. 51e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 52e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public static CodedInputStreamMicro newInstance(final InputStream input) { 53e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return new CodedInputStreamMicro(input); 54e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 55e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 56e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 57e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Create a new CodedInputStream wrapping the given byte array. 58e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 59e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public static CodedInputStreamMicro newInstance(final byte[] buf) { 60e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return newInstance(buf, 0, buf.length); 61e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 62e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 63e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 64e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Create a new CodedInputStream wrapping the given byte array slice. 65e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 66e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public static CodedInputStreamMicro newInstance(final byte[] buf, final int off, 67e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int len) { 68e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return new CodedInputStreamMicro(buf, off, len); 69e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 70e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 71e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // ----------------------------------------------------------------- 72e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 73e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 74e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Attempt to read a field tag, returning zero if we have reached EOF. 75e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Protocol message parsers use this to read tags, since a protocol message 76e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * may legally end wherever a tag occurs, and zero is not a valid tag number. 77e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 78e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public int readTag() throws IOException { 79e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (isAtEnd()) { 80e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville lastTag = 0; 81e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return 0; 82e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 83e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 84e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville lastTag = readRawVarint32(); 85e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (lastTag == 0) { 86e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // If we actually read zero, that's not a valid tag. 87e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.invalidTag(); 88e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 89e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return lastTag; 90e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 91e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 92e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 93e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Verifies that the last call to readTag() returned the given tag value. 94e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * This is used to verify that a nested group ended with the correct 95e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * end tag. 96e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * 97e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @throws InvalidProtocolBufferMicroException {@code value} does not match the 98e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * last tag. 99e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 100e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public void checkLastTagWas(final int value) 101e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throws InvalidProtocolBufferMicroException { 102e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (lastTag != value) { 103e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.invalidEndTag(); 104e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 105e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 106e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 107e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 108e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Reads and discards a single field, given its tag value. 109e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * 110e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @return {@code false} if the tag is an endgroup tag, in which case 111e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * nothing is skipped. Otherwise, returns {@code true}. 112e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 113e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public boolean skipField(final int tag) throws IOException { 114e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville switch (WireFormatMicro.getTagWireType(tag)) { 115e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville case WireFormatMicro.WIRETYPE_VARINT: 116e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville readInt32(); 117e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return true; 118e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville case WireFormatMicro.WIRETYPE_FIXED64: 119e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville readRawLittleEndian64(); 120e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return true; 121e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville case WireFormatMicro.WIRETYPE_LENGTH_DELIMITED: 122e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville skipRawBytes(readRawVarint32()); 123e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return true; 124e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville case WireFormatMicro.WIRETYPE_START_GROUP: 125e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville skipMessage(); 126e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville checkLastTagWas( 127e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville WireFormatMicro.makeTag(WireFormatMicro.getTagFieldNumber(tag), 128e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville WireFormatMicro.WIRETYPE_END_GROUP)); 129e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return true; 130e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville case WireFormatMicro.WIRETYPE_END_GROUP: 131e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return false; 132e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville case WireFormatMicro.WIRETYPE_FIXED32: 133e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville readRawLittleEndian32(); 134e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return true; 135e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville default: 136e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.invalidWireType(); 137e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 138e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 139e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 140e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 141e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Reads and discards an entire message. This will read either until EOF 142e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * or until an endgroup tag, whichever comes first. 143e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 144e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public void skipMessage() throws IOException { 145e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville while (true) { 146e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int tag = readTag(); 147e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (tag == 0 || !skipField(tag)) { 148e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return; 149e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 150e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 151e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 152e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 153e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // ----------------------------------------------------------------- 154e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 155e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read a {@code double} field value from the stream. */ 156e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public double readDouble() throws IOException { 157e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return Double.longBitsToDouble(readRawLittleEndian64()); 158e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 159e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 160e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read a {@code float} field value from the stream. */ 161e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public float readFloat() throws IOException { 162e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return Float.intBitsToFloat(readRawLittleEndian32()); 163e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 164e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 165e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read a {@code uint64} field value from the stream. */ 166e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public long readUInt64() throws IOException { 167e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return readRawVarint64(); 168e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 169e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 170e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read an {@code int64} field value from the stream. */ 171e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public long readInt64() throws IOException { 172e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return readRawVarint64(); 173e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 174e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 175e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read an {@code int32} field value from the stream. */ 176e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public int readInt32() throws IOException { 177e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return readRawVarint32(); 178e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 179e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 180e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read a {@code fixed64} field value from the stream. */ 181e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public long readFixed64() throws IOException { 182e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return readRawLittleEndian64(); 183e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 184e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 185e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read a {@code fixed32} field value from the stream. */ 186e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public int readFixed32() throws IOException { 187e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return readRawLittleEndian32(); 188e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 189e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 190e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read a {@code bool} field value from the stream. */ 191e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public boolean readBool() throws IOException { 192e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return readRawVarint32() != 0; 193e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 194e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 195e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read a {@code string} field value from the stream. */ 196e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public String readString() throws IOException { 197e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int size = readRawVarint32(); 198e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (size <= (bufferSize - bufferPos) && size > 0) { 199e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Fast path: We already have the bytes in a contiguous buffer, so 200e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // just copy directly from it. 201e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final String result = new String(buffer, bufferPos, size, "UTF-8"); 202e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferPos += size; 203e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return result; 204e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } else { 205e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Slow path: Build a byte array first then copy it. 206e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return new String(readRawBytes(size), "UTF-8"); 207e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 208e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 209e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 210e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read a {@code group} field value from the stream. */ 211e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public void readGroup(final MessageMicro msg, final int fieldNumber) 212e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throws IOException { 213e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (recursionDepth >= recursionLimit) { 214e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.recursionLimitExceeded(); 215e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 216e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville ++recursionDepth; 217e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville msg.mergeFrom(this); 218e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville checkLastTagWas( 219e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville WireFormatMicro.makeTag(fieldNumber, WireFormatMicro.WIRETYPE_END_GROUP)); 220e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville --recursionDepth; 221e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 222e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 223e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public void readMessage(final MessageMicro msg) 224e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throws IOException { 225e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int length = readRawVarint32(); 226e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (recursionDepth >= recursionLimit) { 227e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.recursionLimitExceeded(); 228e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 229e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int oldLimit = pushLimit(length); 230e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville ++recursionDepth; 231e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville msg.mergeFrom(this); 232e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville checkLastTagWas(0); 233e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville --recursionDepth; 234e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville popLimit(oldLimit); 235e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 236e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 237e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read a {@code bytes} field value from the stream. */ 238e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public ByteStringMicro readBytes() throws IOException { 239e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int size = readRawVarint32(); 240e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (size <= (bufferSize - bufferPos) && size > 0) { 241e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Fast path: We already have the bytes in a contiguous buffer, so 242e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // just copy directly from it. 243e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final ByteStringMicro result = ByteStringMicro.copyFrom(buffer, bufferPos, size); 244e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferPos += size; 245e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return result; 2464d8b123b8985b3f87a640be2d9a1b4b730b5fdcaAndre Eisenbach } else if (size == 0) { 2474d8b123b8985b3f87a640be2d9a1b4b730b5fdcaAndre Eisenbach return ByteStringMicro.EMPTY; 248e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } else { 249e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Slow path: Build a byte array first then copy it. 250e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return ByteStringMicro.copyFrom(readRawBytes(size)); 251e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 252e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 253e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 254e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read a {@code uint32} field value from the stream. */ 255e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public int readUInt32() throws IOException { 256e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return readRawVarint32(); 257e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 258e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 259e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 260e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Read an enum field value from the stream. Caller is responsible 261e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * for converting the numeric value to an actual enum. 262e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 263e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public int readEnum() throws IOException { 264e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return readRawVarint32(); 265e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 266e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 267e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read an {@code sfixed32} field value from the stream. */ 268e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public int readSFixed32() throws IOException { 269e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return readRawLittleEndian32(); 270e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 271e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 272e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read an {@code sfixed64} field value from the stream. */ 273e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public long readSFixed64() throws IOException { 274e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return readRawLittleEndian64(); 275e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 276e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 277e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read an {@code sint32} field value from the stream. */ 278e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public int readSInt32() throws IOException { 279e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return decodeZigZag32(readRawVarint32()); 280e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 281e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 282e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read an {@code sint64} field value from the stream. */ 283e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public long readSInt64() throws IOException { 284e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return decodeZigZag64(readRawVarint64()); 285e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 286e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 287e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // ================================================================= 288e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 289e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 290e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Read a raw Varint from the stream. If larger than 32 bits, discard the 291e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * upper bits. 292e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 293e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public int readRawVarint32() throws IOException { 294e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville byte tmp = readRawByte(); 295e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (tmp >= 0) { 296e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return tmp; 297e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 298e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville int result = tmp & 0x7f; 299e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if ((tmp = readRawByte()) >= 0) { 300e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville result |= tmp << 7; 301e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } else { 302e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville result |= (tmp & 0x7f) << 7; 303e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if ((tmp = readRawByte()) >= 0) { 304e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville result |= tmp << 14; 305e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } else { 306e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville result |= (tmp & 0x7f) << 14; 307e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if ((tmp = readRawByte()) >= 0) { 308e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville result |= tmp << 21; 309e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } else { 310e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville result |= (tmp & 0x7f) << 21; 311e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville result |= (tmp = readRawByte()) << 28; 312e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (tmp < 0) { 313e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Discard upper 32 bits. 314e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville for (int i = 0; i < 5; i++) { 315e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (readRawByte() >= 0) { 316e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return result; 317e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 318e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 319e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.malformedVarint(); 320e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 321e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 322e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 323e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 324e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return result; 325e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 326e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 327e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 328e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Reads a varint from the input one byte at a time, so that it does not 329e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * read any bytes after the end of the varint. If you simply wrapped the 330e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)} 331e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * then you would probably end up reading past the end of the varint since 332e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * CodedInputStream buffers its input. 333e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 334e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville static int readRawVarint32(final InputStream input) throws IOException { 335e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville int result = 0; 336e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville int offset = 0; 337e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville for (; offset < 32; offset += 7) { 338e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int b = input.read(); 339e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (b == -1) { 340e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.truncatedMessage(); 341e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 342e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville result |= (b & 0x7f) << offset; 343e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if ((b & 0x80) == 0) { 344e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return result; 345e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 346e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 347e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Keep reading up to 64 bits. 348e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville for (; offset < 64; offset += 7) { 349e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int b = input.read(); 350e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (b == -1) { 351e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.truncatedMessage(); 352e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 353e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if ((b & 0x80) == 0) { 354e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return result; 355e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 356e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 357e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.malformedVarint(); 358e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 359e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 360e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read a raw Varint from the stream. */ 361e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public long readRawVarint64() throws IOException { 362e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville int shift = 0; 363e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville long result = 0; 364e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville while (shift < 64) { 365e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte b = readRawByte(); 366e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville result |= (long)(b & 0x7F) << shift; 367e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if ((b & 0x80) == 0) { 368e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return result; 369e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 370e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville shift += 7; 371e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 372e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.malformedVarint(); 373e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 374e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 375e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read a 32-bit little-endian integer from the stream. */ 376e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public int readRawLittleEndian32() throws IOException { 377e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte b1 = readRawByte(); 378e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte b2 = readRawByte(); 379e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte b3 = readRawByte(); 380e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte b4 = readRawByte(); 381e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return ((b1 & 0xff) ) | 382e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville ((b2 & 0xff) << 8) | 383e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville ((b3 & 0xff) << 16) | 384e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville ((b4 & 0xff) << 24); 385e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 386e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 387e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** Read a 64-bit little-endian integer from the stream. */ 388e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public long readRawLittleEndian64() throws IOException { 389e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte b1 = readRawByte(); 390e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte b2 = readRawByte(); 391e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte b3 = readRawByte(); 392e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte b4 = readRawByte(); 393e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte b5 = readRawByte(); 394e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte b6 = readRawByte(); 395e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte b7 = readRawByte(); 396e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte b8 = readRawByte(); 397e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return (((long)b1 & 0xff) ) | 398e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville (((long)b2 & 0xff) << 8) | 399e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville (((long)b3 & 0xff) << 16) | 400e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville (((long)b4 & 0xff) << 24) | 401e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville (((long)b5 & 0xff) << 32) | 402e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville (((long)b6 & 0xff) << 40) | 403e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville (((long)b7 & 0xff) << 48) | 404e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville (((long)b8 & 0xff) << 56); 405e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 406e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 407e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 408e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers 409e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * into values that can be efficiently encoded with varint. (Otherwise, 410e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * negative values must be sign-extended to 64 bits to be varint encoded, 411e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * thus always taking 10 bytes on the wire.) 412e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * 413e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @param n An unsigned 32-bit integer, stored in a signed int because 414e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Java has no explicit unsigned support. 415e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @return A signed 32-bit integer. 416e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 417e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public static int decodeZigZag32(final int n) { 418e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return (n >>> 1) ^ -(n & 1); 419e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 420e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 421e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 422e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers 423e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * into values that can be efficiently encoded with varint. (Otherwise, 424e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * negative values must be sign-extended to 64 bits to be varint encoded, 425e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * thus always taking 10 bytes on the wire.) 426e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * 427e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @param n An unsigned 64-bit integer, stored in a signed int because 428e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Java has no explicit unsigned support. 429e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @return A signed 64-bit integer. 430e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 431e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public static long decodeZigZag64(final long n) { 432e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return (n >>> 1) ^ -(n & 1); 433e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 434e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 435e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // ----------------------------------------------------------------- 436e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 437e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private final byte[] buffer; 438e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private int bufferSize; 439e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private int bufferSizeAfterLimit; 440e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private int bufferPos; 441e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private final InputStream input; 442e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private int lastTag; 443e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 444e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 445e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * The total number of bytes read before the current buffer. The total 446e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * bytes read up to the current position can be computed as 447e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * {@code totalBytesRetired + bufferPos}. 448e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 449e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private int totalBytesRetired; 450e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 451e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** The absolute position of the end of the current message. */ 452e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private int currentLimit = Integer.MAX_VALUE; 453e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 454e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** See setRecursionLimit() */ 455e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private int recursionDepth; 456e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private int recursionLimit = DEFAULT_RECURSION_LIMIT; 457e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 458e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** See setSizeLimit() */ 459e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private int sizeLimit = DEFAULT_SIZE_LIMIT; 460e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 461e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private static final int DEFAULT_RECURSION_LIMIT = 64; 462e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB 463e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private static final int BUFFER_SIZE = 4096; 464e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 465e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private CodedInputStreamMicro(final byte[] buffer, final int off, final int len) { 466e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville this.buffer = buffer; 467e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferSize = off + len; 468e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferPos = off; 469e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville input = null; 470e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 471e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 472e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private CodedInputStreamMicro(final InputStream input) { 473e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville buffer = new byte[BUFFER_SIZE]; 474e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferSize = 0; 475e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferPos = 0; 476e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville this.input = input; 477e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 478e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 479e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 480e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Set the maximum message recursion depth. In order to prevent malicious 481e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * messages from causing stack overflows, {@code CodedInputStream} limits 482e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * how deeply messages may be nested. The default limit is 64. 483e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * 484e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @return the old limit. 485e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 486e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public int setRecursionLimit(final int limit) { 487e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (limit < 0) { 488e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw new IllegalArgumentException( 489e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville "Recursion limit cannot be negative: " + limit); 490e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 491e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int oldLimit = recursionLimit; 492e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville recursionLimit = limit; 493e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return oldLimit; 494e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 495e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 496e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 497e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Set the maximum message size. In order to prevent malicious 498e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * messages from exhausting memory or causing integer overflows, 499e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * {@code CodedInputStream} limits how large a message may be. 500e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * The default limit is 64MB. You should set this limit as small 501e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * as you can without harming your app's functionality. Note that 502e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * size limits only apply when reading from an {@code InputStream}, not 503e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * when constructed around a raw byte array (nor with 504e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * {@link ByteStringMicro#newCodedInput}). 505e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * <p> 506e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * If you want to read several messages from a single CodedInputStream, you 507e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * could call {@link #resetSizeCounter()} after each one to avoid hitting the 508e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * size limit. 509e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * 510e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @return the old limit. 511e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 512e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public int setSizeLimit(final int limit) { 513e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (limit < 0) { 514e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw new IllegalArgumentException( 515e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville "Size limit cannot be negative: " + limit); 516e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 517e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int oldLimit = sizeLimit; 518e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville sizeLimit = limit; 519e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return oldLimit; 520e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 521e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 522e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 523e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). 524e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 525e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public void resetSizeCounter() { 526e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville totalBytesRetired = 0; 527e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 528e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 529e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 530e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This 531e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * is called when descending into a length-delimited embedded message. 532e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * 533e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @return the old limit. 534e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 535e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public int pushLimit(int byteLimit) throws InvalidProtocolBufferMicroException { 536e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (byteLimit < 0) { 537e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.negativeSize(); 538e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 539e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville byteLimit += totalBytesRetired + bufferPos; 540e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int oldLimit = currentLimit; 541e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (byteLimit > oldLimit) { 542e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.truncatedMessage(); 543e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 544e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville currentLimit = byteLimit; 545e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 546e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville recomputeBufferSizeAfterLimit(); 547e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 548e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return oldLimit; 549e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 550e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 551e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private void recomputeBufferSizeAfterLimit() { 552e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferSize += bufferSizeAfterLimit; 553e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int bufferEnd = totalBytesRetired + bufferSize; 554e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (bufferEnd > currentLimit) { 555e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Limit is in current buffer. 556e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferSizeAfterLimit = bufferEnd - currentLimit; 557e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferSize -= bufferSizeAfterLimit; 558e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } else { 559e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferSizeAfterLimit = 0; 560e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 561e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 562e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 563e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 564e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Discards the current limit, returning to the previous limit. 565e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * 566e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @param oldLimit The old limit, as returned by {@code pushLimit}. 567e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 568e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public void popLimit(final int oldLimit) { 569e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville currentLimit = oldLimit; 570e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville recomputeBufferSizeAfterLimit(); 571e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 572e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 573e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 574e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Returns the number of bytes to be read before the current limit. 575e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * If no limit is set, returns -1. 576e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 577e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public int getBytesUntilLimit() { 578e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (currentLimit == Integer.MAX_VALUE) { 579e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return -1; 580e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 581e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 582e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int currentAbsolutePosition = totalBytesRetired + bufferPos; 583e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return currentLimit - currentAbsolutePosition; 584e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 585e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 586e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 587e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Returns true if the stream has reached the end of the input. This is the 588e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * case if either the end of the underlying input source has been reached or 589e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * if the stream has reached a limit created using {@link #pushLimit(int)}. 590e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 591e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public boolean isAtEnd() throws IOException { 592e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return bufferPos == bufferSize && !refillBuffer(false); 593e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 594e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 595e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 596e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Called with {@code this.buffer} is empty to read more bytes from the 597e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * input. If {@code mustSucceed} is true, refillBuffer() gurantees that 598e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * either there will be at least one byte in the buffer when it returns 599e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * or it will throw an exception. If {@code mustSucceed} is false, 600e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * refillBuffer() returns false if no more bytes were available. 601e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 602e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville private boolean refillBuffer(final boolean mustSucceed) throws IOException { 603e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (bufferPos < bufferSize) { 604e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw new IllegalStateException( 605e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville "refillBuffer() called when buffer wasn't empty."); 606e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 607e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 608e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (totalBytesRetired + bufferSize == currentLimit) { 609e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Oops, we hit a limit. 610e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (mustSucceed) { 611e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.truncatedMessage(); 612e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } else { 613e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return false; 614e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 615e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 616e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 617e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville totalBytesRetired += bufferSize; 618e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 619e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferPos = 0; 620e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferSize = (input == null) ? -1 : input.read(buffer); 621e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (bufferSize == 0 || bufferSize < -1) { 622e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw new IllegalStateException( 623e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville "InputStream#read(byte[]) returned invalid result: " + bufferSize + 624e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville "\nThe InputStream implementation is buggy."); 625e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 626e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (bufferSize == -1) { 627e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferSize = 0; 628e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (mustSucceed) { 629e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.truncatedMessage(); 630e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } else { 631e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return false; 632e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 633e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } else { 634e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville recomputeBufferSizeAfterLimit(); 635e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int totalBytesRead = 636e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville totalBytesRetired + bufferSize + bufferSizeAfterLimit; 637e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (totalBytesRead > sizeLimit || totalBytesRead < 0) { 638e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.sizeLimitExceeded(); 639e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 640e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return true; 641e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 642e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 643e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 644e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 645e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Read one byte from the input. 646e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * 647e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @throws InvalidProtocolBufferMicroException The end of the stream or the current 648e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * limit was reached. 649e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 650e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public byte readRawByte() throws IOException { 651e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (bufferPos == bufferSize) { 652e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville refillBuffer(true); 653e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 654e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return buffer[bufferPos++]; 655e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 656e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 657e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 658e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Read a fixed size of bytes from the input. 659e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * 660e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @throws InvalidProtocolBufferMicroException The end of the stream or the current 661e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * limit was reached. 662e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 663e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public byte[] readRawBytes(final int size) throws IOException { 664e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (size < 0) { 665e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.negativeSize(); 666e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 667e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 668e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (totalBytesRetired + bufferPos + size > currentLimit) { 669e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Read to the end of the stream anyway. 670e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville skipRawBytes(currentLimit - totalBytesRetired - bufferPos); 671e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Then fail. 672e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.truncatedMessage(); 673e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 674e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 675e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (size <= bufferSize - bufferPos) { 676e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // We have all the bytes we need already. 677e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte[] bytes = new byte[size]; 678e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville System.arraycopy(buffer, bufferPos, bytes, 0, size); 679e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferPos += size; 680e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return bytes; 681e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } else if (size < BUFFER_SIZE) { 682e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Reading more bytes than are in the buffer, but not an excessive number 683e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // of bytes. We can safely allocate the resulting array ahead of time. 684e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 685e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // First copy what we have. 686e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte[] bytes = new byte[size]; 687e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville int pos = bufferSize - bufferPos; 688e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville System.arraycopy(buffer, bufferPos, bytes, 0, pos); 689e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferPos = bufferSize; 690e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 691e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // We want to use refillBuffer() and then copy from the buffer into our 692e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // byte array rather than reading directly into our byte array because 693e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // the input may be unbuffered. 694e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville refillBuffer(true); 695e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 696e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville while (size - pos > bufferSize) { 697e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville System.arraycopy(buffer, 0, bytes, pos, bufferSize); 698e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville pos += bufferSize; 699e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferPos = bufferSize; 700e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville refillBuffer(true); 701e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 702e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 703e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville System.arraycopy(buffer, 0, bytes, pos, size - pos); 704e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferPos = size - pos; 705e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 706e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return bytes; 707e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } else { 708e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // The size is very large. For security reasons, we can't allocate the 709e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // entire byte array yet. The size comes directly from the input, so a 710e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // maliciously-crafted message could provide a bogus very large size in 711e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // order to trick the app into allocating a lot of memory. We avoid this 712e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // by allocating and reading only a small chunk at a time, so that the 713e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // malicious message must actually *be* extremely large to cause 714e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // problems. Meanwhile, we limit the allowed size of a message elsewhere. 715e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 716e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Remember the buffer markers since we'll have to copy the bytes out of 717e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // it later. 718e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int originalBufferPos = bufferPos; 719e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int originalBufferSize = bufferSize; 720e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 721e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Mark the current buffer consumed. 722e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville totalBytesRetired += bufferSize; 723e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferPos = 0; 724e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferSize = 0; 725e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 726e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Read all the rest of the bytes we need. 727e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville int sizeLeft = size - (originalBufferSize - originalBufferPos); 728e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 729e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // For compatibility with Java 1.3 use Vector 730e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final java.util.Vector chunks = new java.util.Vector(); 731e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 732e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville while (sizeLeft > 0) { 733e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)]; 734e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville int pos = 0; 735e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville while (pos < chunk.length) { 736e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int n = (input == null) ? -1 : 737e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville input.read(chunk, pos, chunk.length - pos); 738e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (n == -1) { 739e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.truncatedMessage(); 740e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 741e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville totalBytesRetired += n; 742e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville pos += n; 743e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 744e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville sizeLeft -= chunk.length; 745e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville chunks.addElement(chunk); 746e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 747e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 748e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // OK, got everything. Now concatenate it all into one buffer. 749e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final byte[] bytes = new byte[size]; 750e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 751e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Start by copying the leftover bytes from this.buffer. 752e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville int pos = originalBufferSize - originalBufferPos; 753e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville System.arraycopy(buffer, originalBufferPos, bytes, 0, pos); 754e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 755e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // And now all the chunks. 756e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville for (int i = 0; i < chunks.size(); i++) { 757e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville byte [] chunk = (byte [])chunks.elementAt(i); 758e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville System.arraycopy(chunk, 0, bytes, pos, chunk.length); 759e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville pos += chunk.length; 760e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 761e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 762e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Done. 763e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville return bytes; 764e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 765e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 766e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 767e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville /** 768e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * Reads and discards {@code size} bytes. 769e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * 770e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * @throws InvalidProtocolBufferMicroException The end of the stream or the current 771e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville * limit was reached. 772e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville */ 773e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville public void skipRawBytes(final int size) throws IOException { 774e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (size < 0) { 775e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.negativeSize(); 776e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 777e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 778e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (totalBytesRetired + bufferPos + size > currentLimit) { 779e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Read to the end of the stream anyway. 780e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville skipRawBytes(currentLimit - totalBytesRetired - bufferPos); 781e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Then fail. 782e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.truncatedMessage(); 783e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 784e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 785e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (size <= bufferSize - bufferPos) { 786e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // We have all the bytes we need already. 787e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferPos += size; 788e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } else { 789e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Skipping more bytes than are in the buffer. First skip what we have. 790e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville int pos = bufferSize - bufferPos; 7918a2f7578bb6289415f1d0a01c9cc96d283730480Wink Saville totalBytesRetired += bufferSize; 792e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferPos = 0; 793e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville bufferSize = 0; 794e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville 795e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville // Then skip directly from the InputStream for the rest. 796e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville while (pos < size) { 797e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville final int n = (input == null) ? -1 : (int) input.skip(size - pos); 798e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville if (n <= 0) { 799e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville throw InvalidProtocolBufferMicroException.truncatedMessage(); 800e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 801e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville pos += n; 802e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville totalBytesRetired += n; 803e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 804e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 805e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville } 806e2d542951c059563a3b7f74c257dac4f222d9dc5Wink Saville} 807