1fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Protocol Buffers - Google's data interchange format 2fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Copyright 2008 Google Inc. All rights reserved. 3afb4b72037e3f13db208590fc782c4bc8e27f862Jeff Davidson// https://developers.google.com/protocol-buffers/ 4fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// 5fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Redistribution and use in source and binary forms, with or without 6fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// modification, are permitted provided that the following conditions are 7fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// met: 8fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// 9fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// * Redistributions of source code must retain the above copyright 10fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// notice, this list of conditions and the following disclaimer. 11fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// * Redistributions in binary form must reproduce the above 12fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// copyright notice, this list of conditions and the following disclaimer 13fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// in the documentation and/or other materials provided with the 14fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// distribution. 15fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// * Neither the name of Google Inc. nor the names of its 16fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// contributors may be used to endorse or promote products derived from 17fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// this software without specific prior written permission. 18fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// 19fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 31fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillepackage com.google.protobuf; 32fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 33a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonimport java.io.ByteArrayOutputStream; 34fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport java.io.IOException; 35fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport java.io.InputStream; 36a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonimport java.nio.ByteBuffer; 37fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport java.util.ArrayList; 38a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonimport java.util.Arrays; 39fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport java.util.List; 40fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 41fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville/** 42fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Reads and decodes protocol message fields. 43fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 44fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * This class contains two kinds of methods: methods that read specific 45fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * protocol message constructs and field types (e.g. {@link #readTag()} and 46fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * {@link #readInt32()}) and methods that read low-level values (e.g. 47fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading 48fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * encoded protocol messages, you should use the former methods, but if you are 49fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * reading some other format of your own design, use the latter. 50fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 51fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @author kenton@google.com Kenton Varda 52fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 53fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillepublic final class CodedInputStream { 54fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 55fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Create a new CodedInputStream wrapping the given InputStream. 56fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 57fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public static CodedInputStream newInstance(final InputStream input) { 58fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return new CodedInputStream(input); 59fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 60fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 61fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 62fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Create a new CodedInputStream wrapping the given byte array. 63fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 64fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public static CodedInputStream newInstance(final byte[] buf) { 65fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return newInstance(buf, 0, buf.length); 66fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 67fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 68fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 69fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Create a new CodedInputStream wrapping the given byte array slice. 70fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 71fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public static CodedInputStream newInstance(final byte[] buf, final int off, 72fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int len) { 73a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson CodedInputStream result = new CodedInputStream(buf, off, len); 74a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson try { 75a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Some uses of CodedInputStream can be more efficient if they know 76a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // exactly how many bytes are available. By pushing the end point of the 77a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // buffer as a limit, we allow them to get this information via 78a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // getBytesUntilLimit(). Pushing a limit that we know is at the end of 79a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // the stream can never hurt, since we can never past that point anyway. 80a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson result.pushLimit(len); 81a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } catch (InvalidProtocolBufferException ex) { 82a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // The only reason pushLimit() might throw an exception here is if len 83a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // is negative. Normally pushLimit()'s parameter comes directly off the 84a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // wire, so it's important to catch exceptions in case of corrupt or 85a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // malicious data. However, in this case, we expect that len is not a 86a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // user-supplied value, so we can assume that it being negative indicates 87a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // a programming error. Therefore, throwing an unchecked exception is 88a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // appropriate. 89a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throw new IllegalArgumentException(ex); 90a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 91a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return result; 92a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 93a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 94a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 95a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Create a new CodedInputStream wrapping the given ByteBuffer. The data 96a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * starting from the ByteBuffer's current position to its limit will be read. 97a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * The returned CodedInputStream may or may not share the underlying data 98a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * in the ByteBuffer, therefore the ByteBuffer cannot be changed while the 99a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * CodedInputStream is in use. 100a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Note that the ByteBuffer's position won't be changed by this function. 101a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Concurrent calls with the same ByteBuffer object are safe if no other 102a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * thread is trying to alter the ByteBuffer's status. 103a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 104a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static CodedInputStream newInstance(ByteBuffer buf) { 105a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (buf.hasArray()) { 106a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return newInstance(buf.array(), buf.arrayOffset() + buf.position(), 107a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson buf.remaining()); 108a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 109a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ByteBuffer temp = buf.duplicate(); 110a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson byte[] buffer = new byte[temp.remaining()]; 111a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson temp.get(buffer); 112a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return newInstance(buffer); 113a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 114a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 115a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 116a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 117a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Create a new CodedInputStream wrapping a LiteralByteString. 118a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 119a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson static CodedInputStream newInstance(LiteralByteString byteString) { 120a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson CodedInputStream result = new CodedInputStream(byteString); 121a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson try { 122a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Some uses of CodedInputStream can be more efficient if they know 123a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // exactly how many bytes are available. By pushing the end point of the 124a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // buffer as a limit, we allow them to get this information via 125a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // getBytesUntilLimit(). Pushing a limit that we know is at the end of 126a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // the stream can never hurt, since we can never past that point anyway. 127a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson result.pushLimit(byteString.size()); 128a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } catch (InvalidProtocolBufferException ex) { 129a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // The only reason pushLimit() might throw an exception here is if len 130a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // is negative. Normally pushLimit()'s parameter comes directly off the 131a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // wire, so it's important to catch exceptions in case of corrupt or 132a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // malicious data. However, in this case, we expect that len is not a 133a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // user-supplied value, so we can assume that it being negative indicates 134a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // a programming error. Therefore, throwing an unchecked exception is 135a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // appropriate. 136a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throw new IllegalArgumentException(ex); 137a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 138a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return result; 139fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 140fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 141fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // ----------------------------------------------------------------- 142fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 143fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 144fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Attempt to read a field tag, returning zero if we have reached EOF. 145fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Protocol message parsers use this to read tags, since a protocol message 146fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * may legally end wherever a tag occurs, and zero is not a valid tag number. 147fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 148fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public int readTag() throws IOException { 149fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (isAtEnd()) { 150fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville lastTag = 0; 151fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return 0; 152fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 153fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 154fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville lastTag = readRawVarint32(); 155d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville if (WireFormat.getTagFieldNumber(lastTag) == 0) { 156d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville // If we actually read zero (or any tag number corresponding to field 157d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville // number zero), that's not a valid tag. 158fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.invalidTag(); 159fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 160fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return lastTag; 161fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 162fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 163fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 164fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Verifies that the last call to readTag() returned the given tag value. 165fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * This is used to verify that a nested group ended with the correct 166fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * end tag. 167fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 168fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @throws InvalidProtocolBufferException {@code value} does not match the 169fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * last tag. 170fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 171fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public void checkLastTagWas(final int value) 172fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throws InvalidProtocolBufferException { 173fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (lastTag != value) { 174fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.invalidEndTag(); 175fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 176fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 177fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 178a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public int getLastTag() { 179a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return lastTag; 180a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 181a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 182fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 183fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Reads and discards a single field, given its tag value. 184fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 185fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @return {@code false} if the tag is an endgroup tag, in which case 186fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * nothing is skipped. Otherwise, returns {@code true}. 187fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 188fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public boolean skipField(final int tag) throws IOException { 189fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville switch (WireFormat.getTagWireType(tag)) { 190fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville case WireFormat.WIRETYPE_VARINT: 191a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson skipRawVarint(); 192fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return true; 193fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville case WireFormat.WIRETYPE_FIXED64: 194a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson skipRawBytes(8); 195fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return true; 196fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville case WireFormat.WIRETYPE_LENGTH_DELIMITED: 197fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville skipRawBytes(readRawVarint32()); 198fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return true; 199fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville case WireFormat.WIRETYPE_START_GROUP: 200fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville skipMessage(); 201fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville checkLastTagWas( 202fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), 203fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville WireFormat.WIRETYPE_END_GROUP)); 204fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return true; 205fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville case WireFormat.WIRETYPE_END_GROUP: 206fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return false; 207fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville case WireFormat.WIRETYPE_FIXED32: 208a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson skipRawBytes(4); 209fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return true; 210fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville default: 211fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.invalidWireType(); 212fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 213fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 214fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 215fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 216a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Reads a single field and writes it to output in wire format, 217a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * given its tag value. 218a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 219a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return {@code false} if the tag is an endgroup tag, in which case 220a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * nothing is skipped. Otherwise, returns {@code true}. 221a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 222a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public boolean skipField(final int tag, final CodedOutputStream output) 223a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throws IOException { 224a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson switch (WireFormat.getTagWireType(tag)) { 225a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson case WireFormat.WIRETYPE_VARINT: { 226a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson long value = readInt64(); 227a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson output.writeRawVarint32(tag); 228a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson output.writeUInt64NoTag(value); 229a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return true; 230a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 231a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson case WireFormat.WIRETYPE_FIXED64: { 232a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson long value = readRawLittleEndian64(); 233a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson output.writeRawVarint32(tag); 234a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson output.writeFixed64NoTag(value); 235a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return true; 236a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 237a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson case WireFormat.WIRETYPE_LENGTH_DELIMITED: { 238a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ByteString value = readBytes(); 239a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson output.writeRawVarint32(tag); 240a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson output.writeBytesNoTag(value); 241a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return true; 242a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 243a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson case WireFormat.WIRETYPE_START_GROUP: { 244a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson output.writeRawVarint32(tag); 245a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson skipMessage(output); 246a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int endtag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), 247a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson WireFormat.WIRETYPE_END_GROUP); 248a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson checkLastTagWas(endtag); 249a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson output.writeRawVarint32(endtag); 250a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return true; 251a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 252a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson case WireFormat.WIRETYPE_END_GROUP: { 253a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return false; 254a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 255a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson case WireFormat.WIRETYPE_FIXED32: { 256a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int value = readRawLittleEndian32(); 257a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson output.writeRawVarint32(tag); 258a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson output.writeFixed32NoTag(value); 259a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return true; 260a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 261a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson default: 262a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throw InvalidProtocolBufferException.invalidWireType(); 263a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 264a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 265a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 266a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 267fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Reads and discards an entire message. This will read either until EOF 268fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * or until an endgroup tag, whichever comes first. 269fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 270fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public void skipMessage() throws IOException { 271fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville while (true) { 272fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int tag = readTag(); 273fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (tag == 0 || !skipField(tag)) { 274fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return; 275fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 276fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 277fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 278fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 279a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 280a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Reads an entire message and writes it to output in wire format. 281a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * This will read either until EOF or until an endgroup tag, 282a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * whichever comes first. 283a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 284a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public void skipMessage(CodedOutputStream output) throws IOException { 285a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson while (true) { 286a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final int tag = readTag(); 287a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (tag == 0 || !skipField(tag, output)) { 288a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return; 289a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 290a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 291a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 292a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 293a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 294a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Collects the bytes skipped and returns the data in a ByteBuffer. 295a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 296a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private class SkippedDataSink implements RefillCallback { 297a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private int lastPos = bufferPos; 298a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private ByteArrayOutputStream byteArrayStream; 299a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 300a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson @Override 301a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public void onRefill() { 302a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (byteArrayStream == null) { 303a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson byteArrayStream = new ByteArrayOutputStream(); 304a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 305a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson byteArrayStream.write(buffer, lastPos, bufferPos - lastPos); 306a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson lastPos = 0; 307a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 308a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 309a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 310a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Gets skipped data in a ByteBuffer. This method should only be 311a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * called once. 312a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 313a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ByteBuffer getSkippedData() { 314a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (byteArrayStream == null) { 315a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return ByteBuffer.wrap(buffer, lastPos, bufferPos - lastPos); 316a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 317a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson byteArrayStream.write(buffer, lastPos, bufferPos); 318a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return ByteBuffer.wrap(byteArrayStream.toByteArray()); 319a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 320a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 321a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 322a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 323a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 324fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // ----------------------------------------------------------------- 325fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 326fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read a {@code double} field value from the stream. */ 327fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public double readDouble() throws IOException { 328fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return Double.longBitsToDouble(readRawLittleEndian64()); 329fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 330fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 331fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read a {@code float} field value from the stream. */ 332fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public float readFloat() throws IOException { 333fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return Float.intBitsToFloat(readRawLittleEndian32()); 334fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 335fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 336fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read a {@code uint64} field value from the stream. */ 337fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public long readUInt64() throws IOException { 338fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return readRawVarint64(); 339fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 340fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 341fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read an {@code int64} field value from the stream. */ 342fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public long readInt64() throws IOException { 343fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return readRawVarint64(); 344fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 345fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 346fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read an {@code int32} field value from the stream. */ 347fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public int readInt32() throws IOException { 348fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return readRawVarint32(); 349fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 350fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 351fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read a {@code fixed64} field value from the stream. */ 352fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public long readFixed64() throws IOException { 353fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return readRawLittleEndian64(); 354fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 355fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 356fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read a {@code fixed32} field value from the stream. */ 357fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public int readFixed32() throws IOException { 358fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return readRawLittleEndian32(); 359fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 360fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 361fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read a {@code bool} field value from the stream. */ 362fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public boolean readBool() throws IOException { 363a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return readRawVarint64() != 0; 364fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 365fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 366a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 367a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Read a {@code string} field value from the stream. 368a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * If the stream contains malformed UTF-8, 369a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * replace the offending bytes with the standard UTF-8 replacement character. 370a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 371fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public String readString() throws IOException { 372fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int size = readRawVarint32(); 373fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (size <= (bufferSize - bufferPos) && size > 0) { 374fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Fast path: We already have the bytes in a contiguous buffer, so 375fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // just copy directly from it. 376fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final String result = new String(buffer, bufferPos, size, "UTF-8"); 377fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferPos += size; 378fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return result; 379a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if (size == 0) { 380a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return ""; 381fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } else { 382fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Slow path: Build a byte array first then copy it. 383a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return new String(readRawBytesSlowPath(size), "UTF-8"); 384a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 385a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 386a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 387a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 388a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Read a {@code string} field value from the stream. 389a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * If the stream contains malformed UTF-8, 390a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * throw exception {@link InvalidProtocolBufferException}. 391a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 392a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public String readStringRequireUtf8() throws IOException { 393a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final int size = readRawVarint32(); 394a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final byte[] bytes; 395a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int pos = bufferPos; 396a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (size <= (bufferSize - pos) && size > 0) { 397a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Fast path: We already have the bytes in a contiguous buffer, so 398a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // just copy directly from it. 399a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bytes = buffer; 400a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = pos + size; 401a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if (size == 0) { 402a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return ""; 403a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 404a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Slow path: Build a byte array first then copy it. 405a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bytes = readRawBytesSlowPath(size); 406a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson pos = 0; 407a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 408a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // TODO(martinrb): We could save a pass by validating while decoding. 409a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (!Utf8.isValidUtf8(bytes, pos, pos + size)) { 410a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throw InvalidProtocolBufferException.invalidUtf8(); 411fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 412a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return new String(bytes, pos, size, "UTF-8"); 413fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 414fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 415fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read a {@code group} field value from the stream. */ 416fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public void readGroup(final int fieldNumber, 417fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final MessageLite.Builder builder, 418fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final ExtensionRegistryLite extensionRegistry) 419fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throws IOException { 420fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (recursionDepth >= recursionLimit) { 421fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.recursionLimitExceeded(); 422fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 423fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville ++recursionDepth; 424fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville builder.mergeFrom(this, extensionRegistry); 425fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville checkLastTagWas( 426fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); 427fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville --recursionDepth; 428fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 429fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 430a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 431a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** Read a {@code group} field value from the stream. */ 432a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public <T extends MessageLite> T readGroup( 433a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final int fieldNumber, 434a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final Parser<T> parser, 435a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final ExtensionRegistryLite extensionRegistry) 436a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throws IOException { 437a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (recursionDepth >= recursionLimit) { 438a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throw InvalidProtocolBufferException.recursionLimitExceeded(); 439a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 440a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ++recursionDepth; 441a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson T result = parser.parsePartialFrom(this, extensionRegistry); 442a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson checkLastTagWas( 443a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); 444a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson --recursionDepth; 445a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return result; 446a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 447a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 448fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 449fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Reads a {@code group} field value from the stream and merges it into the 450fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * given {@link UnknownFieldSet}. 451fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 452fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so 453fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * you can just call {@link #readGroup}. 454fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 455fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville @Deprecated 456fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public void readUnknownGroup(final int fieldNumber, 457fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final MessageLite.Builder builder) 458fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throws IOException { 459fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // We know that UnknownFieldSet will ignore any ExtensionRegistry so it 460fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // is safe to pass null here. (We can't call 461fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // ExtensionRegistry.getEmptyRegistry() because that would make this 462fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // class depend on ExtensionRegistry, which is not part of the lite 463fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // library.) 464fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville readGroup(fieldNumber, builder, null); 465fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 466fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 467fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read an embedded message field value from the stream. */ 468fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public void readMessage(final MessageLite.Builder builder, 469fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final ExtensionRegistryLite extensionRegistry) 470fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throws IOException { 471fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int length = readRawVarint32(); 472fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (recursionDepth >= recursionLimit) { 473fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.recursionLimitExceeded(); 474fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 475fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int oldLimit = pushLimit(length); 476fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville ++recursionDepth; 477fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville builder.mergeFrom(this, extensionRegistry); 478fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville checkLastTagWas(0); 479fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville --recursionDepth; 480fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville popLimit(oldLimit); 481fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 482fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 483a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 484a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** Read an embedded message field value from the stream. */ 485a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public <T extends MessageLite> T readMessage( 486a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final Parser<T> parser, 487a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final ExtensionRegistryLite extensionRegistry) 488a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throws IOException { 489a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int length = readRawVarint32(); 490a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (recursionDepth >= recursionLimit) { 491a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throw InvalidProtocolBufferException.recursionLimitExceeded(); 492a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 493a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final int oldLimit = pushLimit(length); 494a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ++recursionDepth; 495a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson T result = parser.parsePartialFrom(this, extensionRegistry); 496a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson checkLastTagWas(0); 497a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson --recursionDepth; 498a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson popLimit(oldLimit); 499a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return result; 500a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 501a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 502fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read a {@code bytes} field value from the stream. */ 503fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public ByteString readBytes() throws IOException { 504fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int size = readRawVarint32(); 505fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (size <= (bufferSize - bufferPos) && size > 0) { 506fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Fast path: We already have the bytes in a contiguous buffer, so 507fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // just copy directly from it. 508a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final ByteString result = bufferIsImmutable && enableAliasing 509a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ? new BoundedByteString(buffer, bufferPos, size) 510a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson : ByteString.copyFrom(buffer, bufferPos, size); 511fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferPos += size; 512fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return result; 513a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if (size == 0) { 514a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return ByteString.EMPTY; 515fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } else { 516fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Slow path: Build a byte array first then copy it. 517a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return new LiteralByteString(readRawBytesSlowPath(size)); 518a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 519a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 520a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 521a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** Read a {@code bytes} field value from the stream. */ 522a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public byte[] readByteArray() throws IOException { 523a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final int size = readRawVarint32(); 524a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (size <= (bufferSize - bufferPos) && size > 0) { 525a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Fast path: We already have the bytes in a contiguous buffer, so 526a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // just copy directly from it. 527a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final byte[] result = 528a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson Arrays.copyOfRange(buffer, bufferPos, bufferPos + size); 529a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos += size; 530a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return result; 531a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 532a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Slow path: Build a byte array first then copy it. 533a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return readRawBytesSlowPath(size); 534a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 535a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 536a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 537a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** Read a {@code bytes} field value from the stream. */ 538a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public ByteBuffer readByteBuffer() throws IOException { 539a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final int size = readRawVarint32(); 540a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (size <= (bufferSize - bufferPos) && size > 0) { 541a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Fast path: We already have the bytes in a contiguous buffer. 542a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // When aliasing is enabled, we can return a ByteBuffer pointing directly 543a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // into the underlying byte array without copy if the CodedInputStream is 544a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // constructed from a byte array. If aliasing is disabled or the input is 545a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // from an InputStream or ByteString, we have to make a copy of the bytes. 546a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ByteBuffer result = input == null && !bufferIsImmutable && enableAliasing 547a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ? ByteBuffer.wrap(buffer, bufferPos, size).slice() 548a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson : ByteBuffer.wrap(Arrays.copyOfRange( 549a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson buffer, bufferPos, bufferPos + size)); 550a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos += size; 551a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return result; 552a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if (size == 0) { 553a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return Internal.EMPTY_BYTE_BUFFER; 554a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 555a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Slow path: Build a byte array first then copy it. 556a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return ByteBuffer.wrap(readRawBytesSlowPath(size)); 557fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 558fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 559fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 560fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read a {@code uint32} field value from the stream. */ 561fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public int readUInt32() throws IOException { 562fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return readRawVarint32(); 563fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 564fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 565fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 566fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Read an enum field value from the stream. Caller is responsible 567fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * for converting the numeric value to an actual enum. 568fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 569fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public int readEnum() throws IOException { 570fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return readRawVarint32(); 571fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 572fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 573fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read an {@code sfixed32} field value from the stream. */ 574fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public int readSFixed32() throws IOException { 575fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return readRawLittleEndian32(); 576fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 577fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 578fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read an {@code sfixed64} field value from the stream. */ 579fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public long readSFixed64() throws IOException { 580fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return readRawLittleEndian64(); 581fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 582fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 583fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read an {@code sint32} field value from the stream. */ 584fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public int readSInt32() throws IOException { 585fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return decodeZigZag32(readRawVarint32()); 586fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 587fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 588fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read an {@code sint64} field value from the stream. */ 589fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public long readSInt64() throws IOException { 590fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return decodeZigZag64(readRawVarint64()); 591fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 592fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 593fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // ================================================================= 594fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 595fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 596fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Read a raw Varint from the stream. If larger than 32 bits, discard the 597fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * upper bits. 598fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 599fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public int readRawVarint32() throws IOException { 600a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // See implementation notes for readRawVarint64 601a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson fastpath: { 602a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int pos = bufferPos; 603a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 604a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bufferSize == pos) { 605a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson break fastpath; 606a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 607a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 608a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final byte[] buffer = this.buffer; 609a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int x; 610a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if ((x = buffer[pos++]) >= 0) { 611a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = pos; 612a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return x; 613a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if (bufferSize - pos < 9) { 614a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson break fastpath; 615a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if ((x ^= (buffer[pos++] << 7)) < 0L) { 616a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= (~0L << 7); 617a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if ((x ^= (buffer[pos++] << 14)) >= 0L) { 618a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= (~0L << 7) ^ (~0L << 14); 619a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if ((x ^= (buffer[pos++] << 21)) < 0L) { 620a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21); 621fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } else { 622a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int y = buffer[pos++]; 623a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= y << 28; 624a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); 625a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (y < 0 && 626a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson buffer[pos++] < 0 && 627a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson buffer[pos++] < 0 && 628a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson buffer[pos++] < 0 && 629a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson buffer[pos++] < 0 && 630a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson buffer[pos++] < 0) { 631a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson break fastpath; // Will throw malformedVarint() 632fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 633fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 634a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = pos; 635a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return x; 636fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 637a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return (int) readRawVarint64SlowPath(); 638a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 639a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 640a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private void skipRawVarint() throws IOException { 641a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bufferSize - bufferPos >= 10) { 642a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final byte[] buffer = this.buffer; 643a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int pos = bufferPos; 644a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson for (int i = 0; i < 10; i++) { 645a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (buffer[pos++] >= 0) { 646a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = pos; 647a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return; 648a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 649a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 650a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 651a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson skipRawVarintSlowPath(); 652a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 653a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 654a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private void skipRawVarintSlowPath() throws IOException { 655a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson for (int i = 0; i < 10; i++) { 656a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (readRawByte() >= 0) { 657a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return; 658a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 659a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 660a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throw InvalidProtocolBufferException.malformedVarint(); 661fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 662fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 663fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 664fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Reads a varint from the input one byte at a time, so that it does not 665fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * read any bytes after the end of the varint. If you simply wrapped the 666fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)} 667fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * then you would probably end up reading past the end of the varint since 668fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * CodedInputStream buffers its input. 669fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 670fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville static int readRawVarint32(final InputStream input) throws IOException { 671d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville final int firstByte = input.read(); 672d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville if (firstByte == -1) { 673d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville throw InvalidProtocolBufferException.truncatedMessage(); 674d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville } 675d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville return readRawVarint32(firstByte, input); 676d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville } 677d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville 678d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville /** 679d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * Like {@link #readRawVarint32(InputStream)}, but expects that the caller 680d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * has already read one byte. This allows the caller to determine if EOF 681d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * has been reached before attempting to read. 682d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville */ 683a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static int readRawVarint32( 684a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final int firstByte, final InputStream input) throws IOException { 685d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville if ((firstByte & 0x80) == 0) { 686d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville return firstByte; 687d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville } 688d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville 689d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville int result = firstByte & 0x7f; 690d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville int offset = 7; 691fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville for (; offset < 32; offset += 7) { 692fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int b = input.read(); 693fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (b == -1) { 694fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.truncatedMessage(); 695fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 696fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville result |= (b & 0x7f) << offset; 697fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if ((b & 0x80) == 0) { 698fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return result; 699fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 700fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 701fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Keep reading up to 64 bits. 702fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville for (; offset < 64; offset += 7) { 703fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int b = input.read(); 704fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (b == -1) { 705fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.truncatedMessage(); 706fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 707fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if ((b & 0x80) == 0) { 708fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return result; 709fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 710fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 711fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.malformedVarint(); 712fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 713fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 714fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read a raw Varint from the stream. */ 715fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public long readRawVarint64() throws IOException { 716a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Implementation notes: 717a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // 718a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Optimized for one-byte values, expected to be common. 719a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // The particular code below was selected from various candidates 720a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // empirically, by winning VarintBenchmark. 721a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // 722a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Sign extension of (signed) Java bytes is usually a nuisance, but 723a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // we exploit it here to more easily obtain the sign of bytes read. 724a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Instead of cleaning up the sign extension bits by masking eagerly, 725a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // we delay until we find the final (positive) byte, when we clear all 726a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // accumulated bits with one xor. We depend on javac to constant fold. 727a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson fastpath: { 728a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int pos = bufferPos; 729a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 730a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bufferSize == pos) { 731a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson break fastpath; 732a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 733a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 734a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final byte[] buffer = this.buffer; 735a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson long x; 736a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int y; 737a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if ((y = buffer[pos++]) >= 0) { 738a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = pos; 739a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return y; 740a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if (bufferSize - pos < 9) { 741a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson break fastpath; 742a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if ((x = y ^ (buffer[pos++] << 7)) < 0L) { 743a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= (~0L << 7); 744a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if ((x ^= (buffer[pos++] << 14)) >= 0L) { 745a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= (~0L << 7) ^ (~0L << 14); 746a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if ((x ^= (buffer[pos++] << 21)) < 0L) { 747a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21); 748a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if ((x ^= ((long) buffer[pos++] << 28)) >= 0L) { 749a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); 750a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if ((x ^= ((long) buffer[pos++] << 35)) < 0L) { 751a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35); 752a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if ((x ^= ((long) buffer[pos++] << 42)) >= 0L) { 753a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42); 754a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else if ((x ^= ((long) buffer[pos++] << 49)) < 0L) { 755a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42) 756a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ^ (~0L << 49); 757a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 758a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= ((long) buffer[pos++] << 56); 759a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42) 760a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ^ (~0L << 49) ^ (~0L << 56); 761a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (x < 0L) { 762a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (buffer[pos++] < 0L) { 763a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson break fastpath; // Will throw malformedVarint() 764a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 765a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 766a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 767a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = pos; 768a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return x; 769a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 770a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return readRawVarint64SlowPath(); 771a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 772a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 773a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** Variant of readRawVarint64 for when uncomfortably close to the limit. */ 774a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /* Visible for testing */ 775a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson long readRawVarint64SlowPath() throws IOException { 776fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville long result = 0; 777a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson for (int shift = 0; shift < 64; shift += 7) { 778fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final byte b = readRawByte(); 779a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson result |= (long) (b & 0x7F) << shift; 780fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if ((b & 0x80) == 0) { 781fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return result; 782fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 783fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 784fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.malformedVarint(); 785fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 786fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 787fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read a 32-bit little-endian integer from the stream. */ 788fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public int readRawLittleEndian32() throws IOException { 789a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int pos = bufferPos; 790a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 791a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // hand-inlined ensureAvailable(4); 792a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bufferSize - pos < 4) { 793a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson refillBuffer(4); 794a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson pos = bufferPos; 795a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 796a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 797a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final byte[] buffer = this.buffer; 798a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = pos + 4; 799a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return (((buffer[pos] & 0xff)) | 800a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ((buffer[pos + 1] & 0xff) << 8) | 801a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ((buffer[pos + 2] & 0xff) << 16) | 802a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ((buffer[pos + 3] & 0xff) << 24)); 803fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 804fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 805fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** Read a 64-bit little-endian integer from the stream. */ 806fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public long readRawLittleEndian64() throws IOException { 807a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int pos = bufferPos; 808a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 809a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // hand-inlined ensureAvailable(8); 810a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bufferSize - pos < 8) { 811a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson refillBuffer(8); 812a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson pos = bufferPos; 813a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 814a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 815a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final byte[] buffer = this.buffer; 816a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = pos + 8; 817a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return ((((long) buffer[pos] & 0xffL)) | 818a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson (((long) buffer[pos + 1] & 0xffL) << 8) | 819a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson (((long) buffer[pos + 2] & 0xffL) << 16) | 820a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson (((long) buffer[pos + 3] & 0xffL) << 24) | 821a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson (((long) buffer[pos + 4] & 0xffL) << 32) | 822a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson (((long) buffer[pos + 5] & 0xffL) << 40) | 823a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson (((long) buffer[pos + 6] & 0xffL) << 48) | 824a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson (((long) buffer[pos + 7] & 0xffL) << 56)); 825fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 826fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 827fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 828fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers 829fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * into values that can be efficiently encoded with varint. (Otherwise, 830fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * negative values must be sign-extended to 64 bits to be varint encoded, 831fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * thus always taking 10 bytes on the wire.) 832fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 833fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @param n An unsigned 32-bit integer, stored in a signed int because 834fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Java has no explicit unsigned support. 835fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @return A signed 32-bit integer. 836fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 837fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public static int decodeZigZag32(final int n) { 838fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return (n >>> 1) ^ -(n & 1); 839fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 840fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 841fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 842fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers 843fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * into values that can be efficiently encoded with varint. (Otherwise, 844fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * negative values must be sign-extended to 64 bits to be varint encoded, 845fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * thus always taking 10 bytes on the wire.) 846fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 847fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @param n An unsigned 64-bit integer, stored in a signed int because 848fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Java has no explicit unsigned support. 849fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @return A signed 64-bit integer. 850fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 851fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public static long decodeZigZag64(final long n) { 852fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return (n >>> 1) ^ -(n & 1); 853fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 854fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 855fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // ----------------------------------------------------------------- 856fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 857fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private final byte[] buffer; 858a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private final boolean bufferIsImmutable; 859fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private int bufferSize; 860fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private int bufferSizeAfterLimit; 861fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private int bufferPos; 862fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private final InputStream input; 863fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private int lastTag; 864a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private boolean enableAliasing = false; 865fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 866fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 867fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * The total number of bytes read before the current buffer. The total 868fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * bytes read up to the current position can be computed as 869d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * {@code totalBytesRetired + bufferPos}. This value may be negative if 870d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * reading started in the middle of the current buffer (e.g. if the 871d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * constructor that takes a byte array and an offset was used). 872fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 873fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private int totalBytesRetired; 874fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 875fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** The absolute position of the end of the current message. */ 876fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private int currentLimit = Integer.MAX_VALUE; 877fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 878fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** See setRecursionLimit() */ 879fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private int recursionDepth; 880fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private int recursionLimit = DEFAULT_RECURSION_LIMIT; 881fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 882fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** See setSizeLimit() */ 883fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private int sizeLimit = DEFAULT_SIZE_LIMIT; 884fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 885fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private static final int DEFAULT_RECURSION_LIMIT = 64; 886fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB 887fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private static final int BUFFER_SIZE = 4096; 888fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 889fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private CodedInputStream(final byte[] buffer, final int off, final int len) { 890fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville this.buffer = buffer; 891fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferSize = off + len; 892fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferPos = off; 893d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville totalBytesRetired = -off; 894fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville input = null; 895a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferIsImmutable = false; 896fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 897fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 898fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private CodedInputStream(final InputStream input) { 899fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville buffer = new byte[BUFFER_SIZE]; 900fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferSize = 0; 901fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferPos = 0; 902d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville totalBytesRetired = 0; 903fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville this.input = input; 904a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferIsImmutable = false; 905a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 906a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 907a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private CodedInputStream(final LiteralByteString byteString) { 908a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson buffer = byteString.bytes; 909a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = byteString.getOffsetIntoBytes(); 910a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferSize = bufferPos + byteString.size(); 911a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson totalBytesRetired = -bufferPos; 912a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson input = null; 913a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferIsImmutable = true; 914a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 915a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 916a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public void enableAliasing(boolean enabled) { 917a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson this.enableAliasing = enabled; 918fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 919fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 920fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 921fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Set the maximum message recursion depth. In order to prevent malicious 922fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * messages from causing stack overflows, {@code CodedInputStream} limits 923fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * how deeply messages may be nested. The default limit is 64. 924fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 925fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @return the old limit. 926fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 927fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public int setRecursionLimit(final int limit) { 928fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (limit < 0) { 929fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw new IllegalArgumentException( 930fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville "Recursion limit cannot be negative: " + limit); 931fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 932fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int oldLimit = recursionLimit; 933fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville recursionLimit = limit; 934fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return oldLimit; 935fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 936fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 937fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 938fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Set the maximum message size. In order to prevent malicious 939fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * messages from exhausting memory or causing integer overflows, 940fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * {@code CodedInputStream} limits how large a message may be. 941fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * The default limit is 64MB. You should set this limit as small 942fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * as you can without harming your app's functionality. Note that 943fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * size limits only apply when reading from an {@code InputStream}, not 944fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * when constructed around a raw byte array (nor with 945fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * {@link ByteString#newCodedInput}). 946fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * <p> 947fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * If you want to read several messages from a single CodedInputStream, you 948fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * could call {@link #resetSizeCounter()} after each one to avoid hitting the 949fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * size limit. 950fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 951fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @return the old limit. 952fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 953fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public int setSizeLimit(final int limit) { 954fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (limit < 0) { 955fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw new IllegalArgumentException( 956fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville "Size limit cannot be negative: " + limit); 957fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 958fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int oldLimit = sizeLimit; 959fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville sizeLimit = limit; 960fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return oldLimit; 961fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 962fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 963fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 964fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). 965fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 966fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public void resetSizeCounter() { 967d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville totalBytesRetired = -bufferPos; 968fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 969fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 970fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 971fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This 972fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * is called when descending into a length-delimited embedded message. 973fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 974d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * <p>Note that {@code pushLimit()} does NOT affect how many bytes the 975d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * {@code CodedInputStream} reads from an underlying {@code InputStream} when 976d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * refreshing its buffer. If you need to prevent reading past a certain 977d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * point in the underlying {@code InputStream} (e.g. because you expect it to 978d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * contain more data after the end of the message which you need to handle 979a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * differently) then you must place a wrapper around your {@code InputStream} 980d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * which limits the amount of data that can be read from it. 981d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * 982fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @return the old limit. 983fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 984fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public int pushLimit(int byteLimit) throws InvalidProtocolBufferException { 985fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (byteLimit < 0) { 986fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.negativeSize(); 987fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 988fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville byteLimit += totalBytesRetired + bufferPos; 989fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int oldLimit = currentLimit; 990fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (byteLimit > oldLimit) { 991fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.truncatedMessage(); 992fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 993fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville currentLimit = byteLimit; 994fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 995fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville recomputeBufferSizeAfterLimit(); 996fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 997fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return oldLimit; 998fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 999fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1000fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private void recomputeBufferSizeAfterLimit() { 1001fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferSize += bufferSizeAfterLimit; 1002fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int bufferEnd = totalBytesRetired + bufferSize; 1003fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (bufferEnd > currentLimit) { 1004fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Limit is in current buffer. 1005fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferSizeAfterLimit = bufferEnd - currentLimit; 1006fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferSize -= bufferSizeAfterLimit; 1007fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } else { 1008fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferSizeAfterLimit = 0; 1009fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1010fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1011fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1012fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 1013fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Discards the current limit, returning to the previous limit. 1014fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 1015fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @param oldLimit The old limit, as returned by {@code pushLimit}. 1016fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 1017fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public void popLimit(final int oldLimit) { 1018fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville currentLimit = oldLimit; 1019fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville recomputeBufferSizeAfterLimit(); 1020fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1021fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1022fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 1023fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Returns the number of bytes to be read before the current limit. 1024fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * If no limit is set, returns -1. 1025fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 1026fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public int getBytesUntilLimit() { 1027fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (currentLimit == Integer.MAX_VALUE) { 1028fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return -1; 1029fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1030fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1031fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int currentAbsolutePosition = totalBytesRetired + bufferPos; 1032fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return currentLimit - currentAbsolutePosition; 1033fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1034fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1035fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 1036fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Returns true if the stream has reached the end of the input. This is the 1037fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * case if either the end of the underlying input source has been reached or 1038fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * if the stream has reached a limit created using {@link #pushLimit(int)}. 1039fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 1040fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public boolean isAtEnd() throws IOException { 1041a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return bufferPos == bufferSize && !tryRefillBuffer(1); 1042fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1043d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville 1044d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville /** 1045d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * The total bytes read up to the current position. Calling 1046d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * {@link #resetSizeCounter()} resets this value to zero. 1047d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville */ 1048d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville public int getTotalBytesRead() { 1049d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville return totalBytesRetired + bufferPos; 1050d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville } 1051fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1052a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private interface RefillCallback { 1053a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson void onRefill(); 1054a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1055a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1056a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private RefillCallback refillCallback = null; 1057a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1058a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 1059a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Ensures that at least {@code n} bytes are available in the buffer, reading 1060a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * more bytes from the input if necessary to make it so. Caller must ensure 1061a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * that the requested space is less than BUFFER_SIZE. 1062a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 1063a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws InvalidProtocolBufferException The end of the stream or the current 1064a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * limit was reached. 1065a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 1066a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private void ensureAvailable(int n) throws IOException { 1067a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bufferSize - bufferPos < n) { 1068a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson refillBuffer(n); 1069a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1070a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1071a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1072a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 1073a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Reads more bytes from the input, making at least {@code n} bytes available 1074a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * in the buffer. Caller must ensure that the requested space is not yet 1075a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * available, and that the requested space is less than BUFFER_SIZE. 1076a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 1077a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws InvalidProtocolBufferException The end of the stream or the current 1078a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * limit was reached. 1079a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 1080a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private void refillBuffer(int n) throws IOException { 1081a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (!tryRefillBuffer(n)) { 1082a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throw InvalidProtocolBufferException.truncatedMessage(); 1083a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1084a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1085a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1086fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 1087a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Tries to read more bytes from the input, making at least {@code n} bytes 1088a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * available in the buffer. Caller must ensure that the requested space is 1089a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * not yet available, and that the requested space is less than BUFFER_SIZE. 1090a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 1091a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return {@code true} if the bytes could be made available; {@code false} 1092a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * if the end of the stream or the current limit was reached. 1093fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 1094a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private boolean tryRefillBuffer(int n) throws IOException { 1095a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bufferPos + n <= bufferSize) { 1096fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw new IllegalStateException( 1097a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson "refillBuffer() called when " + n + 1098a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson " bytes were already available in buffer"); 1099fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1100fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1101a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (totalBytesRetired + bufferPos + n > currentLimit) { 1102fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Oops, we hit a limit. 1103a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return false; 1104fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1105fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1106a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (refillCallback != null) { 1107a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson refillCallback.onRefill(); 1108fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1109a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1110a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (input != null) { 1111a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int pos = bufferPos; 1112a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (pos > 0) { 1113a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bufferSize > pos) { 1114a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson System.arraycopy(buffer, pos, buffer, 0, bufferSize - pos); 1115a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1116a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson totalBytesRetired += pos; 1117a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferSize -= pos; 1118a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = 0; 1119fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1120a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1121a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize); 1122a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) { 1123a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throw new IllegalStateException( 1124a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson "InputStream#read(byte[]) returned invalid result: " + bytesRead + 1125a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson "\nThe InputStream implementation is buggy."); 1126a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1127a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bytesRead > 0) { 1128a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferSize += bytesRead; 1129a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Integer-overflow-conscious check against sizeLimit 1130a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (totalBytesRetired + n - sizeLimit > 0) { 1131a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throw InvalidProtocolBufferException.sizeLimitExceeded(); 1132a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1133a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson recomputeBufferSizeAfterLimit(); 1134a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return (bufferSize >= n) ? true : tryRefillBuffer(n); 1135fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1136fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1137a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1138a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return false; 1139fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1140fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1141fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 1142fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Read one byte from the input. 1143fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 1144fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @throws InvalidProtocolBufferException The end of the stream or the current 1145fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * limit was reached. 1146fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 1147fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public byte readRawByte() throws IOException { 1148fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (bufferPos == bufferSize) { 1149a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson refillBuffer(1); 1150fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1151fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return buffer[bufferPos++]; 1152fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1153fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1154fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 1155fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Read a fixed size of bytes from the input. 1156fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 1157fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @throws InvalidProtocolBufferException The end of the stream or the current 1158fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * limit was reached. 1159fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 1160fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public byte[] readRawBytes(final int size) throws IOException { 1161a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final int pos = bufferPos; 1162a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (size <= (bufferSize - pos) && size > 0) { 1163a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = pos + size; 1164a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return Arrays.copyOfRange(buffer, pos, pos + size); 1165a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 1166a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return readRawBytesSlowPath(size); 1167a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1168a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1169a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1170a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 1171a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Exactly like readRawBytes, but caller must have already checked the fast 1172a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * path: (size <= (bufferSize - pos) && size > 0) 1173a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 1174a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private byte[] readRawBytesSlowPath(final int size) throws IOException { 1175a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (size <= 0) { 1176a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (size == 0) { 1177a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return Internal.EMPTY_BYTE_ARRAY; 1178a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 1179a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throw InvalidProtocolBufferException.negativeSize(); 1180a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1181fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1182fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1183fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (totalBytesRetired + bufferPos + size > currentLimit) { 1184fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Read to the end of the stream anyway. 1185fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville skipRawBytes(currentLimit - totalBytesRetired - bufferPos); 1186fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Then fail. 1187fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.truncatedMessage(); 1188fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1189fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1190a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (size < BUFFER_SIZE) { 1191fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Reading more bytes than are in the buffer, but not an excessive number 1192fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // of bytes. We can safely allocate the resulting array ahead of time. 1193fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1194fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // First copy what we have. 1195fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final byte[] bytes = new byte[size]; 1196fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville int pos = bufferSize - bufferPos; 1197fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville System.arraycopy(buffer, bufferPos, bytes, 0, pos); 1198fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferPos = bufferSize; 1199fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1200a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // We want to refill the buffer and then copy from the buffer into our 1201fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // byte array rather than reading directly into our byte array because 1202fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // the input may be unbuffered. 1203a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ensureAvailable(size - pos); 1204fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville System.arraycopy(buffer, 0, bytes, pos, size - pos); 1205fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferPos = size - pos; 1206fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1207fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return bytes; 1208fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } else { 1209fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // The size is very large. For security reasons, we can't allocate the 1210fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // entire byte array yet. The size comes directly from the input, so a 1211fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // maliciously-crafted message could provide a bogus very large size in 1212fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // order to trick the app into allocating a lot of memory. We avoid this 1213fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // by allocating and reading only a small chunk at a time, so that the 1214fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // malicious message must actually *be* extremely large to cause 1215fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // problems. Meanwhile, we limit the allowed size of a message elsewhere. 1216fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1217fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Remember the buffer markers since we'll have to copy the bytes out of 1218fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // it later. 1219fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int originalBufferPos = bufferPos; 1220fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int originalBufferSize = bufferSize; 1221fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1222fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Mark the current buffer consumed. 1223fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville totalBytesRetired += bufferSize; 1224fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferPos = 0; 1225fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville bufferSize = 0; 1226fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1227fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Read all the rest of the bytes we need. 1228fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville int sizeLeft = size - (originalBufferSize - originalBufferPos); 1229fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final List<byte[]> chunks = new ArrayList<byte[]>(); 1230fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1231fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville while (sizeLeft > 0) { 1232fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)]; 1233fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville int pos = 0; 1234fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville while (pos < chunk.length) { 1235fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final int n = (input == null) ? -1 : 1236fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville input.read(chunk, pos, chunk.length - pos); 1237fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (n == -1) { 1238fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.truncatedMessage(); 1239fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1240fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville totalBytesRetired += n; 1241fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville pos += n; 1242fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1243fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville sizeLeft -= chunk.length; 1244fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville chunks.add(chunk); 1245fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1246fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1247fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // OK, got everything. Now concatenate it all into one buffer. 1248fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville final byte[] bytes = new byte[size]; 1249fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1250fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Start by copying the leftover bytes from this.buffer. 1251fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville int pos = originalBufferSize - originalBufferPos; 1252fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville System.arraycopy(buffer, originalBufferPos, bytes, 0, pos); 1253fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1254fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // And now all the chunks. 1255fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville for (final byte[] chunk : chunks) { 1256fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville System.arraycopy(chunk, 0, bytes, pos, chunk.length); 1257fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville pos += chunk.length; 1258fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1259fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1260fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Done. 1261fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return bytes; 1262fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1263fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1264fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1265fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 1266fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Reads and discards {@code size} bytes. 1267fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 1268fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @throws InvalidProtocolBufferException The end of the stream or the current 1269fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * limit was reached. 1270fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 1271fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public void skipRawBytes(final int size) throws IOException { 1272a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (size <= (bufferSize - bufferPos) && size >= 0) { 1273a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // We have all the bytes we need already. 1274a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos += size; 1275a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 1276a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson skipRawBytesSlowPath(size); 1277a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1278a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1279a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1280a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 1281a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Exactly like skipRawBytes, but caller must have already checked the fast 1282a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * path: (size <= (bufferSize - pos) && size >= 0) 1283a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 1284a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private void skipRawBytesSlowPath(final int size) throws IOException { 1285fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (size < 0) { 1286fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.negativeSize(); 1287fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1288fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1289fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville if (totalBytesRetired + bufferPos + size > currentLimit) { 1290fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Read to the end of the stream anyway. 1291fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville skipRawBytes(currentLimit - totalBytesRetired - bufferPos); 1292fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Then fail. 1293fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throw InvalidProtocolBufferException.truncatedMessage(); 1294fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1295fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1296a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Skipping more bytes than are in the buffer. First skip what we have. 1297a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int pos = bufferSize - bufferPos; 1298a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = bufferSize; 1299fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1300a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Keep refilling the buffer until we get to the point we wanted to skip to. 1301a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // This has the side effect of ensuring the limits are updated correctly. 1302a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson refillBuffer(1); 1303a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson while (size - pos > bufferSize) { 1304a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson pos += bufferSize; 1305a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = bufferSize; 1306a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson refillBuffer(1); 1307fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1308a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1309a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = size - pos; 1310fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1311fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville} 1312