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 |
33 import java.io.ByteArrayOutputStream; | 41 import java.io.ByteArrayOutputStream; |
34 import java.io.IOException; | 42 import java.io.IOException; |
35 import java.io.InputStream; | 43 import java.io.InputStream; |
36 import java.nio.ByteBuffer; | 44 import java.nio.ByteBuffer; |
37 import java.util.ArrayList; | 45 import java.util.ArrayList; |
38 import java.util.Arrays; | 46 import java.util.Arrays; |
39 import java.util.List; | 47 import java.util.List; |
40 | 48 |
41 /** | 49 /** |
42 * Reads and decodes protocol message fields. | 50 * Reads and decodes protocol message fields. |
43 * | 51 * |
44 * This class contains two kinds of methods: methods that read specific | 52 * <p>This class contains two kinds of methods: methods that read specific proto
col message |
45 * protocol message constructs and field types (e.g. {@link #readTag()} and | 53 * constructs and field types (e.g. {@link #readTag()} and {@link #readInt32()})
and methods that |
46 * {@link #readInt32()}) and methods that read low-level values (e.g. | 54 * read low-level values (e.g. {@link #readRawVarint32()} and {@link #readRawByt
es}). If you are |
47 * {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading | 55 * reading encoded protocol messages, you should use the former methods, but if
you are reading some |
48 * encoded protocol messages, you should use the former methods, but if you are | 56 * other format of your own design, use the latter. |
49 * reading some other format of your own design, use the latter. | |
50 * | 57 * |
51 * @author kenton@google.com Kenton Varda | 58 * @author kenton@google.com Kenton Varda |
52 */ | 59 */ |
53 public final class CodedInputStream { | 60 public abstract class CodedInputStream { |
54 /** | 61 private static final int DEFAULT_BUFFER_SIZE = 4096; |
55 * Create a new CodedInputStream wrapping the given InputStream. | 62 private static final int DEFAULT_RECURSION_LIMIT = 100; |
56 */ | 63 // Integer.MAX_VALUE == 0x7FFFFFF == INT_MAX from limits.h |
| 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. */ |
57 public static CodedInputStream newInstance(final InputStream input) { | 75 public static CodedInputStream newInstance(final InputStream input) { |
58 return new CodedInputStream(input, BUFFER_SIZE); | 76 return newInstance(input, DEFAULT_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); | |
66 } | 77 } |
67 | 78 |
68 /** | 79 /** Create a new CodedInputStream wrapping the given InputStream. */ |
69 * Create a new CodedInputStream wrapping the given byte array. | 80 static CodedInputStream newInstance(final InputStream input, int bufferSize) { |
70 */ | 81 if (input == null) { |
| 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. */ |
71 public static CodedInputStream newInstance(final byte[] buf) { | 89 public static CodedInputStream newInstance(final byte[] buf) { |
72 return newInstance(buf, 0, buf.length); | 90 return newInstance(buf, 0, buf.length); |
73 } | 91 } |
74 | 92 |
75 /** | 93 /** Create a new CodedInputStream wrapping the given byte array slice. */ |
76 * Create a new CodedInputStream wrapping the given byte array slice. | 94 public static CodedInputStream newInstance(final byte[] buf, final int off, fi
nal int len) { |
77 */ | |
78 public static CodedInputStream newInstance(final byte[] buf, final int off, | |
79 final int len) { | |
80 return newInstance(buf, off, len, false /* bufferIsImmutable */); | 95 return newInstance(buf, off, len, false /* bufferIsImmutable */); |
81 } | 96 } |
82 | 97 |
83 /** | 98 /** Create a new CodedInputStream wrapping the given byte array slice. */ |
84 * Create a new CodedInputStream wrapping the given byte array slice. | |
85 */ | |
86 static CodedInputStream newInstance( | 99 static CodedInputStream newInstance( |
87 final byte[] buf, final int off, final int len, final boolean bufferIsImmu
table) { | 100 final byte[] buf, final int off, final int len, final boolean bufferIsImmu
table) { |
88 CodedInputStream result = new CodedInputStream(buf, off, len, bufferIsImmuta
ble); | 101 ArrayDecoder result = new ArrayDecoder(buf, off, len, bufferIsImmutable); |
89 try { | 102 try { |
90 // Some uses of CodedInputStream can be more efficient if they know | 103 // Some uses of CodedInputStream can be more efficient if they know |
91 // exactly how many bytes are available. By pushing the end point of the | 104 // exactly how many bytes are available. By pushing the end point of the |
92 // buffer as a limit, we allow them to get this information via | 105 // buffer as a limit, we allow them to get this information via |
93 // getBytesUntilLimit(). Pushing a limit that we know is at the end of | 106 // getBytesUntilLimit(). Pushing a limit that we know is at the end of |
94 // the stream can never hurt, since we can never past that point anyway. | 107 // the stream can never hurt, since we can never past that point anyway. |
95 result.pushLimit(len); | 108 result.pushLimit(len); |
96 } catch (InvalidProtocolBufferException ex) { | 109 } catch (InvalidProtocolBufferException ex) { |
97 // The only reason pushLimit() might throw an exception here is if len | 110 // The only reason pushLimit() might throw an exception here is if len |
98 // is negative. Normally pushLimit()'s parameter comes directly off the | 111 // is negative. Normally pushLimit()'s parameter comes directly off the |
99 // wire, so it's important to catch exceptions in case of corrupt or | 112 // wire, so it's important to catch exceptions in case of corrupt or |
100 // malicious data. However, in this case, we expect that len is not a | 113 // malicious data. However, in this case, we expect that len is not a |
101 // user-supplied value, so we can assume that it being negative indicates | 114 // user-supplied value, so we can assume that it being negative indicates |
102 // a programming error. Therefore, throwing an unchecked exception is | 115 // a programming error. Therefore, throwing an unchecked exception is |
103 // appropriate. | 116 // appropriate. |
104 throw new IllegalArgumentException(ex); | 117 throw new IllegalArgumentException(ex); |
105 } | 118 } |
106 return result; | 119 return result; |
107 } | 120 } |
108 | 121 |
109 /** | 122 /** |
110 * Create a new CodedInputStream wrapping the given ByteBuffer. The data | 123 * Create a new CodedInputStream wrapping the given ByteBuffer. The data start
ing from the |
111 * starting from the ByteBuffer's current position to its limit will be read. | 124 * ByteBuffer's current position to its limit will be read. The returned Coded
InputStream may or |
112 * The returned CodedInputStream may or may not share the underlying data | 125 * may not share the underlying data in the ByteBuffer, therefore the ByteBuff
er cannot be changed |
113 * in the ByteBuffer, therefore the ByteBuffer cannot be changed while the | 126 * while the CodedInputStream is in use. Note that the ByteBuffer's position w
on't be changed by |
114 * CodedInputStream is in use. | 127 * this function. Concurrent calls with the same ByteBuffer object are safe if
no other thread is |
115 * Note that the ByteBuffer's position won't be changed by this function. | 128 * trying to alter the ByteBuffer's status. |
116 * Concurrent calls with the same ByteBuffer object are safe if no other | |
117 * thread is trying to alter the ByteBuffer's status. | |
118 */ | 129 */ |
119 public static CodedInputStream newInstance(ByteBuffer buf) { | 130 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)
{ |
120 if (buf.hasArray()) { | 136 if (buf.hasArray()) { |
121 return newInstance(buf.array(), buf.arrayOffset() + buf.position(), | 137 return newInstance( |
122 buf.remaining()); | 138 buf.array(), buf.arrayOffset() + buf.position(), buf.remaining(), buff
erIsImmutable); |
123 } else { | |
124 ByteBuffer temp = buf.duplicate(); | |
125 byte[] buffer = new byte[temp.remaining()]; | |
126 temp.get(buffer); | |
127 return newInstance(buffer); | |
128 } | 139 } |
| 140 |
| 141 if (buf.isDirect() && UnsafeDirectNioDecoder.isSupported()) { |
| 142 return new UnsafeDirectNioDecoder(buf, bufferIsImmutable); |
| 143 } |
| 144 |
| 145 // The buffer is non-direct and does not expose the underlying array. Using
the ByteBuffer API |
| 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); |
129 } | 151 } |
130 | 152 |
| 153 /** Disable construction/inheritance outside of this class. */ |
| 154 private CodedInputStream() {} |
| 155 |
131 // ----------------------------------------------------------------- | 156 // ----------------------------------------------------------------- |
132 | 157 |
133 /** | 158 /** |
134 * Attempt to read a field tag, returning zero if we have reached EOF. | 159 * Attempt to read a field tag, returning zero if we have reached EOF. Protoco
l message parsers |
135 * Protocol message parsers use this to read tags, since a protocol message | 160 * use this to read tags, since a protocol message may legally end wherever a
tag occurs, and zero |
136 * may legally end wherever a tag occurs, and zero is not a valid tag number. | 161 * is not a valid tag number. |
137 */ | 162 */ |
138 public int readTag() throws IOException { | 163 public abstract int readTag() throws IOException; |
139 if (isAtEnd()) { | 164 |
140 lastTag = 0; | 165 /** |
141 return 0; | 166 * Verifies that the last call to readTag() returned the given tag value. This
is used to verify |
142 } | 167 * that a nested group ended with the correct end tag. |
143 | 168 * |
144 lastTag = readRawVarint32(); | 169 * @throws InvalidProtocolBufferException {@code value} does not match the las
t tag. |
145 if (WireFormat.getTagFieldNumber(lastTag) == 0) { | 170 */ |
146 // If we actually read zero (or any tag number corresponding to field | 171 public abstract void checkLastTagWas(final int value) throws InvalidProtocolBu
fferException; |
147 // number zero), that's not a valid tag. | 172 |
148 throw InvalidProtocolBufferException.invalidTag(); | 173 public abstract int getLastTag(); |
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. | |
157 * | |
158 * @throws InvalidProtocolBufferException {@code value} does not match the | |
159 * last tag. | |
160 */ | |
161 public void checkLastTagWas(final int value) | |
162 throws InvalidProtocolBufferException { | |
163 if (lastTag != value) { | |
164 throw InvalidProtocolBufferException.invalidEndTag(); | |
165 } | |
166 } | |
167 | |
168 public int getLastTag() { | |
169 return lastTag; | |
170 } | |
171 | 174 |
172 /** | 175 /** |
173 * Reads and discards a single field, given its tag value. | 176 * Reads and discards a single field, given its tag value. |
174 * | 177 * |
175 * @return {@code false} if the tag is an endgroup tag, in which case | 178 * @return {@code false} if the tag is an endgroup tag, in which case nothing
is skipped. |
176 * nothing is skipped. Otherwise, returns {@code true}. | 179 * Otherwise, returns {@code true}. |
177 */ | 180 */ |
178 public boolean skipField(final int tag) throws IOException { | 181 public abstract boolean skipField(final int tag) throws IOException; |
179 switch (WireFormat.getTagWireType(tag)) { | 182 |
180 case WireFormat.WIRETYPE_VARINT: | 183 /** |
181 skipRawVarint(); | 184 * Reads a single field and writes it to output in wire format, given its tag
value. |
182 return true; | 185 * |
183 case WireFormat.WIRETYPE_FIXED64: | 186 * @return {@code false} if the tag is an endgroup tag, in which case nothing
is skipped. |
184 skipRawBytes(8); | 187 * Otherwise, returns {@code true}. |
185 return true; | 188 * @deprecated use {@code UnknownFieldSet} or {@code UnknownFieldSetLite} to s
kip to an output |
186 case WireFormat.WIRETYPE_LENGTH_DELIMITED: | 189 * stream. |
187 skipRawBytes(readRawVarint32()); | 190 */ |
188 return true; | 191 @Deprecated |
189 case WireFormat.WIRETYPE_START_GROUP: | 192 public abstract boolean skipField(final int tag, final CodedOutputStream outpu
t) |
190 skipMessage(); | 193 throws IOException; |
191 checkLastTagWas( | 194 |
192 WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), | 195 /** |
193 WireFormat.WIRETYPE_END_GROUP)); | 196 * Reads and discards an entire message. This will read either until EOF or un
til an endgroup tag, |
194 return true; | 197 * whichever comes first. |
195 case WireFormat.WIRETYPE_END_GROUP: | 198 */ |
196 return false; | 199 public abstract void skipMessage() throws IOException; |
197 case WireFormat.WIRETYPE_FIXED32: | 200 |
198 skipRawBytes(4); | 201 /** |
199 return true; | 202 * Reads an entire message and writes it to output in wire format. This will r
ead either until EOF |
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. | |
208 * | |
209 * @return {@code false} if the tag is an endgroup tag, in which case | |
210 * nothing is skipped. Otherwise, returns {@code true}. | |
211 */ | |
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. | 203 * or until an endgroup tag, whichever comes first. |
259 */ | 204 */ |
260 public void skipMessage() throws IOException { | 205 public abstract void skipMessage(CodedOutputStream output) 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 | 206 |
313 | 207 |
314 // ----------------------------------------------------------------- | 208 // ----------------------------------------------------------------- |
315 | 209 |
316 /** Read a {@code double} field value from the stream. */ | 210 /** Read a {@code double} field value from the stream. */ |
317 public double readDouble() throws IOException { | 211 public abstract double readDouble() throws IOException; |
318 return Double.longBitsToDouble(readRawLittleEndian64()); | |
319 } | |
320 | 212 |
321 /** Read a {@code float} field value from the stream. */ | 213 /** Read a {@code float} field value from the stream. */ |
322 public float readFloat() throws IOException { | 214 public abstract float readFloat() throws IOException; |
323 return Float.intBitsToFloat(readRawLittleEndian32()); | |
324 } | |
325 | 215 |
326 /** Read a {@code uint64} field value from the stream. */ | 216 /** Read a {@code uint64} field value from the stream. */ |
327 public long readUInt64() throws IOException { | 217 public abstract long readUInt64() throws IOException; |
328 return readRawVarint64(); | |
329 } | |
330 | 218 |
331 /** Read an {@code int64} field value from the stream. */ | 219 /** Read an {@code int64} field value from the stream. */ |
332 public long readInt64() throws IOException { | 220 public abstract long readInt64() throws IOException; |
333 return readRawVarint64(); | |
334 } | |
335 | 221 |
336 /** Read an {@code int32} field value from the stream. */ | 222 /** Read an {@code int32} field value from the stream. */ |
337 public int readInt32() throws IOException { | 223 public abstract int readInt32() throws IOException; |
338 return readRawVarint32(); | |
339 } | |
340 | 224 |
341 /** Read a {@code fixed64} field value from the stream. */ | 225 /** Read a {@code fixed64} field value from the stream. */ |
342 public long readFixed64() throws IOException { | 226 public abstract long readFixed64() throws IOException; |
343 return readRawLittleEndian64(); | |
344 } | |
345 | 227 |
346 /** Read a {@code fixed32} field value from the stream. */ | 228 /** Read a {@code fixed32} field value from the stream. */ |
347 public int readFixed32() throws IOException { | 229 public abstract int readFixed32() throws IOException; |
348 return readRawLittleEndian32(); | |
349 } | |
350 | 230 |
351 /** Read a {@code bool} field value from the stream. */ | 231 /** Read a {@code bool} field value from the stream. */ |
352 public boolean readBool() throws IOException { | 232 public abstract boolean readBool() throws IOException; |
353 return readRawVarint64() != 0; | 233 |
354 } | 234 /** |
355 | 235 * Read a {@code string} field value from the stream. If the stream contains m
alformed UTF-8, |
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. | 236 * replace the offending bytes with the standard UTF-8 replacement character. |
360 */ | 237 */ |
361 public String readString() throws IOException { | 238 public abstract String readString() throws IOException; |
362 final int size = readRawVarint32(); | 239 |
363 if (size <= (bufferSize - bufferPos) && size > 0) { | 240 /** |
364 // Fast path: We already have the bytes in a contiguous buffer, so | 241 * Read a {@code string} field value from the stream. If the stream contains m
alformed UTF-8, |
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}. | 242 * throw exception {@link InvalidProtocolBufferException}. |
386 */ | 243 */ |
387 public String readStringRequireUtf8() throws IOException { | 244 public abstract 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 | 245 |
417 /** Read a {@code group} field value from the stream. */ | 246 /** Read a {@code group} field value from the stream. */ |
418 public void readGroup(final int fieldNumber, | 247 public abstract void readGroup( |
419 final MessageLite.Builder builder, | 248 final int fieldNumber, |
420 final ExtensionRegistryLite extensionRegistry) | 249 final MessageLite.Builder builder, |
421 throws IOException { | 250 final ExtensionRegistryLite extensionRegistry) |
422 if (recursionDepth >= recursionLimit) { | 251 throws IOException; |
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 | 252 |
432 | 253 |
433 /** Read a {@code group} field value from the stream. */ | 254 /** Read a {@code group} field value from the stream. */ |
434 public <T extends MessageLite> T readGroup( | 255 public abstract <T extends MessageLite> T readGroup( |
435 final int fieldNumber, | 256 final int fieldNumber, final Parser<T> parser, final ExtensionRegistryLite
extensionRegistry) |
436 final Parser<T> parser, | 257 throws IOException; |
437 final ExtensionRegistryLite extensionRegistry) | 258 |
438 throws IOException { | 259 /** |
439 if (recursionDepth >= recursionLimit) { | 260 * Reads a {@code group} field value from the stream and merges it into the gi
ven {@link |
440 throw InvalidProtocolBufferException.recursionLimitExceeded(); | 261 * UnknownFieldSet}. |
441 } | 262 * |
442 ++recursionDepth; | 263 * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so
you can just call |
443 T result = parser.parsePartialFrom(this, extensionRegistry); | 264 * {@link #readGroup}. |
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}. | |
456 */ | 265 */ |
457 @Deprecated | 266 @Deprecated |
458 public void readUnknownGroup(final int fieldNumber, | 267 public abstract void readUnknownGroup(final int fieldNumber, final MessageLite
.Builder builder) |
459 final MessageLite.Builder builder) | 268 throws IOException; |
460 throws IOException { | |
461 // We know that UnknownFieldSet will ignore any ExtensionRegistry so it | |
462 // is safe to pass null here. (We can't call | |
463 // ExtensionRegistry.getEmptyRegistry() because that would make this | |
464 // class depend on ExtensionRegistry, which is not part of the lite | |
465 // library.) | |
466 readGroup(fieldNumber, builder, null); | |
467 } | |
468 | 269 |
469 /** Read an embedded message field value from the stream. */ | 270 /** Read an embedded message field value from the stream. */ |
470 public void readMessage(final MessageLite.Builder builder, | 271 public abstract void readMessage( |
471 final ExtensionRegistryLite extensionRegistry) | 272 final MessageLite.Builder builder, final ExtensionRegistryLite extensionRe
gistry) |
472 throws IOException { | 273 throws IOException; |
473 final int length = readRawVarint32(); | |
474 if (recursionDepth >= recursionLimit) { | |
475 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
476 } | |
477 final int oldLimit = pushLimit(length); | |
478 ++recursionDepth; | |
479 builder.mergeFrom(this, extensionRegistry); | |
480 checkLastTagWas(0); | |
481 --recursionDepth; | |
482 popLimit(oldLimit); | |
483 } | |
484 | 274 |
485 | 275 |
486 /** Read an embedded message field value from the stream. */ | 276 /** Read an embedded message field value from the stream. */ |
487 public <T extends MessageLite> T readMessage( | 277 public abstract <T extends MessageLite> T readMessage( |
488 final Parser<T> parser, | 278 final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) thr
ows IOException; |
489 final ExtensionRegistryLite extensionRegistry) | |
490 throws IOException { | |
491 int length = readRawVarint32(); | |
492 if (recursionDepth >= recursionLimit) { | |
493 throw InvalidProtocolBufferException.recursionLimitExceeded(); | |
494 } | |
495 final int oldLimit = pushLimit(length); | |
496 ++recursionDepth; | |
497 T result = parser.parsePartialFrom(this, extensionRegistry); | |
498 checkLastTagWas(0); | |
499 --recursionDepth; | |
500 popLimit(oldLimit); | |
501 return result; | |
502 } | |
503 | 279 |
504 /** Read a {@code bytes} field value from the stream. */ | 280 /** Read a {@code bytes} field value from the stream. */ |
505 public ByteString readBytes() throws IOException { | 281 public abstract 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 } | |
522 | 282 |
523 /** Read a {@code bytes} field value from the stream. */ | 283 /** Read a {@code bytes} field value from the stream. */ |
524 public byte[] readByteArray() throws IOException { | 284 public abstract 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 } | |
538 | 285 |
539 /** Read a {@code bytes} field value from the stream. */ | 286 /** Read a {@code bytes} field value from the stream. */ |
540 public ByteBuffer readByteBuffer() throws IOException { | 287 public abstract 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 } | |
561 | 288 |
562 /** Read a {@code uint32} field value from the stream. */ | 289 /** Read a {@code uint32} field value from the stream. */ |
563 public int readUInt32() throws IOException { | 290 public abstract int readUInt32() throws IOException; |
564 return readRawVarint32(); | 291 |
565 } | 292 /** |
566 | 293 * Read an enum field value from the stream. Caller is responsible for convert
ing the numeric |
567 /** | 294 * value to an actual enum. |
568 * Read an enum field value from the stream. Caller is responsible | 295 */ |
569 * for converting the numeric value to an actual enum. | 296 public abstract int readEnum() throws IOException; |
570 */ | |
571 public int readEnum() throws IOException { | |
572 return readRawVarint32(); | |
573 } | |
574 | 297 |
575 /** Read an {@code sfixed32} field value from the stream. */ | 298 /** Read an {@code sfixed32} field value from the stream. */ |
576 public int readSFixed32() throws IOException { | 299 public abstract int readSFixed32() throws IOException; |
577 return readRawLittleEndian32(); | |
578 } | |
579 | 300 |
580 /** Read an {@code sfixed64} field value from the stream. */ | 301 /** Read an {@code sfixed64} field value from the stream. */ |
581 public long readSFixed64() throws IOException { | 302 public abstract long readSFixed64() throws IOException; |
582 return readRawLittleEndian64(); | |
583 } | |
584 | 303 |
585 /** Read an {@code sint32} field value from the stream. */ | 304 /** Read an {@code sint32} field value from the stream. */ |
586 public int readSInt32() throws IOException { | 305 public abstract int readSInt32() throws IOException; |
587 return decodeZigZag32(readRawVarint32()); | |
588 } | |
589 | 306 |
590 /** Read an {@code sint64} field value from the stream. */ | 307 /** Read an {@code sint64} field value from the stream. */ |
591 public long readSInt64() throws IOException { | 308 public abstract long readSInt64() throws IOException; |
592 return decodeZigZag64(readRawVarint64()); | |
593 } | |
594 | 309 |
595 // ================================================================= | 310 // ================================================================= |
596 | 311 |
597 /** | 312 /** Read a raw Varint from the stream. If larger than 32 bits, discard the upp
er bits. */ |
598 * Read a raw Varint from the stream. If larger than 32 bits, discard the | 313 public abstract int readRawVarint32() throws IOException; |
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 } | |
715 | 314 |
716 /** Read a raw Varint from the stream. */ | 315 /** Read a raw Varint from the stream. */ |
717 public long readRawVarint64() throws IOException { | 316 public abstract 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 } | |
774 | 317 |
775 /** Variant of readRawVarint64 for when uncomfortably close to the limit. */ | 318 /** Variant of readRawVarint64 for when uncomfortably close to the limit. */ |
776 /* Visible for testing */ | 319 /* Visible for testing */ |
777 long readRawVarint64SlowPath() throws IOException { | 320 abstract 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 } | |
788 | 321 |
789 /** Read a 32-bit little-endian integer from the stream. */ | 322 /** Read a 32-bit little-endian integer from the stream. */ |
790 public int readRawLittleEndian32() throws IOException { | 323 public abstract 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 } | |
806 | 324 |
807 /** Read a 64-bit little-endian integer from the stream. */ | 325 /** Read a 64-bit little-endian integer from the stream. */ |
808 public long readRawLittleEndian64() throws IOException { | 326 public abstract 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 } | |
856 | 327 |
857 // ----------------------------------------------------------------- | 328 // ----------------------------------------------------------------- |
858 | 329 |
859 private final byte[] buffer; | 330 /** |
860 private final boolean bufferIsImmutable; | 331 * Enables {@link ByteString} aliasing of the underlying buffer, trading off o
n buffer pinning for |
861 private int bufferSize; | 332 * data copies. Only valid for buffer-backed streams. |
862 private int bufferSizeAfterLimit; | 333 */ |
863 private int bufferPos; | 334 public abstract void enableAliasing(boolean enabled); |
864 private final InputStream input; | 335 |
865 private int lastTag; | 336 /** |
866 private boolean enableAliasing = false; | 337 * Set the maximum message recursion depth. In order to prevent malicious mess
ages from causing |
867 | 338 * stack overflows, {@code CodedInputStream} limits how deeply messages may be
nested. The default |
868 /** | 339 * limit is 64. |
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. | |
918 * | 340 * |
919 * @return the old limit. | 341 * @return the old limit. |
920 */ | 342 */ |
921 public int setRecursionLimit(final int limit) { | 343 public final int setRecursionLimit(final int limit) { |
922 if (limit < 0) { | 344 if (limit < 0) { |
923 throw new IllegalArgumentException( | 345 throw new IllegalArgumentException("Recursion limit cannot be negative: "
+ limit); |
924 "Recursion limit cannot be negative: " + limit); | |
925 } | 346 } |
926 final int oldLimit = recursionLimit; | 347 final int oldLimit = recursionLimit; |
927 recursionLimit = limit; | 348 recursionLimit = limit; |
928 return oldLimit; | 349 return oldLimit; |
929 } | 350 } |
930 | 351 |
931 /** | 352 /** |
932 * Set the maximum message size. In order to prevent malicious | 353 * Only valid for {@link InputStream}-backed streams. |
933 * messages from exhausting memory or causing integer overflows, | 354 * |
934 * {@code CodedInputStream} limits how large a message may be. | 355 * <p>Set the maximum message size. In order to prevent malicious messages fro
m exhausting memory |
935 * The default limit is 64MB. You should set this limit as small | 356 * or causing integer overflows, {@code CodedInputStream} limits how large a m
essage may be. The |
936 * as you can without harming your app's functionality. Note that | 357 * default limit is 64MB. You should set this limit as small as you can withou
t harming your app's |
937 * size limits only apply when reading from an {@code InputStream}, not | 358 * functionality. Note that size limits only apply when reading from an {@code
InputStream}, not |
938 * when constructed around a raw byte array (nor with | 359 * when constructed around a raw byte array (nor with {@link ByteString#newCod
edInput}). |
939 * {@link ByteString#newCodedInput}). | 360 * |
940 * <p> | 361 * <p>If you want to read several messages from a single CodedInputStream, you
could call {@link |
941 * If you want to read several messages from a single CodedInputStream, you | 362 * #resetSizeCounter()} after each one to avoid hitting the size limit. |
942 * could call {@link #resetSizeCounter()} after each one to avoid hitting the | |
943 * size limit. | |
944 * | 363 * |
945 * @return the old limit. | 364 * @return the old limit. |
946 */ | 365 */ |
947 public int setSizeLimit(final int limit) { | 366 public final int setSizeLimit(final int limit) { |
948 if (limit < 0) { | 367 if (limit < 0) { |
949 throw new IllegalArgumentException( | 368 throw new IllegalArgumentException("Size limit cannot be negative: " + lim
it); |
950 "Size limit cannot be negative: " + limit); | |
951 } | 369 } |
952 final int oldLimit = sizeLimit; | 370 final int oldLimit = sizeLimit; |
953 sizeLimit = limit; | 371 sizeLimit = limit; |
954 return oldLimit; | 372 return oldLimit; |
955 } | 373 } |
956 | 374 |
957 /** | 375 /** |
958 * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). | 376 * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). O
nly valid for {@link |
| 377 * InputStream}-backed streams. |
959 */ | 378 */ |
960 public void resetSizeCounter() { | 379 public abstract void resetSizeCounter(); |
961 totalBytesRetired = -bufferPos; | |
962 } | |
963 | 380 |
964 /** | 381 /** |
965 * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This | 382 * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This i
s called when |
966 * is called when descending into a length-delimited embedded message. | 383 * descending into a length-delimited embedded message. |
967 * | 384 * |
968 * <p>Note that {@code pushLimit()} does NOT affect how many bytes the | 385 * <p>Note that {@code pushLimit()} does NOT affect how many bytes the {@code
CodedInputStream} |
969 * {@code CodedInputStream} reads from an underlying {@code InputStream} when | 386 * reads from an underlying {@code InputStream} when refreshing its buffer. If
you need to prevent |
970 * refreshing its buffer. If you need to prevent reading past a certain | 387 * reading past a certain point in the underlying {@code InputStream} (e.g. be
cause you expect it |
971 * point in the underlying {@code InputStream} (e.g. because you expect it to | 388 * to contain more data after the end of the message which you need to handle
differently) then |
972 * contain more data after the end of the message which you need to handle | 389 * you must place a wrapper around your {@code InputStream} which limits the a
mount of data that |
973 * differently) then you must place a wrapper around your {@code InputStream} | 390 * can be read from it. |
974 * which limits the amount of data that can be read from it. | |
975 * | 391 * |
976 * @return the old limit. | 392 * @return the old limit. |
977 */ | 393 */ |
978 public int pushLimit(int byteLimit) throws InvalidProtocolBufferException { | 394 public abstract int pushLimit(int byteLimit) throws InvalidProtocolBufferExcep
tion; |
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 } | |
1005 | 395 |
1006 /** | 396 /** |
1007 * Discards the current limit, returning to the previous limit. | 397 * Discards the current limit, returning to the previous limit. |
1008 * | 398 * |
1009 * @param oldLimit The old limit, as returned by {@code pushLimit}. | 399 * @param oldLimit The old limit, as returned by {@code pushLimit}. |
1010 */ | 400 */ |
1011 public void popLimit(final int oldLimit) { | 401 public abstract void popLimit(final int oldLimit); |
1012 currentLimit = oldLimit; | 402 |
1013 recomputeBufferSizeAfterLimit(); | 403 /** |
| 404 * Returns the number of bytes to be read before the current limit. If no limi
t is set, returns |
| 405 * -1. |
| 406 */ |
| 407 public abstract int getBytesUntilLimit(); |
| 408 |
| 409 /** |
| 410 * Returns true if the stream has reached the end of the input. This is the ca
se if either the end |
| 411 * of the underlying input source has been reached or if the stream has reache
d a limit created |
| 412 * using {@link #pushLimit(int)}. |
| 413 */ |
| 414 public abstract boolean isAtEnd() throws IOException; |
| 415 |
| 416 /** |
| 417 * The total bytes read up to the current position. Calling {@link #resetSizeC
ounter()} resets |
| 418 * this value to zero. |
| 419 */ |
| 420 public abstract int getTotalBytesRead(); |
| 421 |
| 422 /** |
| 423 * Read one byte from the input. |
| 424 * |
| 425 * @throws InvalidProtocolBufferException The end of the stream or the current
limit was reached. |
| 426 */ |
| 427 public abstract byte readRawByte() throws IOException; |
| 428 |
| 429 /** |
| 430 * Read a fixed size of bytes from the input. |
| 431 * |
| 432 * @throws InvalidProtocolBufferException The end of the stream or the current
limit was reached. |
| 433 */ |
| 434 public abstract byte[] readRawBytes(final int size) throws IOException; |
| 435 |
| 436 /** |
| 437 * Reads and discards {@code size} bytes. |
| 438 * |
| 439 * @throws InvalidProtocolBufferException The end of the stream or the current
limit was reached. |
| 440 */ |
| 441 public abstract void skipRawBytes(final int size) throws IOException; |
| 442 |
| 443 /** |
| 444 * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers into v
alues that can be |
| 445 * efficiently encoded with varint. (Otherwise, negative values must be sign-e
xtended to 64 bits |
| 446 * to be varint encoded, thus always taking 10 bytes on the wire.) |
| 447 * |
| 448 * @param n An unsigned 32-bit integer, stored in a signed int because Java ha
s no explicit |
| 449 * unsigned support. |
| 450 * @return A signed 32-bit integer. |
| 451 */ |
| 452 public static int decodeZigZag32(final int n) { |
| 453 return (n >>> 1) ^ -(n & 1); |
1014 } | 454 } |
1015 | 455 |
1016 /** | 456 /** |
1017 * Returns the number of bytes to be read before the current limit. | 457 * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into v
alues that can be |
1018 * If no limit is set, returns -1. | 458 * efficiently encoded with varint. (Otherwise, negative values must be sign-e
xtended to 64 bits |
| 459 * to be varint encoded, thus always taking 10 bytes on the wire.) |
| 460 * |
| 461 * @param n An unsigned 64-bit integer, stored in a signed int because Java ha
s no explicit |
| 462 * unsigned support. |
| 463 * @return A signed 64-bit integer. |
1019 */ | 464 */ |
1020 public int getBytesUntilLimit() { | 465 public static long decodeZigZag64(final long n) { |
1021 if (currentLimit == Integer.MAX_VALUE) { | 466 return (n >>> 1) ^ -(n & 1); |
1022 return -1; | |
1023 } | |
1024 | |
1025 final int currentAbsolutePosition = totalBytesRetired + bufferPos; | |
1026 return currentLimit - currentAbsolutePosition; | |
1027 } | 467 } |
1028 | 468 |
1029 /** | 469 /** |
1030 * Returns true if the stream has reached the end of the input. This is the | 470 * Like {@link #readRawVarint32(InputStream)}, but expects that the caller has
already read one |
1031 * case if either the end of the underlying input source has been reached or | 471 * byte. This allows the caller to determine if EOF has been reached before at
tempting to read. |
1032 * if the stream has reached a limit created using {@link #pushLimit(int)}. | |
1033 */ | 472 */ |
1034 public boolean isAtEnd() throws IOException { | 473 public static int readRawVarint32(final int firstByte, final InputStream input
) |
1035 return bufferPos == bufferSize && !tryRefillBuffer(1); | 474 throws IOException { |
| 475 if ((firstByte & 0x80) == 0) { |
| 476 return firstByte; |
| 477 } |
| 478 |
| 479 int result = firstByte & 0x7f; |
| 480 int offset = 7; |
| 481 for (; offset < 32; offset += 7) { |
| 482 final int b = input.read(); |
| 483 if (b == -1) { |
| 484 throw InvalidProtocolBufferException.truncatedMessage(); |
| 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(); |
1036 } | 502 } |
1037 | 503 |
1038 /** | 504 /** |
1039 * The total bytes read up to the current position. Calling | 505 * Reads a varint from the input one byte at a time, so that it does not read
any bytes after the |
1040 * {@link #resetSizeCounter()} resets this value to zero. | 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. |
1041 */ | 509 */ |
1042 public int getTotalBytesRead() { | 510 static int readRawVarint32(final InputStream input) throws IOException { |
1043 return totalBytesRetired + bufferPos; | 511 final int firstByte = input.read(); |
| 512 if (firstByte == -1) { |
| 513 throw InvalidProtocolBufferException.truncatedMessage(); |
| 514 } |
| 515 return readRawVarint32(firstByte, input); |
1044 } | 516 } |
1045 | 517 |
1046 private interface RefillCallback { | 518 /** A {@link CodedInputStream} implementation that uses a backing array as the
input. */ |
1047 void onRefill(); | 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 } |
| 653 } |
| 654 } |
| 655 |
| 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 } |
1048 } | 1202 } |
1049 | 1203 |
1050 private RefillCallback refillCallback = null; | |
1051 | |
1052 /** | 1204 /** |
1053 * Reads more bytes from the input, making at least {@code n} bytes available | 1205 * A {@link CodedInputStream} implementation that uses a backing direct ByteBu
ffer as the input. |
1054 * in the buffer. Caller must ensure that the requested space is not yet | 1206 * Requires the use of {@code sun.misc.Unsafe} to perform fast reads on the bu
ffer. |
1055 * available, and that the requested space is less than BUFFER_SIZE. | |
1056 * | |
1057 * @throws InvalidProtocolBufferException The end of the stream or the current | |
1058 * limit was reached. | |
1059 */ | 1207 */ |
1060 private void refillBuffer(int n) throws IOException { | 1208 private static final class UnsafeDirectNioDecoder extends CodedInputStream { |
1061 if (!tryRefillBuffer(n)) { | 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 } |
1062 throw InvalidProtocolBufferException.truncatedMessage(); | 1444 throw InvalidProtocolBufferException.truncatedMessage(); |
1063 } | 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 } |
1064 } | 1967 } |
1065 | 1968 |
1066 /** | 1969 /** |
1067 * Tries to read more bytes from the input, making at least {@code n} bytes | 1970 * Implementation of {@link CodedInputStream} that uses an {@link InputStream}
as the data source. |
1068 * available in the buffer. Caller must ensure that the requested space is | |
1069 * not yet available, and that the requested space is less than BUFFER_SIZE. | |
1070 * | |
1071 * @return {@code true} if the bytes could be made available; {@code false} | |
1072 * if the end of the stream or the current limit was reached. | |
1073 */ | 1971 */ |
1074 private boolean tryRefillBuffer(int n) throws IOException { | 1972 private static final class StreamDecoder extends CodedInputStream { |
1075 if (bufferPos + n <= bufferSize) { | 1973 private final InputStream input; |
1076 throw new IllegalStateException( | 1974 private final byte[] buffer; |
1077 "refillBuffer() called when " + n + | 1975 /** bufferSize represents how many bytes are currently filled in the buffer
*/ |
1078 " bytes were already available in buffer"); | 1976 private int bufferSize; |
1079 } | 1977 |
1080 | 1978 private int bufferSizeAfterLimit; |
1081 if (totalBytesRetired + bufferPos + n > currentLimit) { | 1979 private int pos; |
1082 // Oops, we hit a limit. | 1980 private int lastTag; |
1083 return false; | 1981 |
1084 } | 1982 /** |
1085 | 1983 * The total number of bytes read before the current buffer. The total bytes
read up to the |
1086 if (refillCallback != null) { | 1984 * current position can be computed as {@code totalBytesRetired + pos}. This
value may be |
1087 refillCallback.onRefill(); | 1985 * negative if reading started in the middle of the current buffer (e.g. if
the constructor that |
1088 } | 1986 * takes a byte array and an offset was used). |
1089 | 1987 */ |
1090 if (input != null) { | 1988 private int totalBytesRetired; |
1091 int pos = bufferPos; | 1989 |
1092 if (pos > 0) { | 1990 /** The absolute position of the end of the current message. */ |
1093 if (bufferSize > pos) { | 1991 private int currentLimit = Integer.MAX_VALUE; |
1094 System.arraycopy(buffer, pos, buffer, 0, bufferSize - pos); | 1992 |
1095 } | 1993 private StreamDecoder(final InputStream input, int bufferSize) { |
1096 totalBytesRetired += pos; | 1994 checkNotNull(input, "input"); |
1097 bufferSize -= pos; | 1995 this.input = input; |
1098 bufferPos = 0; | 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; |
1099 } | 2713 } |
1100 | 2714 |
1101 int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize)
; | 2715 int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize)
; |
1102 if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) { | 2716 if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) { |
1103 throw new IllegalStateException( | 2717 throw new IllegalStateException( |
1104 "InputStream#read(byte[]) returned invalid result: " + bytesRead + | 2718 "InputStream#read(byte[]) returned invalid result: " |
1105 "\nThe InputStream implementation is buggy."); | 2719 + bytesRead |
| 2720 + "\nThe InputStream implementation is buggy."); |
1106 } | 2721 } |
1107 if (bytesRead > 0) { | 2722 if (bytesRead > 0) { |
1108 bufferSize += bytesRead; | 2723 bufferSize += bytesRead; |
1109 // Integer-overflow-conscious check against sizeLimit | 2724 // Integer-overflow-conscious check against sizeLimit |
1110 if (totalBytesRetired + n - sizeLimit > 0) { | 2725 if (totalBytesRetired + n - sizeLimit > 0) { |
1111 throw InvalidProtocolBufferException.sizeLimitExceeded(); | 2726 throw InvalidProtocolBufferException.sizeLimitExceeded(); |
1112 } | 2727 } |
1113 recomputeBufferSizeAfterLimit(); | 2728 recomputeBufferSizeAfterLimit(); |
1114 return (bufferSize >= n) ? true : tryRefillBuffer(n); | 2729 return (bufferSize >= n) ? true : tryRefillBuffer(n); |
1115 } | 2730 } |
1116 } | 2731 |
1117 | 2732 return false; |
1118 return false; | 2733 } |
1119 } | 2734 |
1120 | 2735 @Override |
1121 /** | 2736 public byte readRawByte() throws IOException { |
1122 * Read one byte from the input. | 2737 if (pos == bufferSize) { |
1123 * | 2738 refillBuffer(1); |
1124 * @throws InvalidProtocolBufferException The end of the stream or the current | 2739 } |
1125 * limit was reached. | 2740 return buffer[pos++]; |
1126 */ | 2741 } |
1127 public byte readRawByte() throws IOException { | 2742 |
1128 if (bufferPos == bufferSize) { | 2743 @Override |
1129 refillBuffer(1); | 2744 public byte[] readRawBytes(final int size) throws IOException { |
1130 } | 2745 final int tempPos = pos; |
1131 return buffer[bufferPos++]; | 2746 if (size <= (bufferSize - tempPos) && size > 0) { |
1132 } | 2747 pos = tempPos + size; |
1133 | 2748 return Arrays.copyOfRange(buffer, tempPos, tempPos + size); |
1134 /** | 2749 } else { |
1135 * Read a fixed size of bytes from the input. | 2750 return readRawBytesSlowPath(size); |
1136 * | 2751 } |
1137 * @throws InvalidProtocolBufferException The end of the stream or the current | 2752 } |
1138 * limit was reached. | 2753 |
1139 */ | 2754 /** |
1140 public byte[] readRawBytes(final int size) throws IOException { | 2755 * Exactly like readRawBytes, but caller must have already checked the fast
path: (size <= |
1141 final int pos = bufferPos; | 2756 * (bufferSize - pos) && size > 0) |
1142 if (size <= (bufferSize - pos) && size > 0) { | 2757 */ |
1143 bufferPos = pos + size; | 2758 private byte[] readRawBytesSlowPath(final int size) throws IOException { |
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) { | |
1156 if (size == 0) { | 2759 if (size == 0) { |
1157 return Internal.EMPTY_BYTE_ARRAY; | 2760 return Internal.EMPTY_BYTE_ARRAY; |
| 2761 } |
| 2762 if (size < 0) { |
| 2763 throw InvalidProtocolBufferException.negativeSize(); |
| 2764 } |
| 2765 |
| 2766 // Integer-overflow-conscious check that the message size so far has not e
xceeded sizeLimit. |
| 2767 int currentMessageSize = totalBytesRetired + pos + size; |
| 2768 if (currentMessageSize - sizeLimit > 0) { |
| 2769 throw InvalidProtocolBufferException.sizeLimitExceeded(); |
| 2770 } |
| 2771 |
| 2772 // Verify that the message size so far has not exceeded currentLimit. |
| 2773 if (currentMessageSize > currentLimit) { |
| 2774 // Read to the end of the stream anyway. |
| 2775 skipRawBytes(currentLimit - totalBytesRetired - pos); |
| 2776 throw InvalidProtocolBufferException.truncatedMessage(); |
| 2777 } |
| 2778 |
| 2779 final int originalBufferPos = pos; |
| 2780 final int bufferedBytes = bufferSize - pos; |
| 2781 |
| 2782 // Mark the current buffer consumed. |
| 2783 totalBytesRetired += bufferSize; |
| 2784 pos = 0; |
| 2785 bufferSize = 0; |
| 2786 |
| 2787 // Determine the number of bytes we need to read from the input stream. |
| 2788 int sizeLeft = size - bufferedBytes; |
| 2789 // TODO(nathanmittler): Consider using a value larger than DEFAULT_BUFFER_
SIZE. |
| 2790 if (sizeLeft < DEFAULT_BUFFER_SIZE || sizeLeft <= input.available()) { |
| 2791 // Either the bytes we need are known to be available, or the required b
uffer is |
| 2792 // within an allowed threshold - go ahead and allocate the buffer now. |
| 2793 final byte[] bytes = new byte[size]; |
| 2794 |
| 2795 // Copy all of the buffered bytes to the result buffer. |
| 2796 System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes); |
| 2797 |
| 2798 // Fill the remaining bytes from the input stream. |
| 2799 int tempPos = bufferedBytes; |
| 2800 while (tempPos < bytes.length) { |
| 2801 int n = input.read(bytes, tempPos, size - tempPos); |
| 2802 if (n == -1) { |
| 2803 throw InvalidProtocolBufferException.truncatedMessage(); |
| 2804 } |
| 2805 totalBytesRetired += n; |
| 2806 tempPos += n; |
| 2807 } |
| 2808 |
| 2809 return bytes; |
| 2810 } |
| 2811 |
| 2812 // The size is very large. For security reasons, we can't allocate the |
| 2813 // entire byte array yet. The size comes directly from the input, so a |
| 2814 // maliciously-crafted message could provide a bogus very large size in |
| 2815 // order to trick the app into allocating a lot of memory. We avoid this |
| 2816 // by allocating and reading only a small chunk at a time, so that the |
| 2817 // malicious message must actually *be* extremely large to cause |
| 2818 // problems. Meanwhile, we limit the allowed size of a message elsewhere. |
| 2819 final List<byte[]> chunks = new ArrayList<byte[]>(); |
| 2820 |
| 2821 while (sizeLeft > 0) { |
| 2822 // TODO(nathanmittler): Consider using a value larger than DEFAULT_BUFFE
R_SIZE. |
| 2823 final byte[] chunk = new byte[Math.min(sizeLeft, DEFAULT_BUFFER_SIZE)]; |
| 2824 int tempPos = 0; |
| 2825 while (tempPos < chunk.length) { |
| 2826 final int n = input.read(chunk, tempPos, chunk.length - tempPos); |
| 2827 if (n == -1) { |
| 2828 throw InvalidProtocolBufferException.truncatedMessage(); |
| 2829 } |
| 2830 totalBytesRetired += n; |
| 2831 tempPos += n; |
| 2832 } |
| 2833 sizeLeft -= chunk.length; |
| 2834 chunks.add(chunk); |
| 2835 } |
| 2836 |
| 2837 // OK, got everything. Now concatenate it all into one buffer. |
| 2838 final byte[] bytes = new byte[size]; |
| 2839 |
| 2840 // Start by copying the leftover bytes from this.buffer. |
| 2841 System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes); |
| 2842 |
| 2843 // And now all the chunks. |
| 2844 int tempPos = bufferedBytes; |
| 2845 for (final byte[] chunk : chunks) { |
| 2846 System.arraycopy(chunk, 0, bytes, tempPos, chunk.length); |
| 2847 tempPos += chunk.length; |
| 2848 } |
| 2849 |
| 2850 // Done. |
| 2851 return bytes; |
| 2852 } |
| 2853 |
| 2854 @Override |
| 2855 public void skipRawBytes(final int size) throws IOException { |
| 2856 if (size <= (bufferSize - pos) && size >= 0) { |
| 2857 // We have all the bytes we need already. |
| 2858 pos += size; |
1158 } else { | 2859 } else { |
| 2860 skipRawBytesSlowPath(size); |
| 2861 } |
| 2862 } |
| 2863 |
| 2864 /** |
| 2865 * Exactly like skipRawBytes, but caller must have already checked the fast
path: (size <= |
| 2866 * (bufferSize - pos) && size >= 0) |
| 2867 */ |
| 2868 private void skipRawBytesSlowPath(final int size) throws IOException { |
| 2869 if (size < 0) { |
1159 throw InvalidProtocolBufferException.negativeSize(); | 2870 throw InvalidProtocolBufferException.negativeSize(); |
1160 } | 2871 } |
1161 } | 2872 |
1162 | 2873 if (totalBytesRetired + pos + size > currentLimit) { |
1163 // Verify that the message size so far has not exceeded sizeLimit. | 2874 // Read to the end of the stream anyway. |
1164 int currentMessageSize = totalBytesRetired + bufferPos + size; | 2875 skipRawBytes(currentLimit - totalBytesRetired - pos); |
1165 if (currentMessageSize > sizeLimit) { | 2876 // Then fail. |
1166 throw InvalidProtocolBufferException.sizeLimitExceeded(); | 2877 throw InvalidProtocolBufferException.truncatedMessage(); |
1167 } | 2878 } |
1168 | 2879 |
1169 // Verify that the message size so far has not exceeded currentLimit. | 2880 // Skipping more bytes than are in the buffer. First skip what we have. |
1170 if (currentMessageSize > currentLimit) { | 2881 int tempPos = bufferSize - pos; |
1171 // Read to the end of the stream anyway. | 2882 pos = bufferSize; |
1172 skipRawBytes(currentLimit - totalBytesRetired - bufferPos); | 2883 |
1173 throw InvalidProtocolBufferException.truncatedMessage(); | 2884 // Keep refilling the buffer until we get to the point we wanted to skip t
o. |
1174 } | 2885 // This has the side effect of ensuring the limits are updated correctly. |
1175 | |
1176 // We need the input stream to proceed. | |
1177 if (input == null) { | |
1178 throw InvalidProtocolBufferException.truncatedMessage(); | |
1179 } | |
1180 | |
1181 final int originalBufferPos = bufferPos; | |
1182 final int bufferedBytes = bufferSize - bufferPos; | |
1183 | |
1184 // Mark the current buffer consumed. | |
1185 totalBytesRetired += bufferSize; | |
1186 bufferPos = 0; | |
1187 bufferSize = 0; | |
1188 | |
1189 // Determine the number of bytes we need to read from the input stream. | |
1190 int sizeLeft = size - bufferedBytes; | |
1191 // TODO(nathanmittler): Consider using a value larger than BUFFER_SIZE. | |
1192 if (sizeLeft < BUFFER_SIZE || sizeLeft <= input.available()) { | |
1193 // Either the bytes we need are known to be available, or the required buf
fer is | |
1194 // within an allowed threshold - go ahead and allocate the buffer now. | |
1195 final byte[] bytes = new byte[size]; | |
1196 | |
1197 // Copy all of the buffered bytes to the result buffer. | |
1198 System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes); | |
1199 | |
1200 // Fill the remaining bytes from the input stream. | |
1201 int pos = bufferedBytes; | |
1202 while (pos < bytes.length) { | |
1203 int n = input.read(bytes, pos, size - pos); | |
1204 if (n == -1) { | |
1205 throw InvalidProtocolBufferException.truncatedMessage(); | |
1206 } | |
1207 totalBytesRetired += n; | |
1208 pos += n; | |
1209 } | |
1210 | |
1211 return bytes; | |
1212 } | |
1213 | |
1214 // The size is very large. For security reasons, we can't allocate the | |
1215 // entire byte array yet. The size comes directly from the input, so a | |
1216 // maliciously-crafted message could provide a bogus very large size in | |
1217 // order to trick the app into allocating a lot of memory. We avoid this | |
1218 // by allocating and reading only a small chunk at a time, so that the | |
1219 // malicious message must actually *be* extremely large to cause | |
1220 // problems. Meanwhile, we limit the allowed size of a message elsewhere. | |
1221 final List<byte[]> chunks = new ArrayList<byte[]>(); | |
1222 | |
1223 while (sizeLeft > 0) { | |
1224 // TODO(nathanmittler): Consider using a value larger than BUFFER_SIZE. | |
1225 final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)]; | |
1226 int pos = 0; | |
1227 while (pos < chunk.length) { | |
1228 final int n = input.read(chunk, pos, chunk.length - pos); | |
1229 if (n == -1) { | |
1230 throw InvalidProtocolBufferException.truncatedMessage(); | |
1231 } | |
1232 totalBytesRetired += n; | |
1233 pos += n; | |
1234 } | |
1235 sizeLeft -= chunk.length; | |
1236 chunks.add(chunk); | |
1237 } | |
1238 | |
1239 // OK, got everything. Now concatenate it all into one buffer. | |
1240 final byte[] bytes = new byte[size]; | |
1241 | |
1242 // Start by copying the leftover bytes from this.buffer. | |
1243 System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes); | |
1244 | |
1245 // And now all the chunks. | |
1246 int pos = bufferedBytes; | |
1247 for (final byte[] chunk : chunks) { | |
1248 System.arraycopy(chunk, 0, bytes, pos, chunk.length); | |
1249 pos += chunk.length; | |
1250 } | |
1251 | |
1252 // Done. | |
1253 return bytes; | |
1254 } | |
1255 | |
1256 /** | |
1257 * Reads and discards {@code size} bytes. | |
1258 * | |
1259 * @throws InvalidProtocolBufferException The end of the stream or the current | |
1260 * limit was reached. | |
1261 */ | |
1262 public void skipRawBytes(final int size) throws IOException { | |
1263 if (size <= (bufferSize - bufferPos) && size >= 0) { | |
1264 // We have all the bytes we need already. | |
1265 bufferPos += size; | |
1266 } else { | |
1267 skipRawBytesSlowPath(size); | |
1268 } | |
1269 } | |
1270 | |
1271 /** | |
1272 * Exactly like skipRawBytes, but caller must have already checked the fast | |
1273 * path: (size <= (bufferSize - pos) && size >= 0) | |
1274 */ | |
1275 private void skipRawBytesSlowPath(final int size) throws IOException { | |
1276 if (size < 0) { | |
1277 throw InvalidProtocolBufferException.negativeSize(); | |
1278 } | |
1279 | |
1280 if (totalBytesRetired + bufferPos + size > currentLimit) { | |
1281 // Read to the end of the stream anyway. | |
1282 skipRawBytes(currentLimit - totalBytesRetired - bufferPos); | |
1283 // Then fail. | |
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; | |
1297 refillBuffer(1); | 2886 refillBuffer(1); |
1298 } | 2887 while (size - tempPos > bufferSize) { |
1299 | 2888 tempPos += bufferSize; |
1300 bufferPos = size - pos; | 2889 pos = bufferSize; |
| 2890 refillBuffer(1); |
| 2891 } |
| 2892 |
| 2893 pos = size - tempPos; |
| 2894 } |
1301 } | 2895 } |
1302 } | 2896 } |
OLD | NEW |