• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2013 Google Inc.  All rights reserved.
3 // http://code.google.com/p/protobuf/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 package com.google.protobuf.nano;
32 
33 import java.io.IOException;
34 
35 /**
36  * Reads and decodes protocol message fields.
37  *
38  * This class contains two kinds of methods:  methods that read specific
39  * protocol message constructs and field types (e.g. {@link #readTag()} and
40  * {@link #readInt32()}) and methods that read low-level values (e.g.
41  * {@link #readRawVarint32()} and {@link #readRawBytes}).  If you are reading
42  * encoded protocol messages, you should use the former methods, but if you are
43  * reading some other format of your own design, use the latter.
44  *
45  * @author kenton@google.com Kenton Varda
46  */
47 public final class CodedInputByteBufferNano {
48   /**
49    * Create a new CodedInputStream wrapping the given byte array.
50    */
newInstance(final byte[] buf)51   public static CodedInputByteBufferNano newInstance(final byte[] buf) {
52     return newInstance(buf, 0, buf.length);
53   }
54 
55   /**
56    * Create a new CodedInputStream wrapping the given byte array slice.
57    */
newInstance(final byte[] buf, final int off, final int len)58   public static CodedInputByteBufferNano newInstance(final byte[] buf, final int off,
59                                              final int len) {
60     return new CodedInputByteBufferNano(buf, off, len);
61   }
62 
63   // -----------------------------------------------------------------
64 
65   /**
66    * Attempt to read a field tag, returning zero if we have reached EOF.
67    * Protocol message parsers use this to read tags, since a protocol message
68    * may legally end wherever a tag occurs, and zero is not a valid tag number.
69    */
readTag()70   public int readTag() throws IOException {
71     if (isAtEnd()) {
72       lastTag = 0;
73       return 0;
74     }
75 
76     lastTag = readRawVarint32();
77     if (lastTag == 0) {
78       // If we actually read zero, that's not a valid tag.
79       throw InvalidProtocolBufferNanoException.invalidTag();
80     }
81     return lastTag;
82   }
83 
84   /**
85    * Verifies that the last call to readTag() returned the given tag value.
86    * This is used to verify that a nested group ended with the correct
87    * end tag.
88    *
89    * @throws InvalidProtocolBufferNanoException {@code value} does not match the
90    *                                        last tag.
91    */
checkLastTagWas(final int value)92   public void checkLastTagWas(final int value)
93                               throws InvalidProtocolBufferNanoException {
94     if (lastTag != value) {
95       throw InvalidProtocolBufferNanoException.invalidEndTag();
96     }
97   }
98 
99   /**
100    * Reads and discards a single field, given its tag value.
101    *
102    * @return {@code false} if the tag is an endgroup tag, in which case
103    *         nothing is skipped.  Otherwise, returns {@code true}.
104    */
skipField(final int tag)105   public boolean skipField(final int tag) throws IOException {
106     switch (WireFormatNano.getTagWireType(tag)) {
107       case WireFormatNano.WIRETYPE_VARINT:
108         readInt32();
109         return true;
110       case WireFormatNano.WIRETYPE_FIXED64:
111         readRawLittleEndian64();
112         return true;
113       case WireFormatNano.WIRETYPE_LENGTH_DELIMITED:
114         skipRawBytes(readRawVarint32());
115         return true;
116       case WireFormatNano.WIRETYPE_START_GROUP:
117         skipMessage();
118         checkLastTagWas(
119           WireFormatNano.makeTag(WireFormatNano.getTagFieldNumber(tag),
120                              WireFormatNano.WIRETYPE_END_GROUP));
121         return true;
122       case WireFormatNano.WIRETYPE_END_GROUP:
123         return false;
124       case WireFormatNano.WIRETYPE_FIXED32:
125         readRawLittleEndian32();
126         return true;
127       default:
128         throw InvalidProtocolBufferNanoException.invalidWireType();
129     }
130   }
131 
132   /**
133    * Reads and discards an entire message.  This will read either until EOF
134    * or until an endgroup tag, whichever comes first.
135    */
skipMessage()136   public void skipMessage() throws IOException {
137     while (true) {
138       final int tag = readTag();
139       if (tag == 0 || !skipField(tag)) {
140         return;
141       }
142     }
143   }
144 
145   // -----------------------------------------------------------------
146 
147   /** Read a {@code double} field value from the stream. */
readDouble()148   public double readDouble() throws IOException {
149     return Double.longBitsToDouble(readRawLittleEndian64());
150   }
151 
152   /** Read a {@code float} field value from the stream. */
readFloat()153   public float readFloat() throws IOException {
154     return Float.intBitsToFloat(readRawLittleEndian32());
155   }
156 
157   /** Read a {@code uint64} field value from the stream. */
readUInt64()158   public long readUInt64() throws IOException {
159     return readRawVarint64();
160   }
161 
162   /** Read an {@code int64} field value from the stream. */
readInt64()163   public long readInt64() throws IOException {
164     return readRawVarint64();
165   }
166 
167   /** Read an {@code int32} field value from the stream. */
readInt32()168   public int readInt32() throws IOException {
169     return readRawVarint32();
170   }
171 
172   /** Read a {@code fixed64} field value from the stream. */
readFixed64()173   public long readFixed64() throws IOException {
174     return readRawLittleEndian64();
175   }
176 
177   /** Read a {@code fixed32} field value from the stream. */
readFixed32()178   public int readFixed32() throws IOException {
179     return readRawLittleEndian32();
180   }
181 
182   /** Read a {@code bool} field value from the stream. */
readBool()183   public boolean readBool() throws IOException {
184     return readRawVarint32() != 0;
185   }
186 
187   /** Read a {@code string} field value from the stream. */
readString()188   public String readString() throws IOException {
189     final int size = readRawVarint32();
190     if (size <= (bufferSize - bufferPos) && size > 0) {
191       // Fast path:  We already have the bytes in a contiguous buffer, so
192       //   just copy directly from it.
193       final String result = new String(buffer, bufferPos, size, "UTF-8");
194       bufferPos += size;
195       return result;
196     } else {
197       // Slow path:  Build a byte array first then copy it.
198       return new String(readRawBytes(size), "UTF-8");
199     }
200   }
201 
202   /** Read a {@code group} field value from the stream. */
readGroup(final MessageNano msg, final int fieldNumber)203   public void readGroup(final MessageNano msg, final int fieldNumber)
204       throws IOException {
205     if (recursionDepth >= recursionLimit) {
206       throw InvalidProtocolBufferNanoException.recursionLimitExceeded();
207     }
208     ++recursionDepth;
209     msg.mergeFrom(this);
210     checkLastTagWas(
211       WireFormatNano.makeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP));
212     --recursionDepth;
213   }
214 
readMessage(final MessageNano msg)215   public void readMessage(final MessageNano msg)
216       throws IOException {
217     final int length = readRawVarint32();
218     if (recursionDepth >= recursionLimit) {
219       throw InvalidProtocolBufferNanoException.recursionLimitExceeded();
220     }
221     final int oldLimit = pushLimit(length);
222     ++recursionDepth;
223     msg.mergeFrom(this);
224     checkLastTagWas(0);
225     --recursionDepth;
226     popLimit(oldLimit);
227   }
228 
229   /** Read a {@code bytes} field value from the stream. */
readBytes()230   public byte[] readBytes() throws IOException {
231     final int size = readRawVarint32();
232     if (size <= (bufferSize - bufferPos) && size > 0) {
233       // Fast path:  We already have the bytes in a contiguous buffer, so
234       //   just copy directly from it.
235       final byte[] result = new byte[size];
236       System.arraycopy(buffer, bufferPos, result, 0, size);
237       bufferPos += size;
238       return result;
239     } else {
240       // Slow path:  Build a byte array first then copy it.
241       return readRawBytes(size);
242     }
243   }
244 
245   /** Read a {@code uint32} field value from the stream. */
readUInt32()246   public int readUInt32() throws IOException {
247     return readRawVarint32();
248   }
249 
250   /**
251    * Read an enum field value from the stream.  Caller is responsible
252    * for converting the numeric value to an actual enum.
253    */
readEnum()254   public int readEnum() throws IOException {
255     return readRawVarint32();
256   }
257 
258   /** Read an {@code sfixed32} field value from the stream. */
readSFixed32()259   public int readSFixed32() throws IOException {
260     return readRawLittleEndian32();
261   }
262 
263   /** Read an {@code sfixed64} field value from the stream. */
readSFixed64()264   public long readSFixed64() throws IOException {
265     return readRawLittleEndian64();
266   }
267 
268   /** Read an {@code sint32} field value from the stream. */
readSInt32()269   public int readSInt32() throws IOException {
270     return decodeZigZag32(readRawVarint32());
271   }
272 
273   /** Read an {@code sint64} field value from the stream. */
readSInt64()274   public long readSInt64() throws IOException {
275     return decodeZigZag64(readRawVarint64());
276   }
277 
278   // =================================================================
279 
280   /**
281    * Read a raw Varint from the stream.  If larger than 32 bits, discard the
282    * upper bits.
283    */
readRawVarint32()284   public int readRawVarint32() throws IOException {
285     byte tmp = readRawByte();
286     if (tmp >= 0) {
287       return tmp;
288     }
289     int result = tmp & 0x7f;
290     if ((tmp = readRawByte()) >= 0) {
291       result |= tmp << 7;
292     } else {
293       result |= (tmp & 0x7f) << 7;
294       if ((tmp = readRawByte()) >= 0) {
295         result |= tmp << 14;
296       } else {
297         result |= (tmp & 0x7f) << 14;
298         if ((tmp = readRawByte()) >= 0) {
299           result |= tmp << 21;
300         } else {
301           result |= (tmp & 0x7f) << 21;
302           result |= (tmp = readRawByte()) << 28;
303           if (tmp < 0) {
304             // Discard upper 32 bits.
305             for (int i = 0; i < 5; i++) {
306               if (readRawByte() >= 0) {
307                 return result;
308               }
309             }
310             throw InvalidProtocolBufferNanoException.malformedVarint();
311           }
312         }
313       }
314     }
315     return result;
316   }
317 
318   /** Read a raw Varint from the stream. */
readRawVarint64()319   public long readRawVarint64() throws IOException {
320     int shift = 0;
321     long result = 0;
322     while (shift < 64) {
323       final byte b = readRawByte();
324       result |= (long)(b & 0x7F) << shift;
325       if ((b & 0x80) == 0) {
326         return result;
327       }
328       shift += 7;
329     }
330     throw InvalidProtocolBufferNanoException.malformedVarint();
331   }
332 
333   /** Read a 32-bit little-endian integer from the stream. */
readRawLittleEndian32()334   public int readRawLittleEndian32() throws IOException {
335     final byte b1 = readRawByte();
336     final byte b2 = readRawByte();
337     final byte b3 = readRawByte();
338     final byte b4 = readRawByte();
339     return ((b1 & 0xff)      ) |
340            ((b2 & 0xff) <<  8) |
341            ((b3 & 0xff) << 16) |
342            ((b4 & 0xff) << 24);
343   }
344 
345   /** Read a 64-bit little-endian integer from the stream. */
readRawLittleEndian64()346   public long readRawLittleEndian64() throws IOException {
347     final byte b1 = readRawByte();
348     final byte b2 = readRawByte();
349     final byte b3 = readRawByte();
350     final byte b4 = readRawByte();
351     final byte b5 = readRawByte();
352     final byte b6 = readRawByte();
353     final byte b7 = readRawByte();
354     final byte b8 = readRawByte();
355     return (((long)b1 & 0xff)      ) |
356            (((long)b2 & 0xff) <<  8) |
357            (((long)b3 & 0xff) << 16) |
358            (((long)b4 & 0xff) << 24) |
359            (((long)b5 & 0xff) << 32) |
360            (((long)b6 & 0xff) << 40) |
361            (((long)b7 & 0xff) << 48) |
362            (((long)b8 & 0xff) << 56);
363   }
364 
365   /**
366    * Decode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
367    * into values that can be efficiently encoded with varint.  (Otherwise,
368    * negative values must be sign-extended to 64 bits to be varint encoded,
369    * thus always taking 10 bytes on the wire.)
370    *
371    * @param n An unsigned 32-bit integer, stored in a signed int because
372    *          Java has no explicit unsigned support.
373    * @return A signed 32-bit integer.
374    */
decodeZigZag32(final int n)375   public static int decodeZigZag32(final int n) {
376     return (n >>> 1) ^ -(n & 1);
377   }
378 
379   /**
380    * Decode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
381    * into values that can be efficiently encoded with varint.  (Otherwise,
382    * negative values must be sign-extended to 64 bits to be varint encoded,
383    * thus always taking 10 bytes on the wire.)
384    *
385    * @param n An unsigned 64-bit integer, stored in a signed int because
386    *          Java has no explicit unsigned support.
387    * @return A signed 64-bit integer.
388    */
decodeZigZag64(final long n)389   public static long decodeZigZag64(final long n) {
390     return (n >>> 1) ^ -(n & 1);
391   }
392 
393   // -----------------------------------------------------------------
394 
395   private final byte[] buffer;
396   private int bufferStart;
397   private int bufferSize;
398   private int bufferSizeAfterLimit;
399   private int bufferPos;
400   private int lastTag;
401 
402   /** The absolute position of the end of the current message. */
403   private int currentLimit = Integer.MAX_VALUE;
404 
405   /** See setRecursionLimit() */
406   private int recursionDepth;
407   private int recursionLimit = DEFAULT_RECURSION_LIMIT;
408 
409   /** See setSizeLimit() */
410   private int sizeLimit = DEFAULT_SIZE_LIMIT;
411 
412   private static final int DEFAULT_RECURSION_LIMIT = 64;
413   private static final int DEFAULT_SIZE_LIMIT = 64 << 20;  // 64MB
414 
CodedInputByteBufferNano(final byte[] buffer, final int off, final int len)415   private CodedInputByteBufferNano(final byte[] buffer, final int off, final int len) {
416     this.buffer = buffer;
417     bufferStart = off;
418     bufferSize = off + len;
419     bufferPos = off;
420   }
421 
422   /**
423    * Set the maximum message recursion depth.  In order to prevent malicious
424    * messages from causing stack overflows, {@code CodedInputStream} limits
425    * how deeply messages may be nested.  The default limit is 64.
426    *
427    * @return the old limit.
428    */
setRecursionLimit(final int limit)429   public int setRecursionLimit(final int limit) {
430     if (limit < 0) {
431       throw new IllegalArgumentException(
432         "Recursion limit cannot be negative: " + limit);
433     }
434     final int oldLimit = recursionLimit;
435     recursionLimit = limit;
436     return oldLimit;
437   }
438 
439   /**
440    * Set the maximum message size.  In order to prevent malicious
441    * messages from exhausting memory or causing integer overflows,
442    * {@code CodedInputStream} limits how large a message may be.
443    * The default limit is 64MB.  You should set this limit as small
444    * as you can without harming your app's functionality.  Note that
445    * size limits only apply when reading from an {@code InputStream}, not
446    * when constructed around a raw byte array.
447    * <p>
448    * If you want to read several messages from a single CodedInputStream, you
449    * could call {@link #resetSizeCounter()} after each one to avoid hitting the
450    * size limit.
451    *
452    * @return the old limit.
453    */
setSizeLimit(final int limit)454   public int setSizeLimit(final int limit) {
455     if (limit < 0) {
456       throw new IllegalArgumentException(
457         "Size limit cannot be negative: " + limit);
458     }
459     final int oldLimit = sizeLimit;
460     sizeLimit = limit;
461     return oldLimit;
462   }
463 
464   /**
465    * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
466    */
resetSizeCounter()467   public void resetSizeCounter() {
468   }
469 
470   /**
471    * Sets {@code currentLimit} to (current position) + {@code byteLimit}.  This
472    * is called when descending into a length-delimited embedded message.
473    *
474    * @return the old limit.
475    */
pushLimit(int byteLimit)476   public int pushLimit(int byteLimit) throws InvalidProtocolBufferNanoException {
477     if (byteLimit < 0) {
478       throw InvalidProtocolBufferNanoException.negativeSize();
479     }
480     byteLimit += bufferPos;
481     final int oldLimit = currentLimit;
482     if (byteLimit > oldLimit) {
483       throw InvalidProtocolBufferNanoException.truncatedMessage();
484     }
485     currentLimit = byteLimit;
486 
487     recomputeBufferSizeAfterLimit();
488 
489     return oldLimit;
490   }
491 
recomputeBufferSizeAfterLimit()492   private void recomputeBufferSizeAfterLimit() {
493     bufferSize += bufferSizeAfterLimit;
494     final int bufferEnd = bufferSize;
495     if (bufferEnd > currentLimit) {
496       // Limit is in current buffer.
497       bufferSizeAfterLimit = bufferEnd - currentLimit;
498       bufferSize -= bufferSizeAfterLimit;
499     } else {
500       bufferSizeAfterLimit = 0;
501     }
502   }
503 
504   /**
505    * Discards the current limit, returning to the previous limit.
506    *
507    * @param oldLimit The old limit, as returned by {@code pushLimit}.
508    */
popLimit(final int oldLimit)509   public void popLimit(final int oldLimit) {
510     currentLimit = oldLimit;
511     recomputeBufferSizeAfterLimit();
512   }
513 
514   /**
515    * Returns the number of bytes to be read before the current limit.
516    * If no limit is set, returns -1.
517    */
getBytesUntilLimit()518   public int getBytesUntilLimit() {
519     if (currentLimit == Integer.MAX_VALUE) {
520       return -1;
521     }
522 
523     final int currentAbsolutePosition = bufferPos;
524     return currentLimit - currentAbsolutePosition;
525   }
526 
527   /**
528    * Returns true if the stream has reached the end of the input.  This is the
529    * case if either the end of the underlying input source has been reached or
530    * if the stream has reached a limit created using {@link #pushLimit(int)}.
531    */
isAtEnd()532   public boolean isAtEnd() {
533     return bufferPos == bufferSize;
534   }
535 
536   /**
537    * Get current position in buffer relative to beginning offset.
538    */
getPosition()539   public int getPosition() {
540     return bufferPos - bufferStart;
541   }
542 
543   /**
544    * Retrieves a subset of data in the buffer. The returned array is not backed by the original
545    * buffer array.
546    *
547    * @param offset the position (relative to the buffer start position) to start at.
548    * @param length the number of bytes to retrieve.
549    */
getData(int offset, int length)550   public byte[] getData(int offset, int length) {
551     if (length == 0) {
552       return WireFormatNano.EMPTY_BYTES;
553     }
554     byte[] copy = new byte[length];
555     int start = bufferStart + offset;
556     System.arraycopy(buffer, start, copy, 0, length);
557     return copy;
558   }
559 
560   /**
561    * Rewind to previous position. Cannot go forward.
562    */
rewindToPosition(int position)563   public void rewindToPosition(int position) {
564     if (position > bufferPos - bufferStart) {
565       throw new IllegalArgumentException(
566               "Position " + position + " is beyond current " + (bufferPos - bufferStart));
567     }
568     if (position < 0) {
569       throw new IllegalArgumentException("Bad position " + position);
570     }
571     bufferPos = bufferStart + position;
572   }
573 
574   /**
575    * Read one byte from the input.
576    *
577    * @throws InvalidProtocolBufferNanoException The end of the stream or the current
578    *                                        limit was reached.
579    */
readRawByte()580   public byte readRawByte() throws IOException {
581     if (bufferPos == bufferSize) {
582       throw InvalidProtocolBufferNanoException.truncatedMessage();
583     }
584     return buffer[bufferPos++];
585   }
586 
587   /**
588    * Read a fixed size of bytes from the input.
589    *
590    * @throws InvalidProtocolBufferNanoException The end of the stream or the current
591    *                                        limit was reached.
592    */
readRawBytes(final int size)593   public byte[] readRawBytes(final int size) throws IOException {
594     if (size < 0) {
595       throw InvalidProtocolBufferNanoException.negativeSize();
596     }
597 
598     if (bufferPos + size > currentLimit) {
599       // Read to the end of the stream anyway.
600       skipRawBytes(currentLimit - bufferPos);
601       // Then fail.
602       throw InvalidProtocolBufferNanoException.truncatedMessage();
603     }
604 
605     if (size <= bufferSize - bufferPos) {
606       // We have all the bytes we need already.
607       final byte[] bytes = new byte[size];
608       System.arraycopy(buffer, bufferPos, bytes, 0, size);
609       bufferPos += size;
610       return bytes;
611     } else {
612       throw InvalidProtocolBufferNanoException.truncatedMessage();
613     }
614   }
615 
616   /**
617    * Reads and discards {@code size} bytes.
618    *
619    * @throws InvalidProtocolBufferNanoException The end of the stream or the current
620    *                                        limit was reached.
621    */
skipRawBytes(final int size)622   public void skipRawBytes(final int size) throws IOException {
623     if (size < 0) {
624       throw InvalidProtocolBufferNanoException.negativeSize();
625     }
626 
627     if (bufferPos + size > currentLimit) {
628       // Read to the end of the stream anyway.
629       skipRawBytes(currentLimit - bufferPos);
630       // Then fail.
631       throw InvalidProtocolBufferNanoException.truncatedMessage();
632     }
633 
634     if (size <= bufferSize - bufferPos) {
635       // We have all the bytes we need already.
636       bufferPos += size;
637     } else {
638       throw InvalidProtocolBufferNanoException.truncatedMessage();
639     }
640   }
641 }
642