OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 12 matching lines...) Expand all Loading... |
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | 30 |
31 package com.google.protobuf; | 31 package com.google.protobuf; |
32 | 32 |
33 import static com.google.protobuf.Internal.EMPTY_BYTE_ARRAY; | |
34 import static com.google.protobuf.Internal.EMPTY_BYTE_BUFFER; | |
35 import static com.google.protobuf.Internal.UTF_8; | |
36 import static com.google.protobuf.Internal.checkNotNull; | |
37 import static com.google.protobuf.WireFormat.FIXED_32_SIZE; | |
38 import static com.google.protobuf.WireFormat.FIXED_64_SIZE; | |
39 import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE; | |
40 | |
41 import java.io.ByteArrayOutputStream; | 33 import java.io.ByteArrayOutputStream; |
42 import java.io.IOException; | 34 import java.io.IOException; |
43 import java.io.InputStream; | 35 import java.io.InputStream; |
44 import java.nio.ByteBuffer; | 36 import java.nio.ByteBuffer; |
45 import java.util.ArrayList; | 37 import java.util.ArrayList; |
46 import java.util.Arrays; | 38 import java.util.Arrays; |
47 import java.util.List; | 39 import java.util.List; |
48 | 40 |
49 /** | 41 /** |
50 * Reads and decodes protocol message fields. | 42 * Reads and decodes protocol message fields. |
51 * | 43 * |
52 * <p>This class contains two kinds of methods: methods that read specific proto
col message | 44 * This class contains two kinds of methods: methods that read specific |
53 * constructs and field types (e.g. {@link #readTag()} and {@link #readInt32()})
and methods that | 45 * protocol message constructs and field types (e.g. {@link #readTag()} and |
54 * read low-level values (e.g. {@link #readRawVarint32()} and {@link #readRawByt
es}). If you are | 46 * {@link #readInt32()}) and methods that read low-level values (e.g. |
55 * reading encoded protocol messages, you should use the former methods, but if
you are reading some | 47 * {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading |
56 * other format of your own design, use the latter. | 48 * encoded protocol messages, you should use the former methods, but if you are |
| 49 * reading some other format of your own design, use the latter. |
57 * | 50 * |
58 * @author kenton@google.com Kenton Varda | 51 * @author kenton@google.com Kenton Varda |
59 */ | 52 */ |
60 public abstract class CodedInputStream { | 53 public final class CodedInputStream { |
61 private static final int DEFAULT_BUFFER_SIZE = 4096; | 54 /** |
62 private static final int DEFAULT_RECURSION_LIMIT = 100; | 55 * Create a new CodedInputStream wrapping the given InputStream. |
63 // Integer.MAX_VALUE == 0x7FFFFFF == INT_MAX from limits.h | 56 */ |
64 private static final int DEFAULT_SIZE_LIMIT = Integer.MAX_VALUE; | |
65 | |
66 /** Visible for subclasses. See setRecursionLimit() */ | |
67 int recursionDepth; | |
68 | |
69 int recursionLimit = DEFAULT_RECURSION_LIMIT; | |
70 | |
71 /** Visible for subclasses. See setSizeLimit() */ | |
72 int sizeLimit = DEFAULT_SIZE_LIMIT; | |
73 | |
74 /** Create a new CodedInputStream wrapping the given InputStream. */ | |
75 public static CodedInputStream newInstance(final InputStream input) { | 57 public static CodedInputStream newInstance(final InputStream input) { |
76 return newInstance(input, DEFAULT_BUFFER_SIZE); | 58 return new CodedInputStream(input, BUFFER_SIZE); |
| 59 } |
| 60 |
| 61 /** |
| 62 * Create a new CodedInputStream wrapping the given InputStream. |
| 63 */ |
| 64 static CodedInputStream newInstance(final InputStream input, int bufferSize) { |
| 65 return new CodedInputStream(input, bufferSize); |
77 } | 66 } |
78 | 67 |
79 /** Create a new CodedInputStream wrapping the given InputStream. */ | 68 /** |
80 static CodedInputStream newInstance(final InputStream input, int bufferSize) { | 69 * Create a new CodedInputStream wrapping the given byte array. |
81 if (input == null) { | 70 */ |
82 // TODO(nathanmittler): Ideally we should throw here. This is done for bac
kward compatibility. | |
83 return newInstance(EMPTY_BYTE_ARRAY); | |
84 } | |
85 return new StreamDecoder(input, bufferSize); | |
86 } | |
87 | |
88 /** Create a new CodedInputStream wrapping the given byte array. */ | |
89 public static CodedInputStream newInstance(final byte[] buf) { | 71 public static CodedInputStream newInstance(final byte[] buf) { |
90 return newInstance(buf, 0, buf.length); | 72 return newInstance(buf, 0, buf.length); |
91 } | 73 } |
92 | 74 |
93 /** Create a new CodedInputStream wrapping the given byte array slice. */ | 75 /** |
94 public static CodedInputStream newInstance(final byte[] buf, final int off, fi
nal int len) { | 76 * Create a new CodedInputStream wrapping the given byte array slice. |
| 77 */ |
| 78 public static CodedInputStream newInstance(final byte[] buf, final int off, |
| 79 final int len) { |
95 return newInstance(buf, off, len, false /* bufferIsImmutable */); | 80 return newInstance(buf, off, len, false /* bufferIsImmutable */); |
96 } | 81 } |
97 | 82 |
98 /** Create a new CodedInputStream wrapping the given byte array slice. */ | 83 /** |
| 84 * Create a new CodedInputStream wrapping the given byte array slice. |
| 85 */ |
99 static CodedInputStream newInstance( | 86 static CodedInputStream newInstance( |
100 final byte[] buf, final int off, final int len, final boolean bufferIsImmu
table) { | 87 final byte[] buf, final int off, final int len, final boolean bufferIsImmu
table) { |
101 ArrayDecoder result = new ArrayDecoder(buf, off, len, bufferIsImmutable); | 88 CodedInputStream result = new CodedInputStream(buf, off, len, bufferIsImmuta
ble); |
102 try { | 89 try { |
103 // Some uses of CodedInputStream can be more efficient if they know | 90 // Some uses of CodedInputStream can be more efficient if they know |
104 // exactly how many bytes are available. By pushing the end point of the | 91 // exactly how many bytes are available. By pushing the end point of the |
105 // buffer as a limit, we allow them to get this information via | 92 // buffer as a limit, we allow them to get this information via |
106 // getBytesUntilLimit(). Pushing a limit that we know is at the end of | 93 // getBytesUntilLimit(). Pushing a limit that we know is at the end of |
107 // the stream can never hurt, since we can never past that point anyway. | 94 // the stream can never hurt, since we can never past that point anyway. |
108 result.pushLimit(len); | 95 result.pushLimit(len); |
109 } catch (InvalidProtocolBufferException ex) { | 96 } catch (InvalidProtocolBufferException ex) { |
110 // The only reason pushLimit() might throw an exception here is if len | 97 // The only reason pushLimit() might throw an exception here is if len |
111 // is negative. Normally pushLimit()'s parameter comes directly off the | 98 // is negative. Normally pushLimit()'s parameter comes directly off the |
112 // wire, so it's important to catch exceptions in case of corrupt or | 99 // wire, so it's important to catch exceptions in case of corrupt or |
113 // malicious data. However, in this case, we expect that len is not a | 100 // malicious data. However, in this case, we expect that len is not a |
114 // user-supplied value, so we can assume that it being negative indicates | 101 // user-supplied value, so we can assume that it being negative indicates |
115 // a programming error. Therefore, throwing an unchecked exception is | 102 // a programming error. Therefore, throwing an unchecked exception is |
116 // appropriate. | 103 // appropriate. |
117 throw new IllegalArgumentException(ex); | 104 throw new IllegalArgumentException(ex); |
118 } | 105 } |
119 return result; | 106 return result; |
120 } | 107 } |
121 | 108 |
122 /** | 109 /** |
123 * Create a new CodedInputStream wrapping the given ByteBuffer. The data start
ing from the | 110 * Create a new CodedInputStream wrapping the given ByteBuffer. The data |
124 * ByteBuffer's current position to its limit will be read. The returned Coded
InputStream may or | 111 * starting from the ByteBuffer's current position to its limit will be read. |
125 * may not share the underlying data in the ByteBuffer, therefore the ByteBuff
er cannot be changed | 112 * The returned CodedInputStream may or may not share the underlying data |
126 * while the CodedInputStream is in use. Note that the ByteBuffer's position w
on't be changed by | 113 * in the ByteBuffer, therefore the ByteBuffer cannot be changed while the |
127 * this function. Concurrent calls with the same ByteBuffer object are safe if
no other thread is | 114 * CodedInputStream is in use. |
128 * trying to alter the ByteBuffer's status. | 115 * Note that the ByteBuffer's position won't be changed by this function. |
| 116 * Concurrent calls with the same ByteBuffer object are safe if no other |
| 117 * thread is trying to alter the ByteBuffer's status. |
129 */ | 118 */ |
130 public static CodedInputStream newInstance(ByteBuffer buf) { | 119 public static CodedInputStream newInstance(ByteBuffer buf) { |
131 return newInstance(buf, false /* bufferIsImmutable */); | |
132 } | |
133 | |
134 /** Create a new CodedInputStream wrapping the given buffer. */ | |
135 static CodedInputStream newInstance(ByteBuffer buf, boolean bufferIsImmutable)
{ | |
136 if (buf.hasArray()) { | 120 if (buf.hasArray()) { |
137 return newInstance( | 121 return newInstance(buf.array(), buf.arrayOffset() + buf.position(), |
138 buf.array(), buf.arrayOffset() + buf.position(), buf.remaining(), buff
erIsImmutable); | 122 buf.remaining()); |
139 } | 123 } else { |
140 | 124 ByteBuffer temp = buf.duplicate(); |
141 if (buf.isDirect() && UnsafeDirectNioDecoder.isSupported()) { | 125 byte[] buffer = new byte[temp.remaining()]; |
142 return new UnsafeDirectNioDecoder(buf, bufferIsImmutable); | 126 temp.get(buffer); |
143 } | 127 return newInstance(buffer); |
144 | 128 } |
145 // The buffer is non-direct and does not expose the underlying array. Using
the ByteBuffer API | 129 } |
146 // to access individual bytes is very slow, so just copy the buffer to an ar
ray. | |
147 // TODO(nathanmittler): Re-evaluate with Java 9 | |
148 byte[] buffer = new byte[buf.remaining()]; | |
149 buf.duplicate().get(buffer); | |
150 return newInstance(buffer, 0, buffer.length, true); | |
151 } | |
152 | |
153 /** Disable construction/inheritance outside of this class. */ | |
154 private CodedInputStream() {} | |
155 | 130 |
156 // ----------------------------------------------------------------- | 131 // ----------------------------------------------------------------- |
157 | 132 |
158 /** | 133 /** |
159 * Attempt to read a field tag, returning zero if we have reached EOF. Protoco
l message parsers | 134 * Attempt to read a field tag, returning zero if we have reached EOF. |
160 * use this to read tags, since a protocol message may legally end wherever a
tag occurs, and zero | 135 * Protocol message parsers use this to read tags, since a protocol message |
161 * is not a valid tag number. | 136 * may legally end wherever a tag occurs, and zero is not a valid tag number. |
162 */ | 137 */ |
163 public abstract int readTag() throws IOException; | 138 public int readTag() throws IOException { |
164 | 139 if (isAtEnd()) { |
165 /** | 140 lastTag = 0; |
166 * Verifies that the last call to readTag() returned the given tag value. This
is used to verify | 141 return 0; |
167 * that a nested group ended with the correct end tag. | 142 } |
| 143 |
| 144 lastTag = readRawVarint32(); |
| 145 if (WireFormat.getTagFieldNumber(lastTag) == 0) { |
| 146 // If we actually read zero (or any tag number corresponding to field |
| 147 // number zero), that's not a valid tag. |
| 148 throw InvalidProtocolBufferException.invalidTag(); |
| 149 } |
| 150 return lastTag; |
| 151 } |
| 152 |
| 153 /** |
| 154 * Verifies that the last call to readTag() returned the given tag value. |
| 155 * This is used to verify that a nested group ended with the correct |
| 156 * end tag. |
168 * | 157 * |
169 * @throws InvalidProtocolBufferException {@code value} does not match the las
t tag. | 158 * @throws InvalidProtocolBufferException {@code value} does not match the |
170 */ | 159 * last tag. |
171 public abstract void checkLastTagWas(final int value) throws InvalidProtocolBu
fferException; | 160 */ |
172 | 161 public void checkLastTagWas(final int value) |
173 public abstract int getLastTag(); | 162 throws InvalidProtocolBufferException { |
| 163 if (lastTag != value) { |
| 164 throw InvalidProtocolBufferException.invalidEndTag(); |
| 165 } |
| 166 } |
| 167 |
| 168 public int getLastTag() { |
| 169 return lastTag; |
| 170 } |
174 | 171 |
175 /** | 172 /** |
176 * Reads and discards a single field, given its tag value. | 173 * Reads and discards a single field, given its tag value. |
177 * | 174 * |
178 * @return {@code false} if the tag is an endgroup tag, in which case nothing
is skipped. | 175 * @return {@code false} if the tag is an endgroup tag, in which case |
179 * Otherwise, returns {@code true}. | 176 * nothing is skipped. Otherwise, returns {@code true}. |
180 */ | 177 */ |
181 public abstract boolean skipField(final int tag) throws IOException; | 178 public boolean skipField(final int tag) throws IOException { |
182 | 179 switch (WireFormat.getTagWireType(tag)) { |
183 /** | 180 case WireFormat.WIRETYPE_VARINT: |
184 * Reads a single field and writes it to output in wire format, given its tag
value. | 181 skipRawVarint(); |
| 182 return true; |
| 183 case WireFormat.WIRETYPE_FIXED64: |
| 184 skipRawBytes(8); |
| 185 return true; |
| 186 case WireFormat.WIRETYPE_LENGTH_DELIMITED: |
| 187 skipRawBytes(readRawVarint32()); |
| 188 return true; |
| 189 case WireFormat.WIRETYPE_START_GROUP: |
| 190 skipMessage(); |
| 191 checkLastTagWas( |
| 192 WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), |
| 193 WireFormat.WIRETYPE_END_GROUP)); |
| 194 return true; |
| 195 case WireFormat.WIRETYPE_END_GROUP: |
| 196 return false; |
| 197 case WireFormat.WIRETYPE_FIXED32: |
| 198 skipRawBytes(4); |
| 199 return true; |
| 200 default: |
| 201 throw InvalidProtocolBufferException.invalidWireType(); |
| 202 } |
| 203 } |
| 204 |
| 205 /** |
| 206 * Reads a single field and writes it to output in wire format, |
| 207 * given its tag value. |
185 * | 208 * |
186 * @return {@code false} if the tag is an endgroup tag, in which case nothing
is skipped. | 209 * @return {@code false} if the tag is an endgroup tag, in which case |
187 * Otherwise, returns {@code true}. | 210 * nothing is skipped. Otherwise, returns {@code true}. |
188 * @deprecated use {@code UnknownFieldSet} or {@code UnknownFieldSetLite} to s
kip to an output | 211 */ |
189 * stream. | 212 public boolean skipField(final int tag, final CodedOutputStream output) |
| 213 throws IOException { |
| 214 switch (WireFormat.getTagWireType(tag)) { |
| 215 case WireFormat.WIRETYPE_VARINT: { |
| 216 long value = readInt64(); |
| 217 output.writeRawVarint32(tag); |
| 218 output.writeUInt64NoTag(value); |
| 219 return true; |
| 220 } |
| 221 case WireFormat.WIRETYPE_FIXED64: { |
| 222 long value = readRawLittleEndian64(); |
| 223 output.writeRawVarint32(tag); |
| 224 output.writeFixed64NoTag(value); |
| 225 return true; |
| 226 } |
| 227 case WireFormat.WIRETYPE_LENGTH_DELIMITED: { |
| 228 ByteString value = readBytes(); |
| 229 output.writeRawVarint32(tag); |
| 230 output.writeBytesNoTag(value); |
| 231 return true; |
| 232 } |
| 233 case WireFormat.WIRETYPE_START_GROUP: { |
| 234 output.writeRawVarint32(tag); |
| 235 skipMessage(output); |
| 236 int endtag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), |
| 237 WireFormat.WIRETYPE_END_GROUP); |
| 238 checkLastTagWas(endtag); |
| 239 output.writeRawVarint32(endtag); |
| 240 return true; |
| 241 } |
| 242 case WireFormat.WIRETYPE_END_GROUP: { |
| 243 return false; |
| 244 } |
| 245 case WireFormat.WIRETYPE_FIXED32: { |
| 246 int value = readRawLittleEndian32(); |
| 247 output.writeRawVarint32(tag); |
| 248 output.writeFixed32NoTag(value); |
| 249 return true; |
| 250 } |
| 251 default: |
| 252 throw InvalidProtocolBufferException.invalidWireType(); |
| 253 } |
| 254 } |
| 255 |
| 256 /** |
| 257 * Reads and discards an entire message. This will read either until EOF |
| 258 * or until an endgroup tag, whichever comes first. |
| 259 */ |
| 260 public void skipMessage() throws IOException { |
| 261 while (true) { |
| 262 final int tag = readTag(); |
| 263 if (tag == 0 || !skipField(tag)) { |
| 264 return; |
| 265 } |
| 266 } |
| 267 } |
| 268 |
| 269 /** |
| 270 * Reads an entire message and writes it to output in wire format. |
| 271 * This will read either until EOF or until an endgroup tag, |
| 272 * whichever comes first. |
| 273 */ |
| 274 public void skipMessage(CodedOutputStream output) throws IOException { |
| 275 while (true) { |
| 276 final int tag = readTag(); |
| 277 if (tag == 0 || !skipField(tag, output)) { |
| 278 return; |
| 279 } |
| 280 } |
| 281 } |
| 282 |
| 283 /** |
| 284 * Collects the bytes skipped and returns the data in a ByteBuffer. |
| 285 */ |
| 286 private class SkippedDataSink implements RefillCallback { |
| 287 private int lastPos = bufferPos; |
| 288 private ByteArrayOutputStream byteArrayStream; |
| 289 |
| 290 @Override |
| 291 public void onRefill() { |
| 292 if (byteArrayStream == null) { |
| 293 byteArrayStream = new ByteArrayOutputStream(); |
| 294 } |
| 295 byteArrayStream.write(buffer, lastPos, bufferPos - lastPos); |
| 296 lastPos = 0; |
| 297 } |
| 298 |
| 299 /** |
| 300 * Gets skipped data in a ByteBuffer. This method should only be |
| 301 * called once. |
| 302 */ |
| 303 ByteBuffer getSkippedData() { |
| 304 if (byteArrayStream == null) { |
| 305 return ByteBuffer.wrap(buffer, lastPos, bufferPos - lastPos); |
| 306 } else { |
| 307 byteArrayStream.write(buffer, lastPos, bufferPos); |
| 308 return ByteBuffer.wrap(byteArrayStream.toByteArray()); |
| 309 } |
| 310 } |
| 311 } |
| 312 |
| 313 |
| 314 // ----------------------------------------------------------------- |
| 315 |
| 316 /** Read a {@code double} field value from the stream. */ |
| 317 public double readDouble() throws IOException { |
| 318 return Double.longBitsToDouble(readRawLittleEndian64()); |
| 319 } |
| 320 |
| 321 /** Read a {@code float} field value from the stream. */ |
| 322 public float readFloat() throws IOException { |
| 323 return Float.intBitsToFloat(readRawLittleEndian32()); |
| 324 } |
| 325 |
| 326 /** Read a {@code uint64} field value from the stream. */ |
| 327 public long readUInt64() throws IOException { |
| 328 return readRawVarint64(); |
| 329 } |
| 330 |
| 331 /** Read an {@code int64} field value from the stream. */ |
| 332 public long readInt64() throws IOException { |
| 333 return readRawVarint64(); |
| 334 } |
| 335 |
| 336 /** Read an {@code int32} field value from the stream. */ |
| 337 public int readInt32() throws IOException { |
| 338 return readRawVarint32(); |
| 339 } |
| 340 |
| 341 /** Read a {@code fixed64} field value from the stream. */ |
| 342 public long readFixed64() throws IOException { |
| 343 return readRawLittleEndian64(); |
| 344 } |
| 345 |
| 346 /** Read a {@code fixed32} field value from the stream. */ |
| 347 public int readFixed32() throws IOException { |
| 348 return readRawLittleEndian32(); |
| 349 } |
| 350 |
| 351 /** Read a {@code bool} field value from the stream. */ |
| 352 public boolean readBool() throws IOException { |
| 353 return readRawVarint64() != 0; |
| 354 } |
| 355 |
| 356 /** |
| 357 * Read a {@code string} field value from the stream. |
| 358 * If the stream contains malformed UTF-8, |
| 359 * replace the offending bytes with the standard UTF-8 replacement character. |
| 360 */ |
| 361 public String readString() throws IOException { |
| 362 final int size = readRawVarint32(); |
| 363 if (size <= (bufferSize - bufferPos) && size > 0) { |
| 364 // Fast path: We already have the bytes in a contiguous buffer, so |
| 365 // just copy directly from it. |
| 366 final String result = new String(buffer, bufferPos, size, Internal.UTF_8); |
| 367 bufferPos += size; |
| 368 return result; |
| 369 } else if (size == 0) { |
| 370 return ""; |
| 371 } else if (size <= bufferSize) { |
| 372 refillBuffer(size); |
| 373 String result = new String(buffer, bufferPos, size, Internal.UTF_8); |
| 374 bufferPos += size; |
| 375 return result; |
| 376 } else { |
| 377 // Slow path: Build a byte array first then copy it. |
| 378 return new String(readRawBytesSlowPath(size), Internal.UTF_8); |
| 379 } |
| 380 } |
| 381 |
| 382 /** |
| 383 * Read a {@code string} field value from the stream. |
| 384 * If the stream contains malformed UTF-8, |
| 385 * throw exception {@link InvalidProtocolBufferException}. |
| 386 */ |
| 387 public String readStringRequireUtf8() throws IOException { |
| 388 final int size = readRawVarint32(); |
| 389 final byte[] bytes; |
| 390 final int oldPos = bufferPos; |
| 391 final int pos; |
| 392 if (size <= (bufferSize - oldPos) && size > 0) { |
| 393 // Fast path: We already have the bytes in a contiguous buffer, so |
| 394 // just copy directly from it. |
| 395 bytes = buffer; |
| 396 bufferPos = oldPos + size; |
| 397 pos = oldPos; |
| 398 } else if (size == 0) { |
| 399 return ""; |
| 400 } else if (size <= bufferSize) { |
| 401 refillBuffer(size); |
| 402 bytes = buffer; |
| 403 pos = 0; |
| 404 bufferPos = pos + size; |
| 405 } else { |
| 406 // Slow path: Build a byte array first then copy it. |
| 407 bytes = readRawBytesSlowPath(size); |
| 408 pos = 0; |
| 409 } |
| 410 // TODO(martinrb): We could save a pass by validating while decoding. |
| 411 if (!Utf8.isValidUtf8(bytes, pos, pos + size)) { |
| 412 throw InvalidProtocolBufferException.invalidUtf8(); |
| 413 } |
| 414 return new String(bytes, pos, size, Internal.UTF_8); |
| 415 } |
| 416 |
| 417 /** Read a {@code group} field value from the stream. */ |
| 418 public void readGroup(final int fieldNumber, |
| 419 final MessageLite.Builder builder, |
| 420 final ExtensionRegistryLite extensionRegistry) |
| 421 throws IOException { |
| 422 if (recursionDepth >= recursionLimit) { |
| 423 throw InvalidProtocolBufferException.recursionLimitExceeded(); |
| 424 } |
| 425 ++recursionDepth; |
| 426 builder.mergeFrom(this, extensionRegistry); |
| 427 checkLastTagWas( |
| 428 WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); |
| 429 --recursionDepth; |
| 430 } |
| 431 |
| 432 |
| 433 /** Read a {@code group} field value from the stream. */ |
| 434 public <T extends MessageLite> T readGroup( |
| 435 final int fieldNumber, |
| 436 final Parser<T> parser, |
| 437 final ExtensionRegistryLite extensionRegistry) |
| 438 throws IOException { |
| 439 if (recursionDepth >= recursionLimit) { |
| 440 throw InvalidProtocolBufferException.recursionLimitExceeded(); |
| 441 } |
| 442 ++recursionDepth; |
| 443 T result = parser.parsePartialFrom(this, extensionRegistry); |
| 444 checkLastTagWas( |
| 445 WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); |
| 446 --recursionDepth; |
| 447 return result; |
| 448 } |
| 449 |
| 450 /** |
| 451 * Reads a {@code group} field value from the stream and merges it into the |
| 452 * given {@link UnknownFieldSet}. |
| 453 * |
| 454 * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so |
| 455 * you can just call {@link #readGroup}. |
190 */ | 456 */ |
191 @Deprecated | 457 @Deprecated |
192 public abstract boolean skipField(final int tag, final CodedOutputStream outpu
t) | 458 public void readUnknownGroup(final int fieldNumber, |
193 throws IOException; | 459 final MessageLite.Builder builder) |
194 | 460 throws IOException { |
195 /** | 461 // We know that UnknownFieldSet will ignore any ExtensionRegistry so it |
196 * Reads and discards an entire message. This will read either until EOF or un
til an endgroup tag, | 462 // is safe to pass null here. (We can't call |
197 * whichever comes first. | 463 // ExtensionRegistry.getEmptyRegistry() because that would make this |
198 */ | 464 // class depend on ExtensionRegistry, which is not part of the lite |
199 public abstract void skipMessage() throws IOException; | 465 // library.) |
200 | 466 readGroup(fieldNumber, builder, null); |
201 /** | 467 } |
202 * Reads an entire message and writes it to output in wire format. This will r
ead either until EOF | 468 |
203 * or until an endgroup tag, whichever comes first. | 469 /** Read an embedded message field value from the stream. */ |
204 */ | 470 public void readMessage(final MessageLite.Builder builder, |
205 public abstract void skipMessage(CodedOutputStream output) throws IOException; | 471 final ExtensionRegistryLite extensionRegistry) |
206 | 472 throws IOException { |
207 | 473 final int length = readRawVarint32(); |
208 // ----------------------------------------------------------------- | 474 if (recursionDepth >= recursionLimit) { |
209 | 475 throw InvalidProtocolBufferException.recursionLimitExceeded(); |
210 /** Read a {@code double} field value from the stream. */ | 476 } |
211 public abstract double readDouble() throws IOException; | 477 final int oldLimit = pushLimit(length); |
212 | 478 ++recursionDepth; |
213 /** Read a {@code float} field value from the stream. */ | 479 builder.mergeFrom(this, extensionRegistry); |
214 public abstract float readFloat() throws IOException; | 480 checkLastTagWas(0); |
215 | 481 --recursionDepth; |
216 /** Read a {@code uint64} field value from the stream. */ | 482 popLimit(oldLimit); |
217 public abstract long readUInt64() throws IOException; | 483 } |
218 | 484 |
219 /** Read an {@code int64} field value from the stream. */ | 485 |
220 public abstract long readInt64() throws IOException; | 486 /** Read an embedded message field value from the stream. */ |
221 | 487 public <T extends MessageLite> T readMessage( |
222 /** Read an {@code int32} field value from the stream. */ | 488 final Parser<T> parser, |
223 public abstract int readInt32() throws IOException; | |
224 | |
225 /** Read a {@code fixed64} field value from the stream. */ | |
226 public abstract long readFixed64() throws IOException; | |
227 | |
228 /** Read a {@code fixed32} field value from the stream. */ | |
229 public abstract int readFixed32() throws IOException; | |
230 | |
231 /** Read a {@code bool} field value from the stream. */ | |
232 public abstract boolean readBool() throws IOException; | |
233 | |
234 /** | |
235 * Read a {@code string} field value from the stream. If the stream contains m
alformed UTF-8, | |
236 * replace the offending bytes with the standard UTF-8 replacement character. | |
237 */ | |
238 public abstract String readString() throws IOException; | |
239 | |
240 /** | |
241 * Read a {@code string} field value from the stream. If the stream contains m
alformed UTF-8, | |
242 * throw exception {@link InvalidProtocolBufferException}. | |
243 */ | |
244 public abstract String readStringRequireUtf8() throws IOException; | |
245 | |
246 /** Read a {@code group} field value from the stream. */ | |
247 public abstract void readGroup( | |
248 final int fieldNumber, | |
249 final MessageLite.Builder builder, | |
250 final ExtensionRegistryLite extensionRegistry) | 489 final ExtensionRegistryLite extensionRegistry) |
251 throws IOException; | 490 throws IOException { |
252 | 491 int length = readRawVarint32(); |
253 | 492 if (recursionDepth >= recursionLimit) { |
254 /** Read a {@code group} field value from the stream. */ | 493 throw InvalidProtocolBufferException.recursionLimitExceeded(); |
255 public abstract <T extends MessageLite> T readGroup( | 494 } |
256 final int fieldNumber, final Parser<T> parser, final ExtensionRegistryLite
extensionRegistry) | 495 final int oldLimit = pushLimit(length); |
257 throws IOException; | 496 ++recursionDepth; |
258 | 497 T result = parser.parsePartialFrom(this, extensionRegistry); |
259 /** | 498 checkLastTagWas(0); |
260 * Reads a {@code group} field value from the stream and merges it into the gi
ven {@link | 499 --recursionDepth; |
261 * UnknownFieldSet}. | 500 popLimit(oldLimit); |
262 * | 501 return result; |
263 * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so
you can just call | 502 } |
264 * {@link #readGroup}. | |
265 */ | |
266 @Deprecated | |
267 public abstract void readUnknownGroup(final int fieldNumber, final MessageLite
.Builder builder) | |
268 throws IOException; | |
269 | |
270 /** Read an embedded message field value from the stream. */ | |
271 public abstract void readMessage( | |
272 final MessageLite.Builder builder, final ExtensionRegistryLite extensionRe
gistry) | |
273 throws IOException; | |
274 | |
275 | |
276 /** Read an embedded message field value from the stream. */ | |
277 public abstract <T extends MessageLite> T readMessage( | |
278 final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) thr
ows IOException; | |
279 | 503 |
280 /** Read a {@code bytes} field value from the stream. */ | 504 /** Read a {@code bytes} field value from the stream. */ |
281 public abstract ByteString readBytes() throws IOException; | 505 public ByteString readBytes() throws IOException { |
| 506 final int size = readRawVarint32(); |
| 507 if (size <= (bufferSize - bufferPos) && size > 0) { |
| 508 // Fast path: We already have the bytes in a contiguous buffer, so |
| 509 // just copy directly from it. |
| 510 final ByteString result = bufferIsImmutable && enableAliasing |
| 511 ? ByteString.wrap(buffer, bufferPos, size) |
| 512 : ByteString.copyFrom(buffer, bufferPos, size); |
| 513 bufferPos += size; |
| 514 return result; |
| 515 } else if (size == 0) { |
| 516 return ByteString.EMPTY; |
| 517 } else { |
| 518 // Slow path: Build a byte array first then copy it. |
| 519 return ByteString.wrap(readRawBytesSlowPath(size)); |
| 520 } |
| 521 } |
282 | 522 |
283 /** Read a {@code bytes} field value from the stream. */ | 523 /** Read a {@code bytes} field value from the stream. */ |
284 public abstract byte[] readByteArray() throws IOException; | 524 public byte[] readByteArray() throws IOException { |
| 525 final int size = readRawVarint32(); |
| 526 if (size <= (bufferSize - bufferPos) && size > 0) { |
| 527 // Fast path: We already have the bytes in a contiguous buffer, so |
| 528 // just copy directly from it. |
| 529 final byte[] result = |
| 530 Arrays.copyOfRange(buffer, bufferPos, bufferPos + size); |
| 531 bufferPos += size; |
| 532 return result; |
| 533 } else { |
| 534 // Slow path: Build a byte array first then copy it. |
| 535 return readRawBytesSlowPath(size); |
| 536 } |
| 537 } |
285 | 538 |
286 /** Read a {@code bytes} field value from the stream. */ | 539 /** Read a {@code bytes} field value from the stream. */ |
287 public abstract ByteBuffer readByteBuffer() throws IOException; | 540 public ByteBuffer readByteBuffer() throws IOException { |
| 541 final int size = readRawVarint32(); |
| 542 if (size <= (bufferSize - bufferPos) && size > 0) { |
| 543 // Fast path: We already have the bytes in a contiguous buffer. |
| 544 // When aliasing is enabled, we can return a ByteBuffer pointing directly |
| 545 // into the underlying byte array without copy if the CodedInputStream is |
| 546 // constructed from a byte array. If aliasing is disabled or the input is |
| 547 // from an InputStream or ByteString, we have to make a copy of the bytes. |
| 548 ByteBuffer result = input == null && !bufferIsImmutable && enableAliasing |
| 549 ? ByteBuffer.wrap(buffer, bufferPos, size).slice() |
| 550 : ByteBuffer.wrap(Arrays.copyOfRange( |
| 551 buffer, bufferPos, bufferPos + size)); |
| 552 bufferPos += size; |
| 553 return result; |
| 554 } else if (size == 0) { |
| 555 return Internal.EMPTY_BYTE_BUFFER; |
| 556 } else { |
| 557 // Slow path: Build a byte array first then copy it. |
| 558 return ByteBuffer.wrap(readRawBytesSlowPath(size)); |
| 559 } |
| 560 } |
288 | 561 |
289 /** Read a {@code uint32} field value from the stream. */ | 562 /** Read a {@code uint32} field value from the stream. */ |
290 public abstract int readUInt32() throws IOException; | 563 public int readUInt32() throws IOException { |
291 | 564 return readRawVarint32(); |
292 /** | 565 } |
293 * Read an enum field value from the stream. Caller is responsible for convert
ing the numeric | 566 |
294 * value to an actual enum. | 567 /** |
295 */ | 568 * Read an enum field value from the stream. Caller is responsible |
296 public abstract int readEnum() throws IOException; | 569 * for converting the numeric value to an actual enum. |
| 570 */ |
| 571 public int readEnum() throws IOException { |
| 572 return readRawVarint32(); |
| 573 } |
297 | 574 |
298 /** Read an {@code sfixed32} field value from the stream. */ | 575 /** Read an {@code sfixed32} field value from the stream. */ |
299 public abstract int readSFixed32() throws IOException; | 576 public int readSFixed32() throws IOException { |
| 577 return readRawLittleEndian32(); |
| 578 } |
300 | 579 |
301 /** Read an {@code sfixed64} field value from the stream. */ | 580 /** Read an {@code sfixed64} field value from the stream. */ |
302 public abstract long readSFixed64() throws IOException; | 581 public long readSFixed64() throws IOException { |
| 582 return readRawLittleEndian64(); |
| 583 } |
303 | 584 |
304 /** Read an {@code sint32} field value from the stream. */ | 585 /** Read an {@code sint32} field value from the stream. */ |
305 public abstract int readSInt32() throws IOException; | 586 public int readSInt32() throws IOException { |
| 587 return decodeZigZag32(readRawVarint32()); |
| 588 } |
306 | 589 |
307 /** Read an {@code sint64} field value from the stream. */ | 590 /** Read an {@code sint64} field value from the stream. */ |
308 public abstract long readSInt64() throws IOException; | 591 public long readSInt64() throws IOException { |
| 592 return decodeZigZag64(readRawVarint64()); |
| 593 } |
309 | 594 |
310 // ================================================================= | 595 // ================================================================= |
311 | 596 |
312 /** Read a raw Varint from the stream. If larger than 32 bits, discard the upp
er bits. */ | 597 /** |
313 public abstract int readRawVarint32() throws IOException; | 598 * Read a raw Varint from the stream. If larger than 32 bits, discard the |
| 599 * upper bits. |
| 600 */ |
| 601 public int readRawVarint32() throws IOException { |
| 602 // See implementation notes for readRawVarint64 |
| 603 fastpath: { |
| 604 int pos = bufferPos; |
| 605 |
| 606 if (bufferSize == pos) { |
| 607 break fastpath; |
| 608 } |
| 609 |
| 610 final byte[] buffer = this.buffer; |
| 611 int x; |
| 612 if ((x = buffer[pos++]) >= 0) { |
| 613 bufferPos = pos; |
| 614 return x; |
| 615 } else if (bufferSize - pos < 9) { |
| 616 break fastpath; |
| 617 } else if ((x ^= (buffer[pos++] << 7)) < 0) { |
| 618 x ^= (~0 << 7); |
| 619 } else if ((x ^= (buffer[pos++] << 14)) >= 0) { |
| 620 x ^= (~0 << 7) ^ (~0 << 14); |
| 621 } else if ((x ^= (buffer[pos++] << 21)) < 0) { |
| 622 x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21); |
| 623 } else { |
| 624 int y = buffer[pos++]; |
| 625 x ^= y << 28; |
| 626 x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28); |
| 627 if (y < 0 && |
| 628 buffer[pos++] < 0 && |
| 629 buffer[pos++] < 0 && |
| 630 buffer[pos++] < 0 && |
| 631 buffer[pos++] < 0 && |
| 632 buffer[pos++] < 0) { |
| 633 break fastpath; // Will throw malformedVarint() |
| 634 } |
| 635 } |
| 636 bufferPos = pos; |
| 637 return x; |
| 638 } |
| 639 return (int) readRawVarint64SlowPath(); |
| 640 } |
| 641 |
| 642 private void skipRawVarint() throws IOException { |
| 643 if (bufferSize - bufferPos >= 10) { |
| 644 final byte[] buffer = this.buffer; |
| 645 int pos = bufferPos; |
| 646 for (int i = 0; i < 10; i++) { |
| 647 if (buffer[pos++] >= 0) { |
| 648 bufferPos = pos; |
| 649 return; |
| 650 } |
| 651 } |
| 652 } |
| 653 skipRawVarintSlowPath(); |
| 654 } |
| 655 |
| 656 private void skipRawVarintSlowPath() throws IOException { |
| 657 for (int i = 0; i < 10; i++) { |
| 658 if (readRawByte() >= 0) { |
| 659 return; |
| 660 } |
| 661 } |
| 662 throw InvalidProtocolBufferException.malformedVarint(); |
| 663 } |
| 664 |
| 665 /** |
| 666 * Reads a varint from the input one byte at a time, so that it does not |
| 667 * read any bytes after the end of the varint. If you simply wrapped the |
| 668 * stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)} |
| 669 * then you would probably end up reading past the end of the varint since |
| 670 * CodedInputStream buffers its input. |
| 671 */ |
| 672 static int readRawVarint32(final InputStream input) throws IOException { |
| 673 final int firstByte = input.read(); |
| 674 if (firstByte == -1) { |
| 675 throw InvalidProtocolBufferException.truncatedMessage(); |
| 676 } |
| 677 return readRawVarint32(firstByte, input); |
| 678 } |
| 679 |
| 680 /** |
| 681 * Like {@link #readRawVarint32(InputStream)}, but expects that the caller |
| 682 * has already read one byte. This allows the caller to determine if EOF |
| 683 * has been reached before attempting to read. |
| 684 */ |
| 685 public static int readRawVarint32( |
| 686 final int firstByte, final InputStream input) throws IOException { |
| 687 if ((firstByte & 0x80) == 0) { |
| 688 return firstByte; |
| 689 } |
| 690 |
| 691 int result = firstByte & 0x7f; |
| 692 int offset = 7; |
| 693 for (; offset < 32; offset += 7) { |
| 694 final int b = input.read(); |
| 695 if (b == -1) { |
| 696 throw InvalidProtocolBufferException.truncatedMessage(); |
| 697 } |
| 698 result |= (b & 0x7f) << offset; |
| 699 if ((b & 0x80) == 0) { |
| 700 return result; |
| 701 } |
| 702 } |
| 703 // Keep reading up to 64 bits. |
| 704 for (; offset < 64; offset += 7) { |
| 705 final int b = input.read(); |
| 706 if (b == -1) { |
| 707 throw InvalidProtocolBufferException.truncatedMessage(); |
| 708 } |
| 709 if ((b & 0x80) == 0) { |
| 710 return result; |
| 711 } |
| 712 } |
| 713 throw InvalidProtocolBufferException.malformedVarint(); |
| 714 } |
314 | 715 |
315 /** Read a raw Varint from the stream. */ | 716 /** Read a raw Varint from the stream. */ |
316 public abstract long readRawVarint64() throws IOException; | 717 public long readRawVarint64() throws IOException { |
| 718 // Implementation notes: |
| 719 // |
| 720 // Optimized for one-byte values, expected to be common. |
| 721 // The particular code below was selected from various candidates |
| 722 // empirically, by winning VarintBenchmark. |
| 723 // |
| 724 // Sign extension of (signed) Java bytes is usually a nuisance, but |
| 725 // we exploit it here to more easily obtain the sign of bytes read. |
| 726 // Instead of cleaning up the sign extension bits by masking eagerly, |
| 727 // we delay until we find the final (positive) byte, when we clear all |
| 728 // accumulated bits with one xor. We depend on javac to constant fold. |
| 729 fastpath: { |
| 730 int pos = bufferPos; |
| 731 |
| 732 if (bufferSize == pos) { |
| 733 break fastpath; |
| 734 } |
| 735 |
| 736 final byte[] buffer = this.buffer; |
| 737 long x; |
| 738 int y; |
| 739 if ((y = buffer[pos++]) >= 0) { |
| 740 bufferPos = pos; |
| 741 return y; |
| 742 } else if (bufferSize - pos < 9) { |
| 743 break fastpath; |
| 744 } else if ((y ^= (buffer[pos++] << 7)) < 0) { |
| 745 x = y ^ (~0 << 7); |
| 746 } else if ((y ^= (buffer[pos++] << 14)) >= 0) { |
| 747 x = y ^ ((~0 << 7) ^ (~0 << 14)); |
| 748 } else if ((y ^= (buffer[pos++] << 21)) < 0) { |
| 749 x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21)); |
| 750 } else if ((x = ((long) y) ^ ((long) buffer[pos++] << 28)) >= 0L) { |
| 751 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); |
| 752 } else if ((x ^= ((long) buffer[pos++] << 35)) < 0L) { |
| 753 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35); |
| 754 } else if ((x ^= ((long) buffer[pos++] << 42)) >= 0L) { |
| 755 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35)
^ (~0L << 42); |
| 756 } else if ((x ^= ((long) buffer[pos++] << 49)) < 0L) { |
| 757 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35)
^ (~0L << 42) |
| 758 ^ (~0L << 49); |
| 759 } else { |
| 760 x ^= ((long) buffer[pos++] << 56); |
| 761 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35)
^ (~0L << 42) |
| 762 ^ (~0L << 49) ^ (~0L << 56); |
| 763 if (x < 0L) { |
| 764 if (buffer[pos++] < 0L) { |
| 765 break fastpath; // Will throw malformedVarint() |
| 766 } |
| 767 } |
| 768 } |
| 769 bufferPos = pos; |
| 770 return x; |
| 771 } |
| 772 return readRawVarint64SlowPath(); |
| 773 } |
317 | 774 |
318 /** Variant of readRawVarint64 for when uncomfortably close to the limit. */ | 775 /** Variant of readRawVarint64 for when uncomfortably close to the limit. */ |
319 /* Visible for testing */ | 776 /* Visible for testing */ |
320 abstract long readRawVarint64SlowPath() throws IOException; | 777 long readRawVarint64SlowPath() throws IOException { |
| 778 long result = 0; |
| 779 for (int shift = 0; shift < 64; shift += 7) { |
| 780 final byte b = readRawByte(); |
| 781 result |= (long) (b & 0x7F) << shift; |
| 782 if ((b & 0x80) == 0) { |
| 783 return result; |
| 784 } |
| 785 } |
| 786 throw InvalidProtocolBufferException.malformedVarint(); |
| 787 } |
321 | 788 |
322 /** Read a 32-bit little-endian integer from the stream. */ | 789 /** Read a 32-bit little-endian integer from the stream. */ |
323 public abstract int readRawLittleEndian32() throws IOException; | 790 public int readRawLittleEndian32() throws IOException { |
| 791 int pos = bufferPos; |
| 792 |
| 793 // hand-inlined ensureAvailable(4); |
| 794 if (bufferSize - pos < 4) { |
| 795 refillBuffer(4); |
| 796 pos = bufferPos; |
| 797 } |
| 798 |
| 799 final byte[] buffer = this.buffer; |
| 800 bufferPos = pos + 4; |
| 801 return (((buffer[pos] & 0xff)) | |
| 802 ((buffer[pos + 1] & 0xff) << 8) | |
| 803 ((buffer[pos + 2] & 0xff) << 16) | |
| 804 ((buffer[pos + 3] & 0xff) << 24)); |
| 805 } |
324 | 806 |
325 /** Read a 64-bit little-endian integer from the stream. */ | 807 /** Read a 64-bit little-endian integer from the stream. */ |
326 public abstract long readRawLittleEndian64() throws IOException; | 808 public long readRawLittleEndian64() throws IOException { |
| 809 int pos = bufferPos; |
| 810 |
| 811 // hand-inlined ensureAvailable(8); |
| 812 if (bufferSize - pos < 8) { |
| 813 refillBuffer(8); |
| 814 pos = bufferPos; |
| 815 } |
| 816 |
| 817 final byte[] buffer = this.buffer; |
| 818 bufferPos = pos + 8; |
| 819 return ((((long) buffer[pos] & 0xffL)) | |
| 820 (((long) buffer[pos + 1] & 0xffL) << 8) | |
| 821 (((long) buffer[pos + 2] & 0xffL) << 16) | |
| 822 (((long) buffer[pos + 3] & 0xffL) << 24) | |
| 823 (((long) buffer[pos + 4] & 0xffL) << 32) | |
| 824 (((long) buffer[pos + 5] & 0xffL) << 40) | |
| 825 (((long) buffer[pos + 6] & 0xffL) << 48) | |
| 826 (((long) buffer[pos + 7] & 0xffL) << 56)); |
| 827 } |
| 828 |
| 829 /** |
| 830 * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers |
| 831 * into values that can be efficiently encoded with varint. (Otherwise, |
| 832 * negative values must be sign-extended to 64 bits to be varint encoded, |
| 833 * thus always taking 10 bytes on the wire.) |
| 834 * |
| 835 * @param n An unsigned 32-bit integer, stored in a signed int because |
| 836 * Java has no explicit unsigned support. |
| 837 * @return A signed 32-bit integer. |
| 838 */ |
| 839 public static int decodeZigZag32(final int n) { |
| 840 return (n >>> 1) ^ -(n & 1); |
| 841 } |
| 842 |
| 843 /** |
| 844 * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers |
| 845 * into values that can be efficiently encoded with varint. (Otherwise, |
| 846 * negative values must be sign-extended to 64 bits to be varint encoded, |
| 847 * thus always taking 10 bytes on the wire.) |
| 848 * |
| 849 * @param n An unsigned 64-bit integer, stored in a signed int because |
| 850 * Java has no explicit unsigned support. |
| 851 * @return A signed 64-bit integer. |
| 852 */ |
| 853 public static long decodeZigZag64(final long n) { |
| 854 return (n >>> 1) ^ -(n & 1); |
| 855 } |
327 | 856 |
328 // ----------------------------------------------------------------- | 857 // ----------------------------------------------------------------- |
329 | 858 |
330 /** | 859 private final byte[] buffer; |
331 * Enables {@link ByteString} aliasing of the underlying buffer, trading off o
n buffer pinning for | 860 private final boolean bufferIsImmutable; |
332 * data copies. Only valid for buffer-backed streams. | 861 private int bufferSize; |
333 */ | 862 private int bufferSizeAfterLimit; |
334 public abstract void enableAliasing(boolean enabled); | 863 private int bufferPos; |
335 | 864 private final InputStream input; |
336 /** | 865 private int lastTag; |
337 * Set the maximum message recursion depth. In order to prevent malicious mess
ages from causing | 866 private boolean enableAliasing = false; |
338 * stack overflows, {@code CodedInputStream} limits how deeply messages may be
nested. The default | 867 |
339 * limit is 64. | 868 /** |
| 869 * The total number of bytes read before the current buffer. The total |
| 870 * bytes read up to the current position can be computed as |
| 871 * {@code totalBytesRetired + bufferPos}. This value may be negative if |
| 872 * reading started in the middle of the current buffer (e.g. if the |
| 873 * constructor that takes a byte array and an offset was used). |
| 874 */ |
| 875 private int totalBytesRetired; |
| 876 |
| 877 /** The absolute position of the end of the current message. */ |
| 878 private int currentLimit = Integer.MAX_VALUE; |
| 879 |
| 880 /** See setRecursionLimit() */ |
| 881 private int recursionDepth; |
| 882 private int recursionLimit = DEFAULT_RECURSION_LIMIT; |
| 883 |
| 884 /** See setSizeLimit() */ |
| 885 private int sizeLimit = DEFAULT_SIZE_LIMIT; |
| 886 |
| 887 private static final int DEFAULT_RECURSION_LIMIT = 100; |
| 888 private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB |
| 889 private static final int BUFFER_SIZE = 4096; |
| 890 |
| 891 private CodedInputStream( |
| 892 final byte[] buffer, final int off, final int len, boolean bufferIsImmutab
le) { |
| 893 this.buffer = buffer; |
| 894 bufferSize = off + len; |
| 895 bufferPos = off; |
| 896 totalBytesRetired = -off; |
| 897 input = null; |
| 898 this.bufferIsImmutable = bufferIsImmutable; |
| 899 } |
| 900 |
| 901 private CodedInputStream(final InputStream input, int bufferSize) { |
| 902 buffer = new byte[bufferSize]; |
| 903 bufferSize = 0; |
| 904 bufferPos = 0; |
| 905 totalBytesRetired = 0; |
| 906 this.input = input; |
| 907 bufferIsImmutable = false; |
| 908 } |
| 909 |
| 910 public void enableAliasing(boolean enabled) { |
| 911 this.enableAliasing = enabled; |
| 912 } |
| 913 |
| 914 /** |
| 915 * Set the maximum message recursion depth. In order to prevent malicious |
| 916 * messages from causing stack overflows, {@code CodedInputStream} limits |
| 917 * how deeply messages may be nested. The default limit is 64. |
340 * | 918 * |
341 * @return the old limit. | 919 * @return the old limit. |
342 */ | 920 */ |
343 public final int setRecursionLimit(final int limit) { | 921 public int setRecursionLimit(final int limit) { |
344 if (limit < 0) { | 922 if (limit < 0) { |
345 throw new IllegalArgumentException("Recursion limit cannot be negative: "
+ limit); | 923 throw new IllegalArgumentException( |
| 924 "Recursion limit cannot be negative: " + limit); |
346 } | 925 } |
347 final int oldLimit = recursionLimit; | 926 final int oldLimit = recursionLimit; |
348 recursionLimit = limit; | 927 recursionLimit = limit; |
349 return oldLimit; | 928 return oldLimit; |
350 } | 929 } |
351 | 930 |
352 /** | 931 /** |
353 * Only valid for {@link InputStream}-backed streams. | 932 * Set the maximum message size. In order to prevent malicious |
354 * | 933 * messages from exhausting memory or causing integer overflows, |
355 * <p>Set the maximum message size. In order to prevent malicious messages fro
m exhausting memory | 934 * {@code CodedInputStream} limits how large a message may be. |
356 * or causing integer overflows, {@code CodedInputStream} limits how large a m
essage may be. The | 935 * The default limit is 64MB. You should set this limit as small |
357 * default limit is 64MB. You should set this limit as small as you can withou
t harming your app's | 936 * as you can without harming your app's functionality. Note that |
358 * functionality. Note that size limits only apply when reading from an {@code
InputStream}, not | 937 * size limits only apply when reading from an {@code InputStream}, not |
359 * when constructed around a raw byte array (nor with {@link ByteString#newCod
edInput}). | 938 * when constructed around a raw byte array (nor with |
360 * | 939 * {@link ByteString#newCodedInput}). |
361 * <p>If you want to read several messages from a single CodedInputStream, you
could call {@link | 940 * <p> |
362 * #resetSizeCounter()} after each one to avoid hitting the size limit. | 941 * If you want to read several messages from a single CodedInputStream, you |
| 942 * could call {@link #resetSizeCounter()} after each one to avoid hitting the |
| 943 * size limit. |
363 * | 944 * |
364 * @return the old limit. | 945 * @return the old limit. |
365 */ | 946 */ |
366 public final int setSizeLimit(final int limit) { | 947 public int setSizeLimit(final int limit) { |
367 if (limit < 0) { | 948 if (limit < 0) { |
368 throw new IllegalArgumentException("Size limit cannot be negative: " + lim
it); | 949 throw new IllegalArgumentException( |
| 950 "Size limit cannot be negative: " + limit); |
369 } | 951 } |
370 final int oldLimit = sizeLimit; | 952 final int oldLimit = sizeLimit; |
371 sizeLimit = limit; | 953 sizeLimit = limit; |
372 return oldLimit; | 954 return oldLimit; |
373 } | 955 } |
374 | 956 |
375 /** | 957 /** |
376 * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). O
nly valid for {@link | 958 * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). |
377 * InputStream}-backed streams. | 959 */ |
378 */ | 960 public void resetSizeCounter() { |
379 public abstract void resetSizeCounter(); | 961 totalBytesRetired = -bufferPos; |
380 | 962 } |
381 /** | 963 |
382 * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This i
s called when | 964 /** |
383 * descending into a length-delimited embedded message. | 965 * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This |
384 * | 966 * is called when descending into a length-delimited embedded message. |
385 * <p>Note that {@code pushLimit()} does NOT affect how many bytes the {@code
CodedInputStream} | 967 * |
386 * reads from an underlying {@code InputStream} when refreshing its buffer. If
you need to prevent | 968 * <p>Note that {@code pushLimit()} does NOT affect how many bytes the |
387 * reading past a certain point in the underlying {@code InputStream} (e.g. be
cause you expect it | 969 * {@code CodedInputStream} reads from an underlying {@code InputStream} when |
388 * to contain more data after the end of the message which you need to handle
differently) then | 970 * refreshing its buffer. If you need to prevent reading past a certain |
389 * you must place a wrapper around your {@code InputStream} which limits the a
mount of data that | 971 * point in the underlying {@code InputStream} (e.g. because you expect it to |
390 * can be read from it. | 972 * contain more data after the end of the message which you need to handle |
| 973 * differently) then you must place a wrapper around your {@code InputStream} |
| 974 * which limits the amount of data that can be read from it. |
391 * | 975 * |
392 * @return the old limit. | 976 * @return the old limit. |
393 */ | 977 */ |
394 public abstract int pushLimit(int byteLimit) throws InvalidProtocolBufferExcep
tion; | 978 public int pushLimit(int byteLimit) throws InvalidProtocolBufferException { |
| 979 if (byteLimit < 0) { |
| 980 throw InvalidProtocolBufferException.negativeSize(); |
| 981 } |
| 982 byteLimit += totalBytesRetired + bufferPos; |
| 983 final int oldLimit = currentLimit; |
| 984 if (byteLimit > oldLimit) { |
| 985 throw InvalidProtocolBufferException.truncatedMessage(); |
| 986 } |
| 987 currentLimit = byteLimit; |
| 988 |
| 989 recomputeBufferSizeAfterLimit(); |
| 990 |
| 991 return oldLimit; |
| 992 } |
| 993 |
| 994 private void recomputeBufferSizeAfterLimit() { |
| 995 bufferSize += bufferSizeAfterLimit; |
| 996 final int bufferEnd = totalBytesRetired + bufferSize; |
| 997 if (bufferEnd > currentLimit) { |
| 998 // Limit is in current buffer. |
| 999 bufferSizeAfterLimit = bufferEnd - currentLimit; |
| 1000 bufferSize -= bufferSizeAfterLimit; |
| 1001 } else { |
| 1002 bufferSizeAfterLimit = 0; |
| 1003 } |
| 1004 } |
395 | 1005 |
396 /** | 1006 /** |
397 * Discards the current limit, returning to the previous limit. | 1007 * Discards the current limit, returning to the previous limit. |
398 * | 1008 * |
399 * @param oldLimit The old limit, as returned by {@code pushLimit}. | 1009 * @param oldLimit The old limit, as returned by {@code pushLimit}. |
400 */ | 1010 */ |
401 public abstract void popLimit(final int oldLimit); | 1011 public void popLimit(final int oldLimit) { |
402 | 1012 currentLimit = oldLimit; |
403 /** | 1013 recomputeBufferSizeAfterLimit(); |
404 * Returns the number of bytes to be read before the current limit. If no limi
t is set, returns | 1014 } |
405 * -1. | 1015 |
406 */ | 1016 /** |
407 public abstract int getBytesUntilLimit(); | 1017 * Returns the number of bytes to be read before the current limit. |
408 | 1018 * If no limit is set, returns -1. |
409 /** | 1019 */ |
410 * Returns true if the stream has reached the end of the input. This is the ca
se if either the end | 1020 public int getBytesUntilLimit() { |
411 * of the underlying input source has been reached or if the stream has reache
d a limit created | 1021 if (currentLimit == Integer.MAX_VALUE) { |
412 * using {@link #pushLimit(int)}. | 1022 return -1; |
413 */ | 1023 } |
414 public abstract boolean isAtEnd() throws IOException; | 1024 |
415 | 1025 final int currentAbsolutePosition = totalBytesRetired + bufferPos; |
416 /** | 1026 return currentLimit - currentAbsolutePosition; |
417 * The total bytes read up to the current position. Calling {@link #resetSizeC
ounter()} resets | 1027 } |
418 * this value to zero. | 1028 |
419 */ | 1029 /** |
420 public abstract int getTotalBytesRead(); | 1030 * Returns true if the stream has reached the end of the input. This is the |
421 | 1031 * case if either the end of the underlying input source has been reached or |
422 /** | 1032 * if the stream has reached a limit created using {@link #pushLimit(int)}. |
423 * Read one byte from the input. | 1033 */ |
424 * | 1034 public boolean isAtEnd() throws IOException { |
425 * @throws InvalidProtocolBufferException The end of the stream or the current
limit was reached. | 1035 return bufferPos == bufferSize && !tryRefillBuffer(1); |
426 */ | 1036 } |
427 public abstract byte readRawByte() throws IOException; | 1037 |
428 | 1038 /** |
429 /** | 1039 * The total bytes read up to the current position. Calling |
430 * Read a fixed size of bytes from the input. | 1040 * {@link #resetSizeCounter()} resets this value to zero. |
431 * | 1041 */ |
432 * @throws InvalidProtocolBufferException The end of the stream or the current
limit was reached. | 1042 public int getTotalBytesRead() { |
433 */ | 1043 return totalBytesRetired + bufferPos; |
434 public abstract byte[] readRawBytes(final int size) throws IOException; | 1044 } |
435 | 1045 |
436 /** | 1046 private interface RefillCallback { |
437 * Reads and discards {@code size} bytes. | 1047 void onRefill(); |
438 * | 1048 } |
439 * @throws InvalidProtocolBufferException The end of the stream or the current
limit was reached. | 1049 |
440 */ | 1050 private RefillCallback refillCallback = null; |
441 public abstract void skipRawBytes(final int size) throws IOException; | 1051 |
442 | 1052 /** |
443 /** | 1053 * Reads more bytes from the input, making at least {@code n} bytes available |
444 * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers into v
alues that can be | 1054 * in the buffer. Caller must ensure that the requested space is not yet |
445 * efficiently encoded with varint. (Otherwise, negative values must be sign-e
xtended to 64 bits | 1055 * available, and that the requested space is less than BUFFER_SIZE. |
446 * to be varint encoded, thus always taking 10 bytes on the wire.) | 1056 * |
447 * | 1057 * @throws InvalidProtocolBufferException The end of the stream or the current |
448 * @param n An unsigned 32-bit integer, stored in a signed int because Java ha
s no explicit | 1058 * limit was reached. |
449 * unsigned support. | 1059 */ |
450 * @return A signed 32-bit integer. | 1060 private void refillBuffer(int n) throws IOException { |
451 */ | 1061 if (!tryRefillBuffer(n)) { |
452 public static int decodeZigZag32(final int n) { | 1062 throw InvalidProtocolBufferException.truncatedMessage(); |
453 return (n >>> 1) ^ -(n & 1); | 1063 } |
454 } | 1064 } |
455 | 1065 |
456 /** | 1066 /** |
457 * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into v
alues that can be | 1067 * Tries to read more bytes from the input, making at least {@code n} bytes |
458 * efficiently encoded with varint. (Otherwise, negative values must be sign-e
xtended to 64 bits | 1068 * available in the buffer. Caller must ensure that the requested space is |
459 * to be varint encoded, thus always taking 10 bytes on the wire.) | 1069 * not yet available, and that the requested space is less than BUFFER_SIZE. |
460 * | 1070 * |
461 * @param n An unsigned 64-bit integer, stored in a signed int because Java ha
s no explicit | 1071 * @return {@code true} if the bytes could be made available; {@code false} |
462 * unsigned support. | 1072 * if the end of the stream or the current limit was reached. |
463 * @return A signed 64-bit integer. | 1073 */ |
464 */ | 1074 private boolean tryRefillBuffer(int n) throws IOException { |
465 public static long decodeZigZag64(final long n) { | 1075 if (bufferPos + n <= bufferSize) { |
466 return (n >>> 1) ^ -(n & 1); | 1076 throw new IllegalStateException( |
467 } | 1077 "refillBuffer() called when " + n + |
468 | 1078 " bytes were already available in buffer"); |
469 /** | 1079 } |
470 * Like {@link #readRawVarint32(InputStream)}, but expects that the caller has
already read one | 1080 |
471 * byte. This allows the caller to determine if EOF has been reached before at
tempting to read. | 1081 if (totalBytesRetired + bufferPos + n > currentLimit) { |
472 */ | 1082 // Oops, we hit a limit. |
473 public static int readRawVarint32(final int firstByte, final InputStream input
) | 1083 return false; |
474 throws IOException { | 1084 } |
475 if ((firstByte & 0x80) == 0) { | 1085 |
476 return firstByte; | 1086 if (refillCallback != null) { |
477 } | 1087 refillCallback.onRefill(); |
478 | 1088 } |
479 int result = firstByte & 0x7f; | 1089 |
480 int offset = 7; | 1090 if (input != null) { |
481 for (; offset < 32; offset += 7) { | 1091 int pos = bufferPos; |
482 final int b = input.read(); | 1092 if (pos > 0) { |
483 if (b == -1) { | 1093 if (bufferSize > pos) { |
484 throw InvalidProtocolBufferException.truncatedMessage(); | 1094 System.arraycopy(buffer, pos, buffer, 0, bufferSize - pos); |
485 } | |
486 result |= (b & 0x7f) << offset; | |
487 if ((b & 0x80) == 0) { | |
488 return result; | |
489 } | |
490 } | |
491 // Keep reading up to 64 bits. | |
492 for (; offset < 64; offset += 7) { | |
493 final int b = input.read(); | |
494 if (b == -1) { | |
495 throw InvalidProtocolBufferException.truncatedMessage(); | |
496 } | |
497 if ((b & 0x80) == 0) { | |
498 return result; | |
499 } | |
500 } | |
501 throw InvalidProtocolBufferException.malformedVarint(); | |
502 } | |
503 | |
504 /** | |
505 * Reads a varint from the input one byte at a time, so that it does not read
any bytes after the | |
506 * end of the varint. If you simply wrapped the stream in a CodedInputStream a
nd used {@link | |
507 * #readRawVarint32(InputStream)} then you would probably end up reading past
the end of the | |
508 * varint since CodedInputStream buffers its input. | |
509 */ | |
510 static int readRawVarint32(final InputStream input) throws IOException { | |
511 final int firstByte = input.read(); | |
512 if (firstByte == -1) { | |
513 throw InvalidProtocolBufferException.truncatedMessage(); | |
514 } | |
515 return readRawVarint32(firstByte, input); | |
516 } | |
517 | |
518 /** A {@link CodedInputStream} implementation that uses a backing array as the
input. */ | |
519 private static final class ArrayDecoder extends CodedInputStream { | |
520 private final byte[] buffer; | |
521 private final boolean immutable; | |
522 private int limit; | |
523 private int bufferSizeAfterLimit; | |
524 private int pos; | |
525 private int startPos; | |
526 private int lastTag; | |
527 private boolean enableAliasing; | |
528 | |
529 /** The absolute position of the end of the current message. */ | |
530 private int currentLimit = Integer.MAX_VALUE; | |
531 | |
532 private ArrayDecoder(final byte[] buffer, final int offset, final int len, b
oolean immutable) { | |
533 this.buffer = buffer; | |
534 limit = offset + len; | |
535 pos = offset; | |
536 startPos = pos; | |
537 this.immutable = immutable; | |
538 } | |
539 | |
540 @Override | |
541 public int readTag() throws IOException { | |
542 if (isAtEnd()) { | |
543 lastTag = 0; | |
544 return 0; | |
545 } | |
546 | |
547 lastTag = readRawVarint32(); | |
548 if (WireFormat.getTagFieldNumber(lastTag) == 0) { | |
549 // If we actually read zero (or any tag number corresponding to field | |
550 // number zero), that's not a valid tag. | |
551 throw InvalidProtocolBufferException.invalidTag(); | |
552 } | |
553 return lastTag; | |
554 } | |
555 | |
556 @Override | |
557 public void checkLastTagWas(final int value) throws InvalidProtocolBufferExc
eption { | |
558 if (lastTag != value) { | |
559 throw InvalidProtocolBufferException.invalidEndTag(); | |
560 } | |
561 } | |
562 | |
563 @Override | |
564 public int getLastTag() { | |
565 return lastTag; | |
566 } | |
567 | |
568 @Override | |
569 public boolean skipField(final int tag) throws IOException { | |
570 switch (WireFormat.getTagWireType(tag)) { | |
571 case WireFormat.WIRETYPE_VARINT: | |
572 skipRawVarint(); | |
573 return true; | |
574 case WireFormat.WIRETYPE_FIXED64: | |
575 skipRawBytes(FIXED_64_SIZE); | |
576 return true; | |
577 case WireFormat.WIRETYPE_LENGTH_DELIMITED: | |
578 skipRawBytes(readRawVarint32()); | |
579 return true; | |
580 case WireFormat.WIRETYPE_START_GROUP: | |
581 skipMessage(); | |
582 checkLastTagWas( | |
583 WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WireFormat.W
IRETYPE_END_GROUP)); | |
584 return true; | |
585 case WireFormat.WIRETYPE_END_GROUP: | |
586 return false; | |
587 case WireFormat.WIRETYPE_FIXED32: | |
588 skipRawBytes(FIXED_32_SIZE); | |
589 return true; | |
590 default: | |
591 throw InvalidProtocolBufferException.invalidWireType(); | |
592 } | |
593 } | |
594 | |
595 @Override | |
596 public boolean skipField(final int tag, final CodedOutputStream output) thro
ws IOException { | |
597 switch (WireFormat.getTagWireType(tag)) { | |
598 case WireFormat.WIRETYPE_VARINT: | |
599 { | |
600 long value = readInt64(); | |
601 output.writeRawVarint32(tag); | |
602 output.writeUInt64NoTag(value); | |
603 return true; | |
604 } | |
605 case WireFormat.WIRETYPE_FIXED64: | |
606 { | |
607 long value = readRawLittleEndian64(); | |
608 output.writeRawVarint32(tag); | |
609 output.writeFixed64NoTag(value); | |
610 return true; | |
611 } | |
612 case WireFormat.WIRETYPE_LENGTH_DELIMITED: | |
613 { | |
614 ByteString value = readBytes(); | |
615 output.writeRawVarint32(tag); | |
616 output.writeBytesNoTag(value); | |
617 return true; | |
618 } | |
619 case WireFormat.WIRETYPE_START_GROUP: | |
620 { | |
621 output.writeRawVarint32(tag); | |
622 skipMessage(output); | |
623 int endtag = | |
624 WireFormat.makeTag( | |
625 WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_G
ROUP); | |
626 checkLastTagWas(endtag); | |
627 output.writeRawVarint32(endtag); | |
628 return true; | |
629 } | |
630 case WireFormat.WIRETYPE_END_GROUP: | |
631 { | |
632 return false; | |
633 } | |
634 case WireFormat.WIRETYPE_FIXED32: | |
635 { | |
636 int value = readRawLittleEndian32(); | |
637 output.writeRawVarint32(tag); | |
638 output.writeFixed32NoTag(value); | |
639 return true; | |
640 } | |
641 default: | |
642 throw InvalidProtocolBufferException.invalidWireType(); | |
643 } | |
644 } | |
645 | |
646 @Override | |
647 public void skipMessage() throws IOException { | |
648 while (true) { | |
649 final int tag = readTag(); | |
650 if (tag == 0 || !skipField(tag)) { | |
651 return; | |
652 } | 1095 } |
653 } | 1096 totalBytesRetired += pos; |
654 } | 1097 bufferSize -= pos; |
655 | 1098 bufferPos = 0; |
656 @Override | |
657 public void skipMessage(CodedOutputStream output) throws IOException { | |
658 while (true) { | |
659 final int tag = readTag(); | |
660 if (tag == 0 || !skipField(tag, output)) { | |
661 return; | |
662 } | |
663 } | |
664 } | |
665 | |
666 | |
667 // ----------------------------------------------------------------- | |
668 | |
669 @Override | |
670 public double readDouble() throws IOException { | |
671 return Double.longBitsToDouble(readRawLittleEndian64()); | |
672 } | |
673 | |
674 @Override | |
675 public float readFloat() throws IOException { | |
676 return Float.intBitsToFloat(readRawLittleEndian32()); | |
677 } | |
678 | |
679 @Override | |
680 public long readUInt64() throws IOException { | |
681 return readRawVarint64(); | |
682 } | |
683 | |
684 @Override | |
685 public long readInt64() throws IOException { | |
686 return readRawVarint64(); | |
687 } | |
688 | |
689 @Override | |
690 public int readInt32() throws IOException { | |
691 return readRawVarint32(); | |
692 } | |
693 | |
694 @Override | |
695 public long readFixed64() throws IOException { | |
696 return readRawLittleEndian64(); | |
697 } | |
698 | |
699 @Override | |
700 public int readFixed32() throws IOException { | |
701 return readRawLittleEndian32(); | |
702 } | |
703 | |
704 @Override | |
705 public boolean readBool() throws IOException { | |
706 return readRawVarint64() != 0; | |
707 } | |
708 | |
709 @Override | |
710 public String readString() throws IOException { | |
711 final int size = readRawVarint32(); | |
712 if (size > 0 && size <= (limit - pos)) { | |
713 // Fast path: We already have the bytes in a contiguous buffer, so | |
714 // just copy directly from it. | |
715 final String result = new String(buffer, pos, size, UTF_8); | |
716 pos += size; | |
717 return result; | |
718 } | |
719 | |
720 if (size == 0) { | |
721 return ""; | |
722 } | |
723 if (size < 0) { | |
724 throw InvalidProtocolBufferException.negativeSize(); | |
725 } | |
726 throw InvalidProtocolBufferException.truncatedMessage(); | |
727 } | |
728 | |
729 @Override | |
730 public String readStringRequireUtf8() throws IOException { | |
731 final int size = readRawVarint32(); | |
732 if (size > 0 && size <= (limit - pos)) { | |
733 // TODO(martinrb): We could save a pass by validating while decoding. | |
734 if (!Utf8.isValidUtf8(buffer, pos, pos + size)) { | |
735 throw InvalidProtocolBufferException.invalidUtf8(); | |
736 } | |
737 final int tempPos = pos; | |
738 pos += size; | |
739 return new String(buffer, tempPos, size, UTF_8); | |
740 } | |
741 | |
742 if (size == 0) { | |
743 return ""; | |
744 } | |
745 if (size <= 0) { | |
746 throw InvalidProtocolBufferException.negativeSize(); | |
747 } | |
748 throw InvalidProtocolBufferException.truncatedMessage(); | |
749 } | |
750 | |
751 @Override | |
752 public void readGroup( | |
753 final int fieldNumber, | |
754 final MessageLite.Builder builder, | |
755 final ExtensionRegistryLite extensionRegistry) | |
756 throws IOException { | |
757 if (recursionDepth >= recursionLimit) { | |
758 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
759 } | |
760 ++recursionDepth; | |
761 builder.mergeFrom(this, extensionRegistry); | |
762 checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GR
OUP)); | |
763 --recursionDepth; | |
764 } | |
765 | |
766 | |
767 @Override | |
768 public <T extends MessageLite> T readGroup( | |
769 final int fieldNumber, | |
770 final Parser<T> parser, | |
771 final ExtensionRegistryLite extensionRegistry) | |
772 throws IOException { | |
773 if (recursionDepth >= recursionLimit) { | |
774 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
775 } | |
776 ++recursionDepth; | |
777 T result = parser.parsePartialFrom(this, extensionRegistry); | |
778 checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GR
OUP)); | |
779 --recursionDepth; | |
780 return result; | |
781 } | |
782 | |
783 @Deprecated | |
784 @Override | |
785 public void readUnknownGroup(final int fieldNumber, final MessageLite.Builde
r builder) | |
786 throws IOException { | |
787 readGroup(fieldNumber, builder, ExtensionRegistryLite.getEmptyRegistry()); | |
788 } | |
789 | |
790 @Override | |
791 public void readMessage( | |
792 final MessageLite.Builder builder, final ExtensionRegistryLite extension
Registry) | |
793 throws IOException { | |
794 final int length = readRawVarint32(); | |
795 if (recursionDepth >= recursionLimit) { | |
796 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
797 } | |
798 final int oldLimit = pushLimit(length); | |
799 ++recursionDepth; | |
800 builder.mergeFrom(this, extensionRegistry); | |
801 checkLastTagWas(0); | |
802 --recursionDepth; | |
803 popLimit(oldLimit); | |
804 } | |
805 | |
806 | |
807 @Override | |
808 public <T extends MessageLite> T readMessage( | |
809 final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) t
hrows IOException { | |
810 int length = readRawVarint32(); | |
811 if (recursionDepth >= recursionLimit) { | |
812 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
813 } | |
814 final int oldLimit = pushLimit(length); | |
815 ++recursionDepth; | |
816 T result = parser.parsePartialFrom(this, extensionRegistry); | |
817 checkLastTagWas(0); | |
818 --recursionDepth; | |
819 popLimit(oldLimit); | |
820 return result; | |
821 } | |
822 | |
823 @Override | |
824 public ByteString readBytes() throws IOException { | |
825 final int size = readRawVarint32(); | |
826 if (size > 0 && size <= (limit - pos)) { | |
827 // Fast path: We already have the bytes in a contiguous buffer, so | |
828 // just copy directly from it. | |
829 final ByteString result = | |
830 immutable && enableAliasing | |
831 ? ByteString.wrap(buffer, pos, size) | |
832 : ByteString.copyFrom(buffer, pos, size); | |
833 pos += size; | |
834 return result; | |
835 } | |
836 if (size == 0) { | |
837 return ByteString.EMPTY; | |
838 } | |
839 // Slow path: Build a byte array first then copy it. | |
840 return ByteString.wrap(readRawBytes(size)); | |
841 } | |
842 | |
843 @Override | |
844 public byte[] readByteArray() throws IOException { | |
845 final int size = readRawVarint32(); | |
846 return readRawBytes(size); | |
847 } | |
848 | |
849 @Override | |
850 public ByteBuffer readByteBuffer() throws IOException { | |
851 final int size = readRawVarint32(); | |
852 if (size > 0 && size <= (limit - pos)) { | |
853 // Fast path: We already have the bytes in a contiguous buffer. | |
854 // When aliasing is enabled, we can return a ByteBuffer pointing directl
y | |
855 // into the underlying byte array without copy if the CodedInputStream i
s | |
856 // constructed from a byte array. If aliasing is disabled or the input i
s | |
857 // from an InputStream or ByteString, we have to make a copy of the byte
s. | |
858 ByteBuffer result = | |
859 !immutable && enableAliasing | |
860 ? ByteBuffer.wrap(buffer, pos, size).slice() | |
861 : ByteBuffer.wrap(Arrays.copyOfRange(buffer, pos, pos + size)); | |
862 pos += size; | |
863 // TODO(nathanmittler): Investigate making the ByteBuffer be made read-o
nly | |
864 return result; | |
865 } | |
866 | |
867 if (size == 0) { | |
868 return EMPTY_BYTE_BUFFER; | |
869 } | |
870 if (size < 0) { | |
871 throw InvalidProtocolBufferException.negativeSize(); | |
872 } | |
873 throw InvalidProtocolBufferException.truncatedMessage(); | |
874 } | |
875 | |
876 @Override | |
877 public int readUInt32() throws IOException { | |
878 return readRawVarint32(); | |
879 } | |
880 | |
881 @Override | |
882 public int readEnum() throws IOException { | |
883 return readRawVarint32(); | |
884 } | |
885 | |
886 @Override | |
887 public int readSFixed32() throws IOException { | |
888 return readRawLittleEndian32(); | |
889 } | |
890 | |
891 @Override | |
892 public long readSFixed64() throws IOException { | |
893 return readRawLittleEndian64(); | |
894 } | |
895 | |
896 @Override | |
897 public int readSInt32() throws IOException { | |
898 return decodeZigZag32(readRawVarint32()); | |
899 } | |
900 | |
901 @Override | |
902 public long readSInt64() throws IOException { | |
903 return decodeZigZag64(readRawVarint64()); | |
904 } | |
905 | |
906 // ================================================================= | |
907 | |
908 @Override | |
909 public int readRawVarint32() throws IOException { | |
910 // See implementation notes for readRawVarint64 | |
911 fastpath: | |
912 { | |
913 int tempPos = pos; | |
914 | |
915 if (limit == tempPos) { | |
916 break fastpath; | |
917 } | |
918 | |
919 final byte[] buffer = this.buffer; | |
920 int x; | |
921 if ((x = buffer[tempPos++]) >= 0) { | |
922 pos = tempPos; | |
923 return x; | |
924 } else if (limit - tempPos < 9) { | |
925 break fastpath; | |
926 } else if ((x ^= (buffer[tempPos++] << 7)) < 0) { | |
927 x ^= (~0 << 7); | |
928 } else if ((x ^= (buffer[tempPos++] << 14)) >= 0) { | |
929 x ^= (~0 << 7) ^ (~0 << 14); | |
930 } else if ((x ^= (buffer[tempPos++] << 21)) < 0) { | |
931 x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21); | |
932 } else { | |
933 int y = buffer[tempPos++]; | |
934 x ^= y << 28; | |
935 x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28); | |
936 if (y < 0 | |
937 && buffer[tempPos++] < 0 | |
938 && buffer[tempPos++] < 0 | |
939 && buffer[tempPos++] < 0 | |
940 && buffer[tempPos++] < 0 | |
941 && buffer[tempPos++] < 0) { | |
942 break fastpath; // Will throw malformedVarint() | |
943 } | |
944 } | |
945 pos = tempPos; | |
946 return x; | |
947 } | |
948 return (int) readRawVarint64SlowPath(); | |
949 } | |
950 | |
951 private void skipRawVarint() throws IOException { | |
952 if (limit - pos >= MAX_VARINT_SIZE) { | |
953 skipRawVarintFastPath(); | |
954 } else { | |
955 skipRawVarintSlowPath(); | |
956 } | |
957 } | |
958 | |
959 private void skipRawVarintFastPath() throws IOException { | |
960 for (int i = 0; i < MAX_VARINT_SIZE; i++) { | |
961 if (buffer[pos++] >= 0) { | |
962 return; | |
963 } | |
964 } | |
965 throw InvalidProtocolBufferException.malformedVarint(); | |
966 } | |
967 | |
968 private void skipRawVarintSlowPath() throws IOException { | |
969 for (int i = 0; i < MAX_VARINT_SIZE; i++) { | |
970 if (readRawByte() >= 0) { | |
971 return; | |
972 } | |
973 } | |
974 throw InvalidProtocolBufferException.malformedVarint(); | |
975 } | |
976 | |
977 @Override | |
978 public long readRawVarint64() throws IOException { | |
979 // Implementation notes: | |
980 // | |
981 // Optimized for one-byte values, expected to be common. | |
982 // The particular code below was selected from various candidates | |
983 // empirically, by winning VarintBenchmark. | |
984 // | |
985 // Sign extension of (signed) Java bytes is usually a nuisance, but | |
986 // we exploit it here to more easily obtain the sign of bytes read. | |
987 // Instead of cleaning up the sign extension bits by masking eagerly, | |
988 // we delay until we find the final (positive) byte, when we clear all | |
989 // accumulated bits with one xor. We depend on javac to constant fold. | |
990 fastpath: | |
991 { | |
992 int tempPos = pos; | |
993 | |
994 if (limit == tempPos) { | |
995 break fastpath; | |
996 } | |
997 | |
998 final byte[] buffer = this.buffer; | |
999 long x; | |
1000 int y; | |
1001 if ((y = buffer[tempPos++]) >= 0) { | |
1002 pos = tempPos; | |
1003 return y; | |
1004 } else if (limit - tempPos < 9) { | |
1005 break fastpath; | |
1006 } else if ((y ^= (buffer[tempPos++] << 7)) < 0) { | |
1007 x = y ^ (~0 << 7); | |
1008 } else if ((y ^= (buffer[tempPos++] << 14)) >= 0) { | |
1009 x = y ^ ((~0 << 7) ^ (~0 << 14)); | |
1010 } else if ((y ^= (buffer[tempPos++] << 21)) < 0) { | |
1011 x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21)); | |
1012 } else if ((x = y ^ ((long) buffer[tempPos++] << 28)) >= 0L) { | |
1013 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); | |
1014 } else if ((x ^= ((long) buffer[tempPos++] << 35)) < 0L) { | |
1015 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35
); | |
1016 } else if ((x ^= ((long) buffer[tempPos++] << 42)) >= 0L) { | |
1017 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35
) ^ (~0L << 42); | |
1018 } else if ((x ^= ((long) buffer[tempPos++] << 49)) < 0L) { | |
1019 x ^= | |
1020 (~0L << 7) | |
1021 ^ (~0L << 14) | |
1022 ^ (~0L << 21) | |
1023 ^ (~0L << 28) | |
1024 ^ (~0L << 35) | |
1025 ^ (~0L << 42) | |
1026 ^ (~0L << 49); | |
1027 } else { | |
1028 x ^= ((long) buffer[tempPos++] << 56); | |
1029 x ^= | |
1030 (~0L << 7) | |
1031 ^ (~0L << 14) | |
1032 ^ (~0L << 21) | |
1033 ^ (~0L << 28) | |
1034 ^ (~0L << 35) | |
1035 ^ (~0L << 42) | |
1036 ^ (~0L << 49) | |
1037 ^ (~0L << 56); | |
1038 if (x < 0L) { | |
1039 if (buffer[tempPos++] < 0L) { | |
1040 break fastpath; // Will throw malformedVarint() | |
1041 } | |
1042 } | |
1043 } | |
1044 pos = tempPos; | |
1045 return x; | |
1046 } | |
1047 return readRawVarint64SlowPath(); | |
1048 } | |
1049 | |
1050 @Override | |
1051 long readRawVarint64SlowPath() throws IOException { | |
1052 long result = 0; | |
1053 for (int shift = 0; shift < 64; shift += 7) { | |
1054 final byte b = readRawByte(); | |
1055 result |= (long) (b & 0x7F) << shift; | |
1056 if ((b & 0x80) == 0) { | |
1057 return result; | |
1058 } | |
1059 } | |
1060 throw InvalidProtocolBufferException.malformedVarint(); | |
1061 } | |
1062 | |
1063 @Override | |
1064 public int readRawLittleEndian32() throws IOException { | |
1065 int tempPos = pos; | |
1066 | |
1067 if (limit - tempPos < FIXED_32_SIZE) { | |
1068 throw InvalidProtocolBufferException.truncatedMessage(); | |
1069 } | |
1070 | |
1071 final byte[] buffer = this.buffer; | |
1072 pos = tempPos + FIXED_32_SIZE; | |
1073 return (((buffer[tempPos] & 0xff)) | |
1074 | ((buffer[tempPos + 1] & 0xff) << 8) | |
1075 | ((buffer[tempPos + 2] & 0xff) << 16) | |
1076 | ((buffer[tempPos + 3] & 0xff) << 24)); | |
1077 } | |
1078 | |
1079 @Override | |
1080 public long readRawLittleEndian64() throws IOException { | |
1081 int tempPos = pos; | |
1082 | |
1083 if (limit - tempPos < FIXED_64_SIZE) { | |
1084 throw InvalidProtocolBufferException.truncatedMessage(); | |
1085 } | |
1086 | |
1087 final byte[] buffer = this.buffer; | |
1088 pos = tempPos + FIXED_64_SIZE; | |
1089 return (((buffer[tempPos] & 0xffL)) | |
1090 | ((buffer[tempPos + 1] & 0xffL) << 8) | |
1091 | ((buffer[tempPos + 2] & 0xffL) << 16) | |
1092 | ((buffer[tempPos + 3] & 0xffL) << 24) | |
1093 | ((buffer[tempPos + 4] & 0xffL) << 32) | |
1094 | ((buffer[tempPos + 5] & 0xffL) << 40) | |
1095 | ((buffer[tempPos + 6] & 0xffL) << 48) | |
1096 | ((buffer[tempPos + 7] & 0xffL) << 56)); | |
1097 } | |
1098 | |
1099 @Override | |
1100 public void enableAliasing(boolean enabled) { | |
1101 this.enableAliasing = enabled; | |
1102 } | |
1103 | |
1104 @Override | |
1105 public void resetSizeCounter() { | |
1106 startPos = pos; | |
1107 } | |
1108 | |
1109 @Override | |
1110 public int pushLimit(int byteLimit) throws InvalidProtocolBufferException { | |
1111 if (byteLimit < 0) { | |
1112 throw InvalidProtocolBufferException.negativeSize(); | |
1113 } | |
1114 byteLimit += getTotalBytesRead(); | |
1115 final int oldLimit = currentLimit; | |
1116 if (byteLimit > oldLimit) { | |
1117 throw InvalidProtocolBufferException.truncatedMessage(); | |
1118 } | |
1119 currentLimit = byteLimit; | |
1120 | |
1121 recomputeBufferSizeAfterLimit(); | |
1122 | |
1123 return oldLimit; | |
1124 } | |
1125 | |
1126 private void recomputeBufferSizeAfterLimit() { | |
1127 limit += bufferSizeAfterLimit; | |
1128 final int bufferEnd = limit - startPos; | |
1129 if (bufferEnd > currentLimit) { | |
1130 // Limit is in current buffer. | |
1131 bufferSizeAfterLimit = bufferEnd - currentLimit; | |
1132 limit -= bufferSizeAfterLimit; | |
1133 } else { | |
1134 bufferSizeAfterLimit = 0; | |
1135 } | |
1136 } | |
1137 | |
1138 @Override | |
1139 public void popLimit(final int oldLimit) { | |
1140 currentLimit = oldLimit; | |
1141 recomputeBufferSizeAfterLimit(); | |
1142 } | |
1143 | |
1144 @Override | |
1145 public int getBytesUntilLimit() { | |
1146 if (currentLimit == Integer.MAX_VALUE) { | |
1147 return -1; | |
1148 } | |
1149 | |
1150 return currentLimit - getTotalBytesRead(); | |
1151 } | |
1152 | |
1153 @Override | |
1154 public boolean isAtEnd() throws IOException { | |
1155 return pos == limit; | |
1156 } | |
1157 | |
1158 @Override | |
1159 public int getTotalBytesRead() { | |
1160 return pos - startPos; | |
1161 } | |
1162 | |
1163 @Override | |
1164 public byte readRawByte() throws IOException { | |
1165 if (pos == limit) { | |
1166 throw InvalidProtocolBufferException.truncatedMessage(); | |
1167 } | |
1168 return buffer[pos++]; | |
1169 } | |
1170 | |
1171 @Override | |
1172 public byte[] readRawBytes(final int length) throws IOException { | |
1173 if (length > 0 && length <= (limit - pos)) { | |
1174 final int tempPos = pos; | |
1175 pos += length; | |
1176 return Arrays.copyOfRange(buffer, tempPos, pos); | |
1177 } | |
1178 | |
1179 if (length <= 0) { | |
1180 if (length == 0) { | |
1181 return Internal.EMPTY_BYTE_ARRAY; | |
1182 } else { | |
1183 throw InvalidProtocolBufferException.negativeSize(); | |
1184 } | |
1185 } | |
1186 throw InvalidProtocolBufferException.truncatedMessage(); | |
1187 } | |
1188 | |
1189 @Override | |
1190 public void skipRawBytes(final int length) throws IOException { | |
1191 if (length >= 0 && length <= (limit - pos)) { | |
1192 // We have all the bytes we need already. | |
1193 pos += length; | |
1194 return; | |
1195 } | |
1196 | |
1197 if (length < 0) { | |
1198 throw InvalidProtocolBufferException.negativeSize(); | |
1199 } | |
1200 throw InvalidProtocolBufferException.truncatedMessage(); | |
1201 } | |
1202 } | |
1203 | |
1204 /** | |
1205 * A {@link CodedInputStream} implementation that uses a backing direct ByteBu
ffer as the input. | |
1206 * Requires the use of {@code sun.misc.Unsafe} to perform fast reads on the bu
ffer. | |
1207 */ | |
1208 private static final class UnsafeDirectNioDecoder extends CodedInputStream { | |
1209 /** The direct buffer that is backing this stream. */ | |
1210 private final ByteBuffer buffer; | |
1211 | |
1212 /** | |
1213 * If {@code true}, indicates that the buffer is backing a {@link ByteString
} and is therefore | |
1214 * considered to be an immutable input source. | |
1215 */ | |
1216 private final boolean immutable; | |
1217 | |
1218 /** The unsafe address of the content of {@link #buffer}. */ | |
1219 private final long address; | |
1220 | |
1221 /** The unsafe address of the current read limit of the buffer. */ | |
1222 private long limit; | |
1223 | |
1224 /** The unsafe address of the current read position of the buffer. */ | |
1225 private long pos; | |
1226 | |
1227 /** The unsafe address of the starting read position. */ | |
1228 private long startPos; | |
1229 | |
1230 /** The amount of available data in the buffer beyond {@link #limit}. */ | |
1231 private int bufferSizeAfterLimit; | |
1232 | |
1233 /** The last tag that was read from this stream. */ | |
1234 private int lastTag; | |
1235 | |
1236 /** | |
1237 * If {@code true}, indicates that calls to read {@link ByteString} or {@cod
e byte[]} | |
1238 * <strong>may</strong> return slices of the underlying buffer, rather than
copies. | |
1239 */ | |
1240 private boolean enableAliasing; | |
1241 | |
1242 /** The absolute position of the end of the current message. */ | |
1243 private int currentLimit = Integer.MAX_VALUE; | |
1244 | |
1245 static boolean isSupported() { | |
1246 return UnsafeUtil.hasUnsafeByteBufferOperations(); | |
1247 } | |
1248 | |
1249 private UnsafeDirectNioDecoder(ByteBuffer buffer, boolean immutable) { | |
1250 this.buffer = buffer; | |
1251 address = UnsafeUtil.addressOffset(buffer); | |
1252 limit = address + buffer.limit(); | |
1253 pos = address + buffer.position(); | |
1254 startPos = pos; | |
1255 this.immutable = immutable; | |
1256 } | |
1257 | |
1258 @Override | |
1259 public int readTag() throws IOException { | |
1260 if (isAtEnd()) { | |
1261 lastTag = 0; | |
1262 return 0; | |
1263 } | |
1264 | |
1265 lastTag = readRawVarint32(); | |
1266 if (WireFormat.getTagFieldNumber(lastTag) == 0) { | |
1267 // If we actually read zero (or any tag number corresponding to field | |
1268 // number zero), that's not a valid tag. | |
1269 throw InvalidProtocolBufferException.invalidTag(); | |
1270 } | |
1271 return lastTag; | |
1272 } | |
1273 | |
1274 @Override | |
1275 public void checkLastTagWas(final int value) throws InvalidProtocolBufferExc
eption { | |
1276 if (lastTag != value) { | |
1277 throw InvalidProtocolBufferException.invalidEndTag(); | |
1278 } | |
1279 } | |
1280 | |
1281 @Override | |
1282 public int getLastTag() { | |
1283 return lastTag; | |
1284 } | |
1285 | |
1286 @Override | |
1287 public boolean skipField(final int tag) throws IOException { | |
1288 switch (WireFormat.getTagWireType(tag)) { | |
1289 case WireFormat.WIRETYPE_VARINT: | |
1290 skipRawVarint(); | |
1291 return true; | |
1292 case WireFormat.WIRETYPE_FIXED64: | |
1293 skipRawBytes(FIXED_64_SIZE); | |
1294 return true; | |
1295 case WireFormat.WIRETYPE_LENGTH_DELIMITED: | |
1296 skipRawBytes(readRawVarint32()); | |
1297 return true; | |
1298 case WireFormat.WIRETYPE_START_GROUP: | |
1299 skipMessage(); | |
1300 checkLastTagWas( | |
1301 WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WireFormat.W
IRETYPE_END_GROUP)); | |
1302 return true; | |
1303 case WireFormat.WIRETYPE_END_GROUP: | |
1304 return false; | |
1305 case WireFormat.WIRETYPE_FIXED32: | |
1306 skipRawBytes(FIXED_32_SIZE); | |
1307 return true; | |
1308 default: | |
1309 throw InvalidProtocolBufferException.invalidWireType(); | |
1310 } | |
1311 } | |
1312 | |
1313 @Override | |
1314 public boolean skipField(final int tag, final CodedOutputStream output) thro
ws IOException { | |
1315 switch (WireFormat.getTagWireType(tag)) { | |
1316 case WireFormat.WIRETYPE_VARINT: | |
1317 { | |
1318 long value = readInt64(); | |
1319 output.writeRawVarint32(tag); | |
1320 output.writeUInt64NoTag(value); | |
1321 return true; | |
1322 } | |
1323 case WireFormat.WIRETYPE_FIXED64: | |
1324 { | |
1325 long value = readRawLittleEndian64(); | |
1326 output.writeRawVarint32(tag); | |
1327 output.writeFixed64NoTag(value); | |
1328 return true; | |
1329 } | |
1330 case WireFormat.WIRETYPE_LENGTH_DELIMITED: | |
1331 { | |
1332 ByteString value = readBytes(); | |
1333 output.writeRawVarint32(tag); | |
1334 output.writeBytesNoTag(value); | |
1335 return true; | |
1336 } | |
1337 case WireFormat.WIRETYPE_START_GROUP: | |
1338 { | |
1339 output.writeRawVarint32(tag); | |
1340 skipMessage(output); | |
1341 int endtag = | |
1342 WireFormat.makeTag( | |
1343 WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_G
ROUP); | |
1344 checkLastTagWas(endtag); | |
1345 output.writeRawVarint32(endtag); | |
1346 return true; | |
1347 } | |
1348 case WireFormat.WIRETYPE_END_GROUP: | |
1349 { | |
1350 return false; | |
1351 } | |
1352 case WireFormat.WIRETYPE_FIXED32: | |
1353 { | |
1354 int value = readRawLittleEndian32(); | |
1355 output.writeRawVarint32(tag); | |
1356 output.writeFixed32NoTag(value); | |
1357 return true; | |
1358 } | |
1359 default: | |
1360 throw InvalidProtocolBufferException.invalidWireType(); | |
1361 } | |
1362 } | |
1363 | |
1364 @Override | |
1365 public void skipMessage() throws IOException { | |
1366 while (true) { | |
1367 final int tag = readTag(); | |
1368 if (tag == 0 || !skipField(tag)) { | |
1369 return; | |
1370 } | |
1371 } | |
1372 } | |
1373 | |
1374 @Override | |
1375 public void skipMessage(CodedOutputStream output) throws IOException { | |
1376 while (true) { | |
1377 final int tag = readTag(); | |
1378 if (tag == 0 || !skipField(tag, output)) { | |
1379 return; | |
1380 } | |
1381 } | |
1382 } | |
1383 | |
1384 | |
1385 // ----------------------------------------------------------------- | |
1386 | |
1387 @Override | |
1388 public double readDouble() throws IOException { | |
1389 return Double.longBitsToDouble(readRawLittleEndian64()); | |
1390 } | |
1391 | |
1392 @Override | |
1393 public float readFloat() throws IOException { | |
1394 return Float.intBitsToFloat(readRawLittleEndian32()); | |
1395 } | |
1396 | |
1397 @Override | |
1398 public long readUInt64() throws IOException { | |
1399 return readRawVarint64(); | |
1400 } | |
1401 | |
1402 @Override | |
1403 public long readInt64() throws IOException { | |
1404 return readRawVarint64(); | |
1405 } | |
1406 | |
1407 @Override | |
1408 public int readInt32() throws IOException { | |
1409 return readRawVarint32(); | |
1410 } | |
1411 | |
1412 @Override | |
1413 public long readFixed64() throws IOException { | |
1414 return readRawLittleEndian64(); | |
1415 } | |
1416 | |
1417 @Override | |
1418 public int readFixed32() throws IOException { | |
1419 return readRawLittleEndian32(); | |
1420 } | |
1421 | |
1422 @Override | |
1423 public boolean readBool() throws IOException { | |
1424 return readRawVarint64() != 0; | |
1425 } | |
1426 | |
1427 @Override | |
1428 public String readString() throws IOException { | |
1429 final int size = readRawVarint32(); | |
1430 if (size > 0 && size <= remaining()) { | |
1431 // TODO(nathanmittler): Is there a way to avoid this copy? | |
1432 byte[] bytes = copyToArray(pos, pos + size); | |
1433 String result = new String(bytes, UTF_8); | |
1434 pos += size; | |
1435 return result; | |
1436 } | |
1437 | |
1438 if (size == 0) { | |
1439 return ""; | |
1440 } | |
1441 if (size < 0) { | |
1442 throw InvalidProtocolBufferException.negativeSize(); | |
1443 } | |
1444 throw InvalidProtocolBufferException.truncatedMessage(); | |
1445 } | |
1446 | |
1447 @Override | |
1448 public String readStringRequireUtf8() throws IOException { | |
1449 final int size = readRawVarint32(); | |
1450 if (size >= 0 && size <= remaining()) { | |
1451 // TODO(nathanmittler): Is there a way to avoid this copy? | |
1452 byte[] bytes = copyToArray(pos, pos + size); | |
1453 // TODO(martinrb): We could save a pass by validating while decoding. | |
1454 if (!Utf8.isValidUtf8(bytes)) { | |
1455 throw InvalidProtocolBufferException.invalidUtf8(); | |
1456 } | |
1457 | |
1458 String result = new String(bytes, UTF_8); | |
1459 pos += size; | |
1460 return result; | |
1461 } | |
1462 | |
1463 if (size == 0) { | |
1464 return ""; | |
1465 } | |
1466 if (size <= 0) { | |
1467 throw InvalidProtocolBufferException.negativeSize(); | |
1468 } | |
1469 throw InvalidProtocolBufferException.truncatedMessage(); | |
1470 } | |
1471 | |
1472 @Override | |
1473 public void readGroup( | |
1474 final int fieldNumber, | |
1475 final MessageLite.Builder builder, | |
1476 final ExtensionRegistryLite extensionRegistry) | |
1477 throws IOException { | |
1478 if (recursionDepth >= recursionLimit) { | |
1479 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
1480 } | |
1481 ++recursionDepth; | |
1482 builder.mergeFrom(this, extensionRegistry); | |
1483 checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GR
OUP)); | |
1484 --recursionDepth; | |
1485 } | |
1486 | |
1487 | |
1488 @Override | |
1489 public <T extends MessageLite> T readGroup( | |
1490 final int fieldNumber, | |
1491 final Parser<T> parser, | |
1492 final ExtensionRegistryLite extensionRegistry) | |
1493 throws IOException { | |
1494 if (recursionDepth >= recursionLimit) { | |
1495 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
1496 } | |
1497 ++recursionDepth; | |
1498 T result = parser.parsePartialFrom(this, extensionRegistry); | |
1499 checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GR
OUP)); | |
1500 --recursionDepth; | |
1501 return result; | |
1502 } | |
1503 | |
1504 @Deprecated | |
1505 @Override | |
1506 public void readUnknownGroup(final int fieldNumber, final MessageLite.Builde
r builder) | |
1507 throws IOException { | |
1508 readGroup(fieldNumber, builder, ExtensionRegistryLite.getEmptyRegistry()); | |
1509 } | |
1510 | |
1511 @Override | |
1512 public void readMessage( | |
1513 final MessageLite.Builder builder, final ExtensionRegistryLite extension
Registry) | |
1514 throws IOException { | |
1515 final int length = readRawVarint32(); | |
1516 if (recursionDepth >= recursionLimit) { | |
1517 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
1518 } | |
1519 final int oldLimit = pushLimit(length); | |
1520 ++recursionDepth; | |
1521 builder.mergeFrom(this, extensionRegistry); | |
1522 checkLastTagWas(0); | |
1523 --recursionDepth; | |
1524 popLimit(oldLimit); | |
1525 } | |
1526 | |
1527 | |
1528 @Override | |
1529 public <T extends MessageLite> T readMessage( | |
1530 final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) t
hrows IOException { | |
1531 int length = readRawVarint32(); | |
1532 if (recursionDepth >= recursionLimit) { | |
1533 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
1534 } | |
1535 final int oldLimit = pushLimit(length); | |
1536 ++recursionDepth; | |
1537 T result = parser.parsePartialFrom(this, extensionRegistry); | |
1538 checkLastTagWas(0); | |
1539 --recursionDepth; | |
1540 popLimit(oldLimit); | |
1541 return result; | |
1542 } | |
1543 | |
1544 @Override | |
1545 public ByteString readBytes() throws IOException { | |
1546 final int size = readRawVarint32(); | |
1547 if (size > 0 && size <= remaining()) { | |
1548 ByteBuffer result; | |
1549 if (immutable && enableAliasing) { | |
1550 result = slice(pos, pos + size); | |
1551 } else { | |
1552 result = copy(pos, pos + size); | |
1553 } | |
1554 pos += size; | |
1555 return ByteString.wrap(result); | |
1556 } | |
1557 | |
1558 if (size == 0) { | |
1559 return ByteString.EMPTY; | |
1560 } | |
1561 if (size < 0) { | |
1562 throw InvalidProtocolBufferException.negativeSize(); | |
1563 } | |
1564 throw InvalidProtocolBufferException.truncatedMessage(); | |
1565 } | |
1566 | |
1567 @Override | |
1568 public byte[] readByteArray() throws IOException { | |
1569 return readRawBytes(readRawVarint32()); | |
1570 } | |
1571 | |
1572 @Override | |
1573 public ByteBuffer readByteBuffer() throws IOException { | |
1574 final int size = readRawVarint32(); | |
1575 if (size > 0 && size <= remaining()) { | |
1576 ByteBuffer result; | |
1577 // "Immutable" implies that buffer is backing a ByteString. | |
1578 // Disallow slicing in this case to prevent the caller from modifying th
e contents | |
1579 // of the ByteString. | |
1580 if (!immutable && enableAliasing) { | |
1581 result = slice(pos, pos + size); | |
1582 } else { | |
1583 result = copy(pos, pos + size); | |
1584 } | |
1585 pos += size; | |
1586 // TODO(nathanmittler): Investigate making the ByteBuffer be made read-o
nly | |
1587 return result; | |
1588 } | |
1589 | |
1590 if (size == 0) { | |
1591 return EMPTY_BYTE_BUFFER; | |
1592 } | |
1593 if (size < 0) { | |
1594 throw InvalidProtocolBufferException.negativeSize(); | |
1595 } | |
1596 throw InvalidProtocolBufferException.truncatedMessage(); | |
1597 } | |
1598 | |
1599 @Override | |
1600 public int readUInt32() throws IOException { | |
1601 return readRawVarint32(); | |
1602 } | |
1603 | |
1604 @Override | |
1605 public int readEnum() throws IOException { | |
1606 return readRawVarint32(); | |
1607 } | |
1608 | |
1609 @Override | |
1610 public int readSFixed32() throws IOException { | |
1611 return readRawLittleEndian32(); | |
1612 } | |
1613 | |
1614 @Override | |
1615 public long readSFixed64() throws IOException { | |
1616 return readRawLittleEndian64(); | |
1617 } | |
1618 | |
1619 @Override | |
1620 public int readSInt32() throws IOException { | |
1621 return decodeZigZag32(readRawVarint32()); | |
1622 } | |
1623 | |
1624 @Override | |
1625 public long readSInt64() throws IOException { | |
1626 return decodeZigZag64(readRawVarint64()); | |
1627 } | |
1628 | |
1629 // ================================================================= | |
1630 | |
1631 @Override | |
1632 public int readRawVarint32() throws IOException { | |
1633 // See implementation notes for readRawVarint64 | |
1634 fastpath: | |
1635 { | |
1636 long tempPos = pos; | |
1637 | |
1638 if (limit == tempPos) { | |
1639 break fastpath; | |
1640 } | |
1641 | |
1642 int x; | |
1643 if ((x = UnsafeUtil.getByte(tempPos++)) >= 0) { | |
1644 pos = tempPos; | |
1645 return x; | |
1646 } else if (limit - tempPos < 9) { | |
1647 break fastpath; | |
1648 } else if ((x ^= (UnsafeUtil.getByte(tempPos++) << 7)) < 0) { | |
1649 x ^= (~0 << 7); | |
1650 } else if ((x ^= (UnsafeUtil.getByte(tempPos++) << 14)) >= 0) { | |
1651 x ^= (~0 << 7) ^ (~0 << 14); | |
1652 } else if ((x ^= (UnsafeUtil.getByte(tempPos++) << 21)) < 0) { | |
1653 x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21); | |
1654 } else { | |
1655 int y = UnsafeUtil.getByte(tempPos++); | |
1656 x ^= y << 28; | |
1657 x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28); | |
1658 if (y < 0 | |
1659 && UnsafeUtil.getByte(tempPos++) < 0 | |
1660 && UnsafeUtil.getByte(tempPos++) < 0 | |
1661 && UnsafeUtil.getByte(tempPos++) < 0 | |
1662 && UnsafeUtil.getByte(tempPos++) < 0 | |
1663 && UnsafeUtil.getByte(tempPos++) < 0) { | |
1664 break fastpath; // Will throw malformedVarint() | |
1665 } | |
1666 } | |
1667 pos = tempPos; | |
1668 return x; | |
1669 } | |
1670 return (int) readRawVarint64SlowPath(); | |
1671 } | |
1672 | |
1673 private void skipRawVarint() throws IOException { | |
1674 if (remaining() >= MAX_VARINT_SIZE) { | |
1675 skipRawVarintFastPath(); | |
1676 } else { | |
1677 skipRawVarintSlowPath(); | |
1678 } | |
1679 } | |
1680 | |
1681 private void skipRawVarintFastPath() throws IOException { | |
1682 for (int i = 0; i < MAX_VARINT_SIZE; i++) { | |
1683 if (UnsafeUtil.getByte(pos++) >= 0) { | |
1684 return; | |
1685 } | |
1686 } | |
1687 throw InvalidProtocolBufferException.malformedVarint(); | |
1688 } | |
1689 | |
1690 private void skipRawVarintSlowPath() throws IOException { | |
1691 for (int i = 0; i < MAX_VARINT_SIZE; i++) { | |
1692 if (readRawByte() >= 0) { | |
1693 return; | |
1694 } | |
1695 } | |
1696 throw InvalidProtocolBufferException.malformedVarint(); | |
1697 } | |
1698 | |
1699 @Override | |
1700 public long readRawVarint64() throws IOException { | |
1701 // Implementation notes: | |
1702 // | |
1703 // Optimized for one-byte values, expected to be common. | |
1704 // The particular code below was selected from various candidates | |
1705 // empirically, by winning VarintBenchmark. | |
1706 // | |
1707 // Sign extension of (signed) Java bytes is usually a nuisance, but | |
1708 // we exploit it here to more easily obtain the sign of bytes read. | |
1709 // Instead of cleaning up the sign extension bits by masking eagerly, | |
1710 // we delay until we find the final (positive) byte, when we clear all | |
1711 // accumulated bits with one xor. We depend on javac to constant fold. | |
1712 fastpath: | |
1713 { | |
1714 long tempPos = pos; | |
1715 | |
1716 if (limit == tempPos) { | |
1717 break fastpath; | |
1718 } | |
1719 | |
1720 long x; | |
1721 int y; | |
1722 if ((y = UnsafeUtil.getByte(tempPos++)) >= 0) { | |
1723 pos = tempPos; | |
1724 return y; | |
1725 } else if (limit - tempPos < 9) { | |
1726 break fastpath; | |
1727 } else if ((y ^= (UnsafeUtil.getByte(tempPos++) << 7)) < 0) { | |
1728 x = y ^ (~0 << 7); | |
1729 } else if ((y ^= (UnsafeUtil.getByte(tempPos++) << 14)) >= 0) { | |
1730 x = y ^ ((~0 << 7) ^ (~0 << 14)); | |
1731 } else if ((y ^= (UnsafeUtil.getByte(tempPos++) << 21)) < 0) { | |
1732 x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21)); | |
1733 } else if ((x = y ^ ((long) UnsafeUtil.getByte(tempPos++) << 28)) >= 0L)
{ | |
1734 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); | |
1735 } else if ((x ^= ((long) UnsafeUtil.getByte(tempPos++) << 35)) < 0L) { | |
1736 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35
); | |
1737 } else if ((x ^= ((long) UnsafeUtil.getByte(tempPos++) << 42)) >= 0L) { | |
1738 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35
) ^ (~0L << 42); | |
1739 } else if ((x ^= ((long) UnsafeUtil.getByte(tempPos++) << 49)) < 0L) { | |
1740 x ^= | |
1741 (~0L << 7) | |
1742 ^ (~0L << 14) | |
1743 ^ (~0L << 21) | |
1744 ^ (~0L << 28) | |
1745 ^ (~0L << 35) | |
1746 ^ (~0L << 42) | |
1747 ^ (~0L << 49); | |
1748 } else { | |
1749 x ^= ((long) UnsafeUtil.getByte(tempPos++) << 56); | |
1750 x ^= | |
1751 (~0L << 7) | |
1752 ^ (~0L << 14) | |
1753 ^ (~0L << 21) | |
1754 ^ (~0L << 28) | |
1755 ^ (~0L << 35) | |
1756 ^ (~0L << 42) | |
1757 ^ (~0L << 49) | |
1758 ^ (~0L << 56); | |
1759 if (x < 0L) { | |
1760 if (UnsafeUtil.getByte(tempPos++) < 0L) { | |
1761 break fastpath; // Will throw malformedVarint() | |
1762 } | |
1763 } | |
1764 } | |
1765 pos = tempPos; | |
1766 return x; | |
1767 } | |
1768 return readRawVarint64SlowPath(); | |
1769 } | |
1770 | |
1771 @Override | |
1772 long readRawVarint64SlowPath() throws IOException { | |
1773 long result = 0; | |
1774 for (int shift = 0; shift < 64; shift += 7) { | |
1775 final byte b = readRawByte(); | |
1776 result |= (long) (b & 0x7F) << shift; | |
1777 if ((b & 0x80) == 0) { | |
1778 return result; | |
1779 } | |
1780 } | |
1781 throw InvalidProtocolBufferException.malformedVarint(); | |
1782 } | |
1783 | |
1784 @Override | |
1785 public int readRawLittleEndian32() throws IOException { | |
1786 long tempPos = pos; | |
1787 | |
1788 if (limit - tempPos < FIXED_32_SIZE) { | |
1789 throw InvalidProtocolBufferException.truncatedMessage(); | |
1790 } | |
1791 | |
1792 pos = tempPos + FIXED_32_SIZE; | |
1793 return (((UnsafeUtil.getByte(tempPos) & 0xff)) | |
1794 | ((UnsafeUtil.getByte(tempPos + 1) & 0xff) << 8) | |
1795 | ((UnsafeUtil.getByte(tempPos + 2) & 0xff) << 16) | |
1796 | ((UnsafeUtil.getByte(tempPos + 3) & 0xff) << 24)); | |
1797 } | |
1798 | |
1799 @Override | |
1800 public long readRawLittleEndian64() throws IOException { | |
1801 long tempPos = pos; | |
1802 | |
1803 if (limit - tempPos < FIXED_64_SIZE) { | |
1804 throw InvalidProtocolBufferException.truncatedMessage(); | |
1805 } | |
1806 | |
1807 pos = tempPos + FIXED_64_SIZE; | |
1808 return (((UnsafeUtil.getByte(tempPos) & 0xffL)) | |
1809 | ((UnsafeUtil.getByte(tempPos + 1) & 0xffL) << 8) | |
1810 | ((UnsafeUtil.getByte(tempPos + 2) & 0xffL) << 16) | |
1811 | ((UnsafeUtil.getByte(tempPos + 3) & 0xffL) << 24) | |
1812 | ((UnsafeUtil.getByte(tempPos + 4) & 0xffL) << 32) | |
1813 | ((UnsafeUtil.getByte(tempPos + 5) & 0xffL) << 40) | |
1814 | ((UnsafeUtil.getByte(tempPos + 6) & 0xffL) << 48) | |
1815 | ((UnsafeUtil.getByte(tempPos + 7) & 0xffL) << 56)); | |
1816 } | |
1817 | |
1818 @Override | |
1819 public void enableAliasing(boolean enabled) { | |
1820 this.enableAliasing = enabled; | |
1821 } | |
1822 | |
1823 @Override | |
1824 public void resetSizeCounter() { | |
1825 startPos = pos; | |
1826 } | |
1827 | |
1828 @Override | |
1829 public int pushLimit(int byteLimit) throws InvalidProtocolBufferException { | |
1830 if (byteLimit < 0) { | |
1831 throw InvalidProtocolBufferException.negativeSize(); | |
1832 } | |
1833 byteLimit += getTotalBytesRead(); | |
1834 final int oldLimit = currentLimit; | |
1835 if (byteLimit > oldLimit) { | |
1836 throw InvalidProtocolBufferException.truncatedMessage(); | |
1837 } | |
1838 currentLimit = byteLimit; | |
1839 | |
1840 recomputeBufferSizeAfterLimit(); | |
1841 | |
1842 return oldLimit; | |
1843 } | |
1844 | |
1845 @Override | |
1846 public void popLimit(final int oldLimit) { | |
1847 currentLimit = oldLimit; | |
1848 recomputeBufferSizeAfterLimit(); | |
1849 } | |
1850 | |
1851 @Override | |
1852 public int getBytesUntilLimit() { | |
1853 if (currentLimit == Integer.MAX_VALUE) { | |
1854 return -1; | |
1855 } | |
1856 | |
1857 return currentLimit - getTotalBytesRead(); | |
1858 } | |
1859 | |
1860 @Override | |
1861 public boolean isAtEnd() throws IOException { | |
1862 return pos == limit; | |
1863 } | |
1864 | |
1865 @Override | |
1866 public int getTotalBytesRead() { | |
1867 return (int) (pos - startPos); | |
1868 } | |
1869 | |
1870 @Override | |
1871 public byte readRawByte() throws IOException { | |
1872 if (pos == limit) { | |
1873 throw InvalidProtocolBufferException.truncatedMessage(); | |
1874 } | |
1875 return UnsafeUtil.getByte(pos++); | |
1876 } | |
1877 | |
1878 @Override | |
1879 public byte[] readRawBytes(final int length) throws IOException { | |
1880 if (length >= 0 && length <= remaining()) { | |
1881 byte[] bytes = new byte[length]; | |
1882 slice(pos, pos + length).get(bytes); | |
1883 pos += length; | |
1884 return bytes; | |
1885 } | |
1886 | |
1887 if (length <= 0) { | |
1888 if (length == 0) { | |
1889 return EMPTY_BYTE_ARRAY; | |
1890 } else { | |
1891 throw InvalidProtocolBufferException.negativeSize(); | |
1892 } | |
1893 } | |
1894 | |
1895 throw InvalidProtocolBufferException.truncatedMessage(); | |
1896 } | |
1897 | |
1898 @Override | |
1899 public void skipRawBytes(final int length) throws IOException { | |
1900 if (length >= 0 && length <= remaining()) { | |
1901 // We have all the bytes we need already. | |
1902 pos += length; | |
1903 return; | |
1904 } | |
1905 | |
1906 if (length < 0) { | |
1907 throw InvalidProtocolBufferException.negativeSize(); | |
1908 } | |
1909 throw InvalidProtocolBufferException.truncatedMessage(); | |
1910 } | |
1911 | |
1912 private void recomputeBufferSizeAfterLimit() { | |
1913 limit += bufferSizeAfterLimit; | |
1914 final int bufferEnd = (int) (limit - startPos); | |
1915 if (bufferEnd > currentLimit) { | |
1916 // Limit is in current buffer. | |
1917 bufferSizeAfterLimit = bufferEnd - currentLimit; | |
1918 limit -= bufferSizeAfterLimit; | |
1919 } else { | |
1920 bufferSizeAfterLimit = 0; | |
1921 } | |
1922 } | |
1923 | |
1924 private int remaining() { | |
1925 return (int) (limit - pos); | |
1926 } | |
1927 | |
1928 private int bufferPos(long pos) { | |
1929 return (int) (pos - address); | |
1930 } | |
1931 | |
1932 private ByteBuffer slice(long begin, long end) throws IOException { | |
1933 int prevPos = buffer.position(); | |
1934 int prevLimit = buffer.limit(); | |
1935 try { | |
1936 buffer.position(bufferPos(begin)); | |
1937 buffer.limit(bufferPos(end)); | |
1938 return buffer.slice(); | |
1939 } catch (IllegalArgumentException e) { | |
1940 throw InvalidProtocolBufferException.truncatedMessage(); | |
1941 } finally { | |
1942 buffer.position(prevPos); | |
1943 buffer.limit(prevLimit); | |
1944 } | |
1945 } | |
1946 | |
1947 private ByteBuffer copy(long begin, long end) throws IOException { | |
1948 return ByteBuffer.wrap(copyToArray(begin, end)); | |
1949 } | |
1950 | |
1951 private byte[] copyToArray(long begin, long end) throws IOException { | |
1952 int prevPos = buffer.position(); | |
1953 int prevLimit = buffer.limit(); | |
1954 try { | |
1955 buffer.position(bufferPos(begin)); | |
1956 buffer.limit(bufferPos(end)); | |
1957 byte[] bytes = new byte[(int) (end - begin)]; | |
1958 buffer.get(bytes); | |
1959 return bytes; | |
1960 } catch (IllegalArgumentException e) { | |
1961 throw InvalidProtocolBufferException.truncatedMessage(); | |
1962 } finally { | |
1963 buffer.position(prevPos); | |
1964 buffer.limit(prevLimit); | |
1965 } | |
1966 } | |
1967 } | |
1968 | |
1969 /** | |
1970 * Implementation of {@link CodedInputStream} that uses an {@link InputStream}
as the data source. | |
1971 */ | |
1972 private static final class StreamDecoder extends CodedInputStream { | |
1973 private final InputStream input; | |
1974 private final byte[] buffer; | |
1975 /** bufferSize represents how many bytes are currently filled in the buffer
*/ | |
1976 private int bufferSize; | |
1977 | |
1978 private int bufferSizeAfterLimit; | |
1979 private int pos; | |
1980 private int lastTag; | |
1981 | |
1982 /** | |
1983 * The total number of bytes read before the current buffer. The total bytes
read up to the | |
1984 * current position can be computed as {@code totalBytesRetired + pos}. This
value may be | |
1985 * negative if reading started in the middle of the current buffer (e.g. if
the constructor that | |
1986 * takes a byte array and an offset was used). | |
1987 */ | |
1988 private int totalBytesRetired; | |
1989 | |
1990 /** The absolute position of the end of the current message. */ | |
1991 private int currentLimit = Integer.MAX_VALUE; | |
1992 | |
1993 private StreamDecoder(final InputStream input, int bufferSize) { | |
1994 checkNotNull(input, "input"); | |
1995 this.input = input; | |
1996 this.buffer = new byte[bufferSize]; | |
1997 this.bufferSize = 0; | |
1998 pos = 0; | |
1999 totalBytesRetired = 0; | |
2000 } | |
2001 | |
2002 @Override | |
2003 public int readTag() throws IOException { | |
2004 if (isAtEnd()) { | |
2005 lastTag = 0; | |
2006 return 0; | |
2007 } | |
2008 | |
2009 lastTag = readRawVarint32(); | |
2010 if (WireFormat.getTagFieldNumber(lastTag) == 0) { | |
2011 // If we actually read zero (or any tag number corresponding to field | |
2012 // number zero), that's not a valid tag. | |
2013 throw InvalidProtocolBufferException.invalidTag(); | |
2014 } | |
2015 return lastTag; | |
2016 } | |
2017 | |
2018 @Override | |
2019 public void checkLastTagWas(final int value) throws InvalidProtocolBufferExc
eption { | |
2020 if (lastTag != value) { | |
2021 throw InvalidProtocolBufferException.invalidEndTag(); | |
2022 } | |
2023 } | |
2024 | |
2025 @Override | |
2026 public int getLastTag() { | |
2027 return lastTag; | |
2028 } | |
2029 | |
2030 @Override | |
2031 public boolean skipField(final int tag) throws IOException { | |
2032 switch (WireFormat.getTagWireType(tag)) { | |
2033 case WireFormat.WIRETYPE_VARINT: | |
2034 skipRawVarint(); | |
2035 return true; | |
2036 case WireFormat.WIRETYPE_FIXED64: | |
2037 skipRawBytes(FIXED_64_SIZE); | |
2038 return true; | |
2039 case WireFormat.WIRETYPE_LENGTH_DELIMITED: | |
2040 skipRawBytes(readRawVarint32()); | |
2041 return true; | |
2042 case WireFormat.WIRETYPE_START_GROUP: | |
2043 skipMessage(); | |
2044 checkLastTagWas( | |
2045 WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WireFormat.W
IRETYPE_END_GROUP)); | |
2046 return true; | |
2047 case WireFormat.WIRETYPE_END_GROUP: | |
2048 return false; | |
2049 case WireFormat.WIRETYPE_FIXED32: | |
2050 skipRawBytes(FIXED_32_SIZE); | |
2051 return true; | |
2052 default: | |
2053 throw InvalidProtocolBufferException.invalidWireType(); | |
2054 } | |
2055 } | |
2056 | |
2057 @Override | |
2058 public boolean skipField(final int tag, final CodedOutputStream output) thro
ws IOException { | |
2059 switch (WireFormat.getTagWireType(tag)) { | |
2060 case WireFormat.WIRETYPE_VARINT: | |
2061 { | |
2062 long value = readInt64(); | |
2063 output.writeRawVarint32(tag); | |
2064 output.writeUInt64NoTag(value); | |
2065 return true; | |
2066 } | |
2067 case WireFormat.WIRETYPE_FIXED64: | |
2068 { | |
2069 long value = readRawLittleEndian64(); | |
2070 output.writeRawVarint32(tag); | |
2071 output.writeFixed64NoTag(value); | |
2072 return true; | |
2073 } | |
2074 case WireFormat.WIRETYPE_LENGTH_DELIMITED: | |
2075 { | |
2076 ByteString value = readBytes(); | |
2077 output.writeRawVarint32(tag); | |
2078 output.writeBytesNoTag(value); | |
2079 return true; | |
2080 } | |
2081 case WireFormat.WIRETYPE_START_GROUP: | |
2082 { | |
2083 output.writeRawVarint32(tag); | |
2084 skipMessage(output); | |
2085 int endtag = | |
2086 WireFormat.makeTag( | |
2087 WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_G
ROUP); | |
2088 checkLastTagWas(endtag); | |
2089 output.writeRawVarint32(endtag); | |
2090 return true; | |
2091 } | |
2092 case WireFormat.WIRETYPE_END_GROUP: | |
2093 { | |
2094 return false; | |
2095 } | |
2096 case WireFormat.WIRETYPE_FIXED32: | |
2097 { | |
2098 int value = readRawLittleEndian32(); | |
2099 output.writeRawVarint32(tag); | |
2100 output.writeFixed32NoTag(value); | |
2101 return true; | |
2102 } | |
2103 default: | |
2104 throw InvalidProtocolBufferException.invalidWireType(); | |
2105 } | |
2106 } | |
2107 | |
2108 @Override | |
2109 public void skipMessage() throws IOException { | |
2110 while (true) { | |
2111 final int tag = readTag(); | |
2112 if (tag == 0 || !skipField(tag)) { | |
2113 return; | |
2114 } | |
2115 } | |
2116 } | |
2117 | |
2118 @Override | |
2119 public void skipMessage(CodedOutputStream output) throws IOException { | |
2120 while (true) { | |
2121 final int tag = readTag(); | |
2122 if (tag == 0 || !skipField(tag, output)) { | |
2123 return; | |
2124 } | |
2125 } | |
2126 } | |
2127 | |
2128 /** Collects the bytes skipped and returns the data in a ByteBuffer. */ | |
2129 private class SkippedDataSink implements RefillCallback { | |
2130 private int lastPos = pos; | |
2131 private ByteArrayOutputStream byteArrayStream; | |
2132 | |
2133 @Override | |
2134 public void onRefill() { | |
2135 if (byteArrayStream == null) { | |
2136 byteArrayStream = new ByteArrayOutputStream(); | |
2137 } | |
2138 byteArrayStream.write(buffer, lastPos, pos - lastPos); | |
2139 lastPos = 0; | |
2140 } | |
2141 | |
2142 /** Gets skipped data in a ByteBuffer. This method should only be called o
nce. */ | |
2143 ByteBuffer getSkippedData() { | |
2144 if (byteArrayStream == null) { | |
2145 return ByteBuffer.wrap(buffer, lastPos, pos - lastPos); | |
2146 } else { | |
2147 byteArrayStream.write(buffer, lastPos, pos); | |
2148 return ByteBuffer.wrap(byteArrayStream.toByteArray()); | |
2149 } | |
2150 } | |
2151 } | |
2152 | |
2153 | |
2154 // ----------------------------------------------------------------- | |
2155 | |
2156 @Override | |
2157 public double readDouble() throws IOException { | |
2158 return Double.longBitsToDouble(readRawLittleEndian64()); | |
2159 } | |
2160 | |
2161 @Override | |
2162 public float readFloat() throws IOException { | |
2163 return Float.intBitsToFloat(readRawLittleEndian32()); | |
2164 } | |
2165 | |
2166 @Override | |
2167 public long readUInt64() throws IOException { | |
2168 return readRawVarint64(); | |
2169 } | |
2170 | |
2171 @Override | |
2172 public long readInt64() throws IOException { | |
2173 return readRawVarint64(); | |
2174 } | |
2175 | |
2176 @Override | |
2177 public int readInt32() throws IOException { | |
2178 return readRawVarint32(); | |
2179 } | |
2180 | |
2181 @Override | |
2182 public long readFixed64() throws IOException { | |
2183 return readRawLittleEndian64(); | |
2184 } | |
2185 | |
2186 @Override | |
2187 public int readFixed32() throws IOException { | |
2188 return readRawLittleEndian32(); | |
2189 } | |
2190 | |
2191 @Override | |
2192 public boolean readBool() throws IOException { | |
2193 return readRawVarint64() != 0; | |
2194 } | |
2195 | |
2196 @Override | |
2197 public String readString() throws IOException { | |
2198 final int size = readRawVarint32(); | |
2199 if (size > 0 && size <= (bufferSize - pos)) { | |
2200 // Fast path: We already have the bytes in a contiguous buffer, so | |
2201 // just copy directly from it. | |
2202 final String result = new String(buffer, pos, size, UTF_8); | |
2203 pos += size; | |
2204 return result; | |
2205 } | |
2206 if (size == 0) { | |
2207 return ""; | |
2208 } | |
2209 if (size <= bufferSize) { | |
2210 refillBuffer(size); | |
2211 String result = new String(buffer, pos, size, UTF_8); | |
2212 pos += size; | |
2213 return result; | |
2214 } | |
2215 // Slow path: Build a byte array first then copy it. | |
2216 return new String(readRawBytesSlowPath(size), UTF_8); | |
2217 } | |
2218 | |
2219 @Override | |
2220 public String readStringRequireUtf8() throws IOException { | |
2221 final int size = readRawVarint32(); | |
2222 final byte[] bytes; | |
2223 final int oldPos = pos; | |
2224 final int tempPos; | |
2225 if (size <= (bufferSize - oldPos) && size > 0) { | |
2226 // Fast path: We already have the bytes in a contiguous buffer, so | |
2227 // just copy directly from it. | |
2228 bytes = buffer; | |
2229 pos = oldPos + size; | |
2230 tempPos = oldPos; | |
2231 } else if (size == 0) { | |
2232 return ""; | |
2233 } else if (size <= bufferSize) { | |
2234 refillBuffer(size); | |
2235 bytes = buffer; | |
2236 tempPos = 0; | |
2237 pos = tempPos + size; | |
2238 } else { | |
2239 // Slow path: Build a byte array first then copy it. | |
2240 bytes = readRawBytesSlowPath(size); | |
2241 tempPos = 0; | |
2242 } | |
2243 // TODO(martinrb): We could save a pass by validating while decoding. | |
2244 if (!Utf8.isValidUtf8(bytes, tempPos, tempPos + size)) { | |
2245 throw InvalidProtocolBufferException.invalidUtf8(); | |
2246 } | |
2247 return new String(bytes, tempPos, size, UTF_8); | |
2248 } | |
2249 | |
2250 @Override | |
2251 public void readGroup( | |
2252 final int fieldNumber, | |
2253 final MessageLite.Builder builder, | |
2254 final ExtensionRegistryLite extensionRegistry) | |
2255 throws IOException { | |
2256 if (recursionDepth >= recursionLimit) { | |
2257 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
2258 } | |
2259 ++recursionDepth; | |
2260 builder.mergeFrom(this, extensionRegistry); | |
2261 checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GR
OUP)); | |
2262 --recursionDepth; | |
2263 } | |
2264 | |
2265 | |
2266 @Override | |
2267 public <T extends MessageLite> T readGroup( | |
2268 final int fieldNumber, | |
2269 final Parser<T> parser, | |
2270 final ExtensionRegistryLite extensionRegistry) | |
2271 throws IOException { | |
2272 if (recursionDepth >= recursionLimit) { | |
2273 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
2274 } | |
2275 ++recursionDepth; | |
2276 T result = parser.parsePartialFrom(this, extensionRegistry); | |
2277 checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GR
OUP)); | |
2278 --recursionDepth; | |
2279 return result; | |
2280 } | |
2281 | |
2282 @Deprecated | |
2283 @Override | |
2284 public void readUnknownGroup(final int fieldNumber, final MessageLite.Builde
r builder) | |
2285 throws IOException { | |
2286 readGroup(fieldNumber, builder, ExtensionRegistryLite.getEmptyRegistry()); | |
2287 } | |
2288 | |
2289 @Override | |
2290 public void readMessage( | |
2291 final MessageLite.Builder builder, final ExtensionRegistryLite extension
Registry) | |
2292 throws IOException { | |
2293 final int length = readRawVarint32(); | |
2294 if (recursionDepth >= recursionLimit) { | |
2295 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
2296 } | |
2297 final int oldLimit = pushLimit(length); | |
2298 ++recursionDepth; | |
2299 builder.mergeFrom(this, extensionRegistry); | |
2300 checkLastTagWas(0); | |
2301 --recursionDepth; | |
2302 popLimit(oldLimit); | |
2303 } | |
2304 | |
2305 | |
2306 @Override | |
2307 public <T extends MessageLite> T readMessage( | |
2308 final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) t
hrows IOException { | |
2309 int length = readRawVarint32(); | |
2310 if (recursionDepth >= recursionLimit) { | |
2311 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
2312 } | |
2313 final int oldLimit = pushLimit(length); | |
2314 ++recursionDepth; | |
2315 T result = parser.parsePartialFrom(this, extensionRegistry); | |
2316 checkLastTagWas(0); | |
2317 --recursionDepth; | |
2318 popLimit(oldLimit); | |
2319 return result; | |
2320 } | |
2321 | |
2322 @Override | |
2323 public ByteString readBytes() throws IOException { | |
2324 final int size = readRawVarint32(); | |
2325 if (size <= (bufferSize - pos) && size > 0) { | |
2326 // Fast path: We already have the bytes in a contiguous buffer, so | |
2327 // just copy directly from it. | |
2328 final ByteString result = ByteString.copyFrom(buffer, pos, size); | |
2329 pos += size; | |
2330 return result; | |
2331 } | |
2332 if (size == 0) { | |
2333 return ByteString.EMPTY; | |
2334 } | |
2335 // Slow path: Build a byte array first then copy it. | |
2336 return ByteString.wrap(readRawBytesSlowPath(size)); | |
2337 } | |
2338 | |
2339 @Override | |
2340 public byte[] readByteArray() throws IOException { | |
2341 final int size = readRawVarint32(); | |
2342 if (size <= (bufferSize - pos) && size > 0) { | |
2343 // Fast path: We already have the bytes in a contiguous buffer, so | |
2344 // just copy directly from it. | |
2345 final byte[] result = Arrays.copyOfRange(buffer, pos, pos + size); | |
2346 pos += size; | |
2347 return result; | |
2348 } else { | |
2349 // Slow path: Build a byte array first then copy it. | |
2350 return readRawBytesSlowPath(size); | |
2351 } | |
2352 } | |
2353 | |
2354 @Override | |
2355 public ByteBuffer readByteBuffer() throws IOException { | |
2356 final int size = readRawVarint32(); | |
2357 if (size <= (bufferSize - pos) && size > 0) { | |
2358 // Fast path: We already have the bytes in a contiguous buffer. | |
2359 ByteBuffer result = ByteBuffer.wrap(Arrays.copyOfRange(buffer, pos, pos
+ size)); | |
2360 pos += size; | |
2361 return result; | |
2362 } | |
2363 if (size == 0) { | |
2364 return Internal.EMPTY_BYTE_BUFFER; | |
2365 } | |
2366 // Slow path: Build a byte array first then copy it. | |
2367 return ByteBuffer.wrap(readRawBytesSlowPath(size)); | |
2368 } | |
2369 | |
2370 @Override | |
2371 public int readUInt32() throws IOException { | |
2372 return readRawVarint32(); | |
2373 } | |
2374 | |
2375 @Override | |
2376 public int readEnum() throws IOException { | |
2377 return readRawVarint32(); | |
2378 } | |
2379 | |
2380 @Override | |
2381 public int readSFixed32() throws IOException { | |
2382 return readRawLittleEndian32(); | |
2383 } | |
2384 | |
2385 @Override | |
2386 public long readSFixed64() throws IOException { | |
2387 return readRawLittleEndian64(); | |
2388 } | |
2389 | |
2390 @Override | |
2391 public int readSInt32() throws IOException { | |
2392 return decodeZigZag32(readRawVarint32()); | |
2393 } | |
2394 | |
2395 @Override | |
2396 public long readSInt64() throws IOException { | |
2397 return decodeZigZag64(readRawVarint64()); | |
2398 } | |
2399 | |
2400 // ================================================================= | |
2401 | |
2402 @Override | |
2403 public int readRawVarint32() throws IOException { | |
2404 // See implementation notes for readRawVarint64 | |
2405 fastpath: | |
2406 { | |
2407 int tempPos = pos; | |
2408 | |
2409 if (bufferSize == tempPos) { | |
2410 break fastpath; | |
2411 } | |
2412 | |
2413 final byte[] buffer = this.buffer; | |
2414 int x; | |
2415 if ((x = buffer[tempPos++]) >= 0) { | |
2416 pos = tempPos; | |
2417 return x; | |
2418 } else if (bufferSize - tempPos < 9) { | |
2419 break fastpath; | |
2420 } else if ((x ^= (buffer[tempPos++] << 7)) < 0) { | |
2421 x ^= (~0 << 7); | |
2422 } else if ((x ^= (buffer[tempPos++] << 14)) >= 0) { | |
2423 x ^= (~0 << 7) ^ (~0 << 14); | |
2424 } else if ((x ^= (buffer[tempPos++] << 21)) < 0) { | |
2425 x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21); | |
2426 } else { | |
2427 int y = buffer[tempPos++]; | |
2428 x ^= y << 28; | |
2429 x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28); | |
2430 if (y < 0 | |
2431 && buffer[tempPos++] < 0 | |
2432 && buffer[tempPos++] < 0 | |
2433 && buffer[tempPos++] < 0 | |
2434 && buffer[tempPos++] < 0 | |
2435 && buffer[tempPos++] < 0) { | |
2436 break fastpath; // Will throw malformedVarint() | |
2437 } | |
2438 } | |
2439 pos = tempPos; | |
2440 return x; | |
2441 } | |
2442 return (int) readRawVarint64SlowPath(); | |
2443 } | |
2444 | |
2445 private void skipRawVarint() throws IOException { | |
2446 if (bufferSize - pos >= MAX_VARINT_SIZE) { | |
2447 skipRawVarintFastPath(); | |
2448 } else { | |
2449 skipRawVarintSlowPath(); | |
2450 } | |
2451 } | |
2452 | |
2453 private void skipRawVarintFastPath() throws IOException { | |
2454 for (int i = 0; i < MAX_VARINT_SIZE; i++) { | |
2455 if (buffer[pos++] >= 0) { | |
2456 return; | |
2457 } | |
2458 } | |
2459 throw InvalidProtocolBufferException.malformedVarint(); | |
2460 } | |
2461 | |
2462 private void skipRawVarintSlowPath() throws IOException { | |
2463 for (int i = 0; i < MAX_VARINT_SIZE; i++) { | |
2464 if (readRawByte() >= 0) { | |
2465 return; | |
2466 } | |
2467 } | |
2468 throw InvalidProtocolBufferException.malformedVarint(); | |
2469 } | |
2470 | |
2471 @Override | |
2472 public long readRawVarint64() throws IOException { | |
2473 // Implementation notes: | |
2474 // | |
2475 // Optimized for one-byte values, expected to be common. | |
2476 // The particular code below was selected from various candidates | |
2477 // empirically, by winning VarintBenchmark. | |
2478 // | |
2479 // Sign extension of (signed) Java bytes is usually a nuisance, but | |
2480 // we exploit it here to more easily obtain the sign of bytes read. | |
2481 // Instead of cleaning up the sign extension bits by masking eagerly, | |
2482 // we delay until we find the final (positive) byte, when we clear all | |
2483 // accumulated bits with one xor. We depend on javac to constant fold. | |
2484 fastpath: | |
2485 { | |
2486 int tempPos = pos; | |
2487 | |
2488 if (bufferSize == tempPos) { | |
2489 break fastpath; | |
2490 } | |
2491 | |
2492 final byte[] buffer = this.buffer; | |
2493 long x; | |
2494 int y; | |
2495 if ((y = buffer[tempPos++]) >= 0) { | |
2496 pos = tempPos; | |
2497 return y; | |
2498 } else if (bufferSize - tempPos < 9) { | |
2499 break fastpath; | |
2500 } else if ((y ^= (buffer[tempPos++] << 7)) < 0) { | |
2501 x = y ^ (~0 << 7); | |
2502 } else if ((y ^= (buffer[tempPos++] << 14)) >= 0) { | |
2503 x = y ^ ((~0 << 7) ^ (~0 << 14)); | |
2504 } else if ((y ^= (buffer[tempPos++] << 21)) < 0) { | |
2505 x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21)); | |
2506 } else if ((x = y ^ ((long) buffer[tempPos++] << 28)) >= 0L) { | |
2507 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); | |
2508 } else if ((x ^= ((long) buffer[tempPos++] << 35)) < 0L) { | |
2509 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35
); | |
2510 } else if ((x ^= ((long) buffer[tempPos++] << 42)) >= 0L) { | |
2511 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35
) ^ (~0L << 42); | |
2512 } else if ((x ^= ((long) buffer[tempPos++] << 49)) < 0L) { | |
2513 x ^= | |
2514 (~0L << 7) | |
2515 ^ (~0L << 14) | |
2516 ^ (~0L << 21) | |
2517 ^ (~0L << 28) | |
2518 ^ (~0L << 35) | |
2519 ^ (~0L << 42) | |
2520 ^ (~0L << 49); | |
2521 } else { | |
2522 x ^= ((long) buffer[tempPos++] << 56); | |
2523 x ^= | |
2524 (~0L << 7) | |
2525 ^ (~0L << 14) | |
2526 ^ (~0L << 21) | |
2527 ^ (~0L << 28) | |
2528 ^ (~0L << 35) | |
2529 ^ (~0L << 42) | |
2530 ^ (~0L << 49) | |
2531 ^ (~0L << 56); | |
2532 if (x < 0L) { | |
2533 if (buffer[tempPos++] < 0L) { | |
2534 break fastpath; // Will throw malformedVarint() | |
2535 } | |
2536 } | |
2537 } | |
2538 pos = tempPos; | |
2539 return x; | |
2540 } | |
2541 return readRawVarint64SlowPath(); | |
2542 } | |
2543 | |
2544 @Override | |
2545 long readRawVarint64SlowPath() throws IOException { | |
2546 long result = 0; | |
2547 for (int shift = 0; shift < 64; shift += 7) { | |
2548 final byte b = readRawByte(); | |
2549 result |= (long) (b & 0x7F) << shift; | |
2550 if ((b & 0x80) == 0) { | |
2551 return result; | |
2552 } | |
2553 } | |
2554 throw InvalidProtocolBufferException.malformedVarint(); | |
2555 } | |
2556 | |
2557 @Override | |
2558 public int readRawLittleEndian32() throws IOException { | |
2559 int tempPos = pos; | |
2560 | |
2561 if (bufferSize - tempPos < FIXED_32_SIZE) { | |
2562 refillBuffer(FIXED_32_SIZE); | |
2563 tempPos = pos; | |
2564 } | |
2565 | |
2566 final byte[] buffer = this.buffer; | |
2567 pos = tempPos + FIXED_32_SIZE; | |
2568 return (((buffer[tempPos] & 0xff)) | |
2569 | ((buffer[tempPos + 1] & 0xff) << 8) | |
2570 | ((buffer[tempPos + 2] & 0xff) << 16) | |
2571 | ((buffer[tempPos + 3] & 0xff) << 24)); | |
2572 } | |
2573 | |
2574 @Override | |
2575 public long readRawLittleEndian64() throws IOException { | |
2576 int tempPos = pos; | |
2577 | |
2578 if (bufferSize - tempPos < FIXED_64_SIZE) { | |
2579 refillBuffer(FIXED_64_SIZE); | |
2580 tempPos = pos; | |
2581 } | |
2582 | |
2583 final byte[] buffer = this.buffer; | |
2584 pos = tempPos + FIXED_64_SIZE; | |
2585 return (((buffer[tempPos] & 0xffL)) | |
2586 | ((buffer[tempPos + 1] & 0xffL) << 8) | |
2587 | ((buffer[tempPos + 2] & 0xffL) << 16) | |
2588 | ((buffer[tempPos + 3] & 0xffL) << 24) | |
2589 | ((buffer[tempPos + 4] & 0xffL) << 32) | |
2590 | ((buffer[tempPos + 5] & 0xffL) << 40) | |
2591 | ((buffer[tempPos + 6] & 0xffL) << 48) | |
2592 | ((buffer[tempPos + 7] & 0xffL) << 56)); | |
2593 } | |
2594 | |
2595 // ----------------------------------------------------------------- | |
2596 | |
2597 @Override | |
2598 public void enableAliasing(boolean enabled) { | |
2599 // TODO(nathanmittler): Ideally we should throw here. Do nothing for backw
ard compatibility. | |
2600 } | |
2601 | |
2602 @Override | |
2603 public void resetSizeCounter() { | |
2604 totalBytesRetired = -pos; | |
2605 } | |
2606 | |
2607 @Override | |
2608 public int pushLimit(int byteLimit) throws InvalidProtocolBufferException { | |
2609 if (byteLimit < 0) { | |
2610 throw InvalidProtocolBufferException.negativeSize(); | |
2611 } | |
2612 byteLimit += totalBytesRetired + pos; | |
2613 final int oldLimit = currentLimit; | |
2614 if (byteLimit > oldLimit) { | |
2615 throw InvalidProtocolBufferException.truncatedMessage(); | |
2616 } | |
2617 currentLimit = byteLimit; | |
2618 | |
2619 recomputeBufferSizeAfterLimit(); | |
2620 | |
2621 return oldLimit; | |
2622 } | |
2623 | |
2624 private void recomputeBufferSizeAfterLimit() { | |
2625 bufferSize += bufferSizeAfterLimit; | |
2626 final int bufferEnd = totalBytesRetired + bufferSize; | |
2627 if (bufferEnd > currentLimit) { | |
2628 // Limit is in current buffer. | |
2629 bufferSizeAfterLimit = bufferEnd - currentLimit; | |
2630 bufferSize -= bufferSizeAfterLimit; | |
2631 } else { | |
2632 bufferSizeAfterLimit = 0; | |
2633 } | |
2634 } | |
2635 | |
2636 @Override | |
2637 public void popLimit(final int oldLimit) { | |
2638 currentLimit = oldLimit; | |
2639 recomputeBufferSizeAfterLimit(); | |
2640 } | |
2641 | |
2642 @Override | |
2643 public int getBytesUntilLimit() { | |
2644 if (currentLimit == Integer.MAX_VALUE) { | |
2645 return -1; | |
2646 } | |
2647 | |
2648 final int currentAbsolutePosition = totalBytesRetired + pos; | |
2649 return currentLimit - currentAbsolutePosition; | |
2650 } | |
2651 | |
2652 @Override | |
2653 public boolean isAtEnd() throws IOException { | |
2654 return pos == bufferSize && !tryRefillBuffer(1); | |
2655 } | |
2656 | |
2657 @Override | |
2658 public int getTotalBytesRead() { | |
2659 return totalBytesRetired + pos; | |
2660 } | |
2661 | |
2662 private interface RefillCallback { | |
2663 void onRefill(); | |
2664 } | |
2665 | |
2666 private RefillCallback refillCallback = null; | |
2667 | |
2668 /** | |
2669 * Reads more bytes from the input, making at least {@code n} bytes availabl
e in the buffer. | |
2670 * Caller must ensure that the requested space is not yet available, and tha
t the requested | |
2671 * space is less than BUFFER_SIZE. | |
2672 * | |
2673 * @throws InvalidProtocolBufferException The end of the stream or the curre
nt limit was | |
2674 * reached. | |
2675 */ | |
2676 private void refillBuffer(int n) throws IOException { | |
2677 if (!tryRefillBuffer(n)) { | |
2678 throw InvalidProtocolBufferException.truncatedMessage(); | |
2679 } | |
2680 } | |
2681 | |
2682 /** | |
2683 * Tries to read more bytes from the input, making at least {@code n} bytes
available in the | |
2684 * buffer. Caller must ensure that the requested space is not yet available,
and that the | |
2685 * requested space is less than BUFFER_SIZE. | |
2686 * | |
2687 * @return {@code true} if the bytes could be made available; {@code false}
if the end of the | |
2688 * stream or the current limit was reached. | |
2689 */ | |
2690 private boolean tryRefillBuffer(int n) throws IOException { | |
2691 if (pos + n <= bufferSize) { | |
2692 throw new IllegalStateException( | |
2693 "refillBuffer() called when " + n + " bytes were already available i
n buffer"); | |
2694 } | |
2695 | |
2696 if (totalBytesRetired + pos + n > currentLimit) { | |
2697 // Oops, we hit a limit. | |
2698 return false; | |
2699 } | |
2700 | |
2701 if (refillCallback != null) { | |
2702 refillCallback.onRefill(); | |
2703 } | |
2704 | |
2705 int tempPos = pos; | |
2706 if (tempPos > 0) { | |
2707 if (bufferSize > tempPos) { | |
2708 System.arraycopy(buffer, tempPos, buffer, 0, bufferSize - tempPos); | |
2709 } | |
2710 totalBytesRetired += tempPos; | |
2711 bufferSize -= tempPos; | |
2712 pos = 0; | |
2713 } | 1099 } |
2714 | 1100 |
2715 int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize)
; | 1101 int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize)
; |
2716 if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) { | 1102 if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) { |
2717 throw new IllegalStateException( | 1103 throw new IllegalStateException( |
2718 "InputStream#read(byte[]) returned invalid result: " | 1104 "InputStream#read(byte[]) returned invalid result: " + bytesRead + |
2719 + bytesRead | 1105 "\nThe InputStream implementation is buggy."); |
2720 + "\nThe InputStream implementation is buggy."); | |
2721 } | 1106 } |
2722 if (bytesRead > 0) { | 1107 if (bytesRead > 0) { |
2723 bufferSize += bytesRead; | 1108 bufferSize += bytesRead; |
2724 // Integer-overflow-conscious check against sizeLimit | 1109 // Integer-overflow-conscious check against sizeLimit |
2725 if (totalBytesRetired + n - sizeLimit > 0) { | 1110 if (totalBytesRetired + n - sizeLimit > 0) { |
2726 throw InvalidProtocolBufferException.sizeLimitExceeded(); | 1111 throw InvalidProtocolBufferException.sizeLimitExceeded(); |
2727 } | 1112 } |
2728 recomputeBufferSizeAfterLimit(); | 1113 recomputeBufferSizeAfterLimit(); |
2729 return (bufferSize >= n) ? true : tryRefillBuffer(n); | 1114 return (bufferSize >= n) ? true : tryRefillBuffer(n); |
2730 } | 1115 } |
2731 | 1116 } |
2732 return false; | 1117 |
2733 } | 1118 return false; |
2734 | 1119 } |
2735 @Override | 1120 |
2736 public byte readRawByte() throws IOException { | 1121 /** |
2737 if (pos == bufferSize) { | 1122 * Read one byte from the input. |
2738 refillBuffer(1); | 1123 * |
2739 } | 1124 * @throws InvalidProtocolBufferException The end of the stream or the current |
2740 return buffer[pos++]; | 1125 * limit was reached. |
2741 } | 1126 */ |
2742 | 1127 public byte readRawByte() throws IOException { |
2743 @Override | 1128 if (bufferPos == bufferSize) { |
2744 public byte[] readRawBytes(final int size) throws IOException { | 1129 refillBuffer(1); |
2745 final int tempPos = pos; | 1130 } |
2746 if (size <= (bufferSize - tempPos) && size > 0) { | 1131 return buffer[bufferPos++]; |
2747 pos = tempPos + size; | 1132 } |
2748 return Arrays.copyOfRange(buffer, tempPos, tempPos + size); | 1133 |
2749 } else { | 1134 /** |
2750 return readRawBytesSlowPath(size); | 1135 * Read a fixed size of bytes from the input. |
2751 } | 1136 * |
2752 } | 1137 * @throws InvalidProtocolBufferException The end of the stream or the current |
2753 | 1138 * limit was reached. |
2754 /** | 1139 */ |
2755 * Exactly like readRawBytes, but caller must have already checked the fast
path: (size <= | 1140 public byte[] readRawBytes(final int size) throws IOException { |
2756 * (bufferSize - pos) && size > 0) | 1141 final int pos = bufferPos; |
2757 */ | 1142 if (size <= (bufferSize - pos) && size > 0) { |
2758 private byte[] readRawBytesSlowPath(final int size) throws IOException { | 1143 bufferPos = pos + size; |
| 1144 return Arrays.copyOfRange(buffer, pos, pos + size); |
| 1145 } else { |
| 1146 return readRawBytesSlowPath(size); |
| 1147 } |
| 1148 } |
| 1149 |
| 1150 /** |
| 1151 * Exactly like readRawBytes, but caller must have already checked the fast |
| 1152 * path: (size <= (bufferSize - pos) && size > 0) |
| 1153 */ |
| 1154 private byte[] readRawBytesSlowPath(final int size) throws IOException { |
| 1155 if (size <= 0) { |
2759 if (size == 0) { | 1156 if (size == 0) { |
2760 return Internal.EMPTY_BYTE_ARRAY; | 1157 return Internal.EMPTY_BYTE_ARRAY; |
2761 } | 1158 } else { |
2762 if (size < 0) { | |
2763 throw InvalidProtocolBufferException.negativeSize(); | 1159 throw InvalidProtocolBufferException.negativeSize(); |
2764 } | 1160 } |
2765 | 1161 } |
2766 // Integer-overflow-conscious check that the message size so far has not e
xceeded sizeLimit. | 1162 |
2767 int currentMessageSize = totalBytesRetired + pos + size; | 1163 // Verify that the message size so far has not exceeded sizeLimit. |
2768 if (currentMessageSize - sizeLimit > 0) { | 1164 int currentMessageSize = totalBytesRetired + bufferPos + size; |
2769 throw InvalidProtocolBufferException.sizeLimitExceeded(); | 1165 if (currentMessageSize > sizeLimit) { |
2770 } | 1166 throw InvalidProtocolBufferException.sizeLimitExceeded(); |
2771 | 1167 } |
2772 // Verify that the message size so far has not exceeded currentLimit. | 1168 |
2773 if (currentMessageSize > currentLimit) { | 1169 // Verify that the message size so far has not exceeded currentLimit. |
2774 // Read to the end of the stream anyway. | 1170 if (currentMessageSize > currentLimit) { |
2775 skipRawBytes(currentLimit - totalBytesRetired - pos); | 1171 // Read to the end of the stream anyway. |
2776 throw InvalidProtocolBufferException.truncatedMessage(); | 1172 skipRawBytes(currentLimit - totalBytesRetired - bufferPos); |
2777 } | 1173 throw InvalidProtocolBufferException.truncatedMessage(); |
2778 | 1174 } |
2779 final int originalBufferPos = pos; | 1175 |
2780 final int bufferedBytes = bufferSize - pos; | 1176 // We need the input stream to proceed. |
2781 | 1177 if (input == null) { |
2782 // Mark the current buffer consumed. | 1178 throw InvalidProtocolBufferException.truncatedMessage(); |
2783 totalBytesRetired += bufferSize; | 1179 } |
2784 pos = 0; | 1180 |
2785 bufferSize = 0; | 1181 final int originalBufferPos = bufferPos; |
2786 | 1182 final int bufferedBytes = bufferSize - bufferPos; |
2787 // Determine the number of bytes we need to read from the input stream. | 1183 |
2788 int sizeLeft = size - bufferedBytes; | 1184 // Mark the current buffer consumed. |
2789 // TODO(nathanmittler): Consider using a value larger than DEFAULT_BUFFER_
SIZE. | 1185 totalBytesRetired += bufferSize; |
2790 if (sizeLeft < DEFAULT_BUFFER_SIZE || sizeLeft <= input.available()) { | 1186 bufferPos = 0; |
2791 // Either the bytes we need are known to be available, or the required b
uffer is | 1187 bufferSize = 0; |
2792 // within an allowed threshold - go ahead and allocate the buffer now. | 1188 |
2793 final byte[] bytes = new byte[size]; | 1189 // Determine the number of bytes we need to read from the input stream. |
2794 | 1190 int sizeLeft = size - bufferedBytes; |
2795 // Copy all of the buffered bytes to the result buffer. | 1191 // TODO(nathanmittler): Consider using a value larger than BUFFER_SIZE. |
2796 System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes); | 1192 if (sizeLeft < BUFFER_SIZE || sizeLeft <= input.available()) { |
2797 | 1193 // Either the bytes we need are known to be available, or the required buf
fer is |
2798 // Fill the remaining bytes from the input stream. | 1194 // within an allowed threshold - go ahead and allocate the buffer now. |
2799 int tempPos = bufferedBytes; | 1195 final byte[] bytes = new byte[size]; |
2800 while (tempPos < bytes.length) { | 1196 |
2801 int n = input.read(bytes, tempPos, size - tempPos); | 1197 // Copy all of the buffered bytes to the result buffer. |
2802 if (n == -1) { | 1198 System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes); |
2803 throw InvalidProtocolBufferException.truncatedMessage(); | 1199 |
2804 } | 1200 // Fill the remaining bytes from the input stream. |
2805 totalBytesRetired += n; | 1201 int pos = bufferedBytes; |
2806 tempPos += n; | 1202 while (pos < bytes.length) { |
| 1203 int n = input.read(bytes, pos, size - pos); |
| 1204 if (n == -1) { |
| 1205 throw InvalidProtocolBufferException.truncatedMessage(); |
2807 } | 1206 } |
2808 | 1207 totalBytesRetired += n; |
2809 return bytes; | 1208 pos += n; |
2810 } | 1209 } |
2811 | 1210 |
2812 // The size is very large. For security reasons, we can't allocate the | 1211 return bytes; |
2813 // entire byte array yet. The size comes directly from the input, so a | 1212 } |
2814 // maliciously-crafted message could provide a bogus very large size in | 1213 |
2815 // order to trick the app into allocating a lot of memory. We avoid this | 1214 // The size is very large. For security reasons, we can't allocate the |
2816 // by allocating and reading only a small chunk at a time, so that the | 1215 // entire byte array yet. The size comes directly from the input, so a |
2817 // malicious message must actually *be* extremely large to cause | 1216 // maliciously-crafted message could provide a bogus very large size in |
2818 // problems. Meanwhile, we limit the allowed size of a message elsewhere. | 1217 // order to trick the app into allocating a lot of memory. We avoid this |
2819 final List<byte[]> chunks = new ArrayList<byte[]>(); | 1218 // by allocating and reading only a small chunk at a time, so that the |
2820 | 1219 // malicious message must actually *be* extremely large to cause |
2821 while (sizeLeft > 0) { | 1220 // problems. Meanwhile, we limit the allowed size of a message elsewhere. |
2822 // TODO(nathanmittler): Consider using a value larger than DEFAULT_BUFFE
R_SIZE. | 1221 final List<byte[]> chunks = new ArrayList<byte[]>(); |
2823 final byte[] chunk = new byte[Math.min(sizeLeft, DEFAULT_BUFFER_SIZE)]; | 1222 |
2824 int tempPos = 0; | 1223 while (sizeLeft > 0) { |
2825 while (tempPos < chunk.length) { | 1224 // TODO(nathanmittler): Consider using a value larger than BUFFER_SIZE. |
2826 final int n = input.read(chunk, tempPos, chunk.length - tempPos); | 1225 final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)]; |
2827 if (n == -1) { | 1226 int pos = 0; |
2828 throw InvalidProtocolBufferException.truncatedMessage(); | 1227 while (pos < chunk.length) { |
2829 } | 1228 final int n = input.read(chunk, pos, chunk.length - pos); |
2830 totalBytesRetired += n; | 1229 if (n == -1) { |
2831 tempPos += n; | 1230 throw InvalidProtocolBufferException.truncatedMessage(); |
2832 } | 1231 } |
2833 sizeLeft -= chunk.length; | 1232 totalBytesRetired += n; |
2834 chunks.add(chunk); | 1233 pos += n; |
2835 } | 1234 } |
2836 | 1235 sizeLeft -= chunk.length; |
2837 // OK, got everything. Now concatenate it all into one buffer. | 1236 chunks.add(chunk); |
2838 final byte[] bytes = new byte[size]; | 1237 } |
2839 | 1238 |
2840 // Start by copying the leftover bytes from this.buffer. | 1239 // OK, got everything. Now concatenate it all into one buffer. |
2841 System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes); | 1240 final byte[] bytes = new byte[size]; |
2842 | 1241 |
2843 // And now all the chunks. | 1242 // Start by copying the leftover bytes from this.buffer. |
2844 int tempPos = bufferedBytes; | 1243 System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes); |
2845 for (final byte[] chunk : chunks) { | 1244 |
2846 System.arraycopy(chunk, 0, bytes, tempPos, chunk.length); | 1245 // And now all the chunks. |
2847 tempPos += chunk.length; | 1246 int pos = bufferedBytes; |
2848 } | 1247 for (final byte[] chunk : chunks) { |
2849 | 1248 System.arraycopy(chunk, 0, bytes, pos, chunk.length); |
2850 // Done. | 1249 pos += chunk.length; |
2851 return bytes; | 1250 } |
2852 } | 1251 |
2853 | 1252 // Done. |
2854 @Override | 1253 return bytes; |
2855 public void skipRawBytes(final int size) throws IOException { | 1254 } |
2856 if (size <= (bufferSize - pos) && size >= 0) { | 1255 |
2857 // We have all the bytes we need already. | 1256 /** |
2858 pos += size; | 1257 * Reads and discards {@code size} bytes. |
2859 } else { | 1258 * |
2860 skipRawBytesSlowPath(size); | 1259 * @throws InvalidProtocolBufferException The end of the stream or the current |
2861 } | 1260 * limit was reached. |
2862 } | 1261 */ |
2863 | 1262 public void skipRawBytes(final int size) throws IOException { |
2864 /** | 1263 if (size <= (bufferSize - bufferPos) && size >= 0) { |
2865 * Exactly like skipRawBytes, but caller must have already checked the fast
path: (size <= | 1264 // We have all the bytes we need already. |
2866 * (bufferSize - pos) && size >= 0) | 1265 bufferPos += size; |
2867 */ | 1266 } else { |
2868 private void skipRawBytesSlowPath(final int size) throws IOException { | 1267 skipRawBytesSlowPath(size); |
2869 if (size < 0) { | 1268 } |
2870 throw InvalidProtocolBufferException.negativeSize(); | 1269 } |
2871 } | 1270 |
2872 | 1271 /** |
2873 if (totalBytesRetired + pos + size > currentLimit) { | 1272 * Exactly like skipRawBytes, but caller must have already checked the fast |
2874 // Read to the end of the stream anyway. | 1273 * path: (size <= (bufferSize - pos) && size >= 0) |
2875 skipRawBytes(currentLimit - totalBytesRetired - pos); | 1274 */ |
2876 // Then fail. | 1275 private void skipRawBytesSlowPath(final int size) throws IOException { |
2877 throw InvalidProtocolBufferException.truncatedMessage(); | 1276 if (size < 0) { |
2878 } | 1277 throw InvalidProtocolBufferException.negativeSize(); |
2879 | 1278 } |
2880 // Skipping more bytes than are in the buffer. First skip what we have. | 1279 |
2881 int tempPos = bufferSize - pos; | 1280 if (totalBytesRetired + bufferPos + size > currentLimit) { |
2882 pos = bufferSize; | 1281 // Read to the end of the stream anyway. |
2883 | 1282 skipRawBytes(currentLimit - totalBytesRetired - bufferPos); |
2884 // Keep refilling the buffer until we get to the point we wanted to skip t
o. | 1283 // Then fail. |
2885 // This has the side effect of ensuring the limits are updated correctly. | 1284 throw InvalidProtocolBufferException.truncatedMessage(); |
| 1285 } |
| 1286 |
| 1287 // Skipping more bytes than are in the buffer. First skip what we have. |
| 1288 int pos = bufferSize - bufferPos; |
| 1289 bufferPos = bufferSize; |
| 1290 |
| 1291 // Keep refilling the buffer until we get to the point we wanted to skip to. |
| 1292 // This has the side effect of ensuring the limits are updated correctly. |
| 1293 refillBuffer(1); |
| 1294 while (size - pos > bufferSize) { |
| 1295 pos += bufferSize; |
| 1296 bufferPos = bufferSize; |
2886 refillBuffer(1); | 1297 refillBuffer(1); |
2887 while (size - tempPos > bufferSize) { | 1298 } |
2888 tempPos += bufferSize; | 1299 |
2889 pos = bufferSize; | 1300 bufferPos = size - pos; |
2890 refillBuffer(1); | |
2891 } | |
2892 | |
2893 pos = size - tempPos; | |
2894 } | |
2895 } | 1301 } |
2896 } | 1302 } |
OLD | NEW |