• 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 < 0) {
191       throw InvalidProtocolBufferNanoException.negativeSize();
192     }
193     if (size > (bufferSize - bufferPos)) {
194       throw InvalidProtocolBufferNanoException.truncatedMessage();
195     }
196 
197     final String result = new String(buffer, bufferPos, size, "UTF-8");
198     bufferPos += size;
199     return result;
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 < 0) {
233       throw InvalidProtocolBufferNanoException.negativeSize();
234     }
235     if (size == 0) {
236       return WireFormatNano.EMPTY_BYTES;
237     }
238     if (size > (bufferSize - bufferPos)) {
239       throw InvalidProtocolBufferNanoException.truncatedMessage();
240     }
241 
242     final byte[] result = new byte[size];
243     System.arraycopy(buffer, bufferPos, result, 0, size);
244     bufferPos += size;
245     return result;
246   }
247 
248   /** Read a {@code uint32} field value from the stream. */
readUInt32()249   public int readUInt32() throws IOException {
250     return readRawVarint32();
251   }
252 
253   /**
254    * Read an enum field value from the stream.  Caller is responsible
255    * for converting the numeric value to an actual enum.
256    */
readEnum()257   public int readEnum() throws IOException {
258     return readRawVarint32();
259   }
260 
261   /** Read an {@code sfixed32} field value from the stream. */
readSFixed32()262   public int readSFixed32() throws IOException {
263     return readRawLittleEndian32();
264   }
265 
266   /** Read an {@code sfixed64} field value from the stream. */
readSFixed64()267   public long readSFixed64() throws IOException {
268     return readRawLittleEndian64();
269   }
270 
271   /** Read an {@code sint32} field value from the stream. */
readSInt32()272   public int readSInt32() throws IOException {
273     return decodeZigZag32(readRawVarint32());
274   }
275 
276   /** Read an {@code sint64} field value from the stream. */
readSInt64()277   public long readSInt64() throws IOException {
278     return decodeZigZag64(readRawVarint64());
279   }
280 
281   // =================================================================
282 
283   /**
284    * Read a raw Varint from the stream.  If larger than 32 bits, discard the
285    * upper bits.
286    */
readRawVarint32()287   public int readRawVarint32() throws IOException {
288     byte tmp = readRawByte();
289     if (tmp >= 0) {
290       return tmp;
291     }
292     int result = tmp & 0x7f;
293     if ((tmp = readRawByte()) >= 0) {
294       result |= tmp << 7;
295     } else {
296       result |= (tmp & 0x7f) << 7;
297       if ((tmp = readRawByte()) >= 0) {
298         result |= tmp << 14;
299       } else {
300         result |= (tmp & 0x7f) << 14;
301         if ((tmp = readRawByte()) >= 0) {
302           result |= tmp << 21;
303         } else {
304           result |= (tmp & 0x7f) << 21;
305           result |= (tmp = readRawByte()) << 28;
306           if (tmp < 0) {
307             // Discard upper 32 bits.
308             for (int i = 0; i < 5; i++) {
309               if (readRawByte() >= 0) {
310                 return result;
311               }
312             }
313             throw InvalidProtocolBufferNanoException.malformedVarint();
314           }
315         }
316       }
317     }
318     return result;
319   }
320 
321   /** Read a raw Varint from the stream. */
readRawVarint64()322   public long readRawVarint64() throws IOException {
323     int shift = 0;
324     long result = 0;
325     while (shift < 64) {
326       final byte b = readRawByte();
327       result |= (long)(b & 0x7F) << shift;
328       if ((b & 0x80) == 0) {
329         return result;
330       }
331       shift += 7;
332     }
333     throw InvalidProtocolBufferNanoException.malformedVarint();
334   }
335 
336   /** Read a 32-bit little-endian integer from the stream. */
readRawLittleEndian32()337   public int readRawLittleEndian32() throws IOException {
338     final byte b1 = readRawByte();
339     final byte b2 = readRawByte();
340     final byte b3 = readRawByte();
341     final byte b4 = readRawByte();
342     return ((b1 & 0xff)      ) |
343            ((b2 & 0xff) <<  8) |
344            ((b3 & 0xff) << 16) |
345            ((b4 & 0xff) << 24);
346   }
347 
348   /** Read a 64-bit little-endian integer from the stream. */
readRawLittleEndian64()349   public long readRawLittleEndian64() throws IOException {
350     final byte b1 = readRawByte();
351     final byte b2 = readRawByte();
352     final byte b3 = readRawByte();
353     final byte b4 = readRawByte();
354     final byte b5 = readRawByte();
355     final byte b6 = readRawByte();
356     final byte b7 = readRawByte();
357     final byte b8 = readRawByte();
358     return (((long)b1 & 0xff)      ) |
359            (((long)b2 & 0xff) <<  8) |
360            (((long)b3 & 0xff) << 16) |
361            (((long)b4 & 0xff) << 24) |
362            (((long)b5 & 0xff) << 32) |
363            (((long)b6 & 0xff) << 40) |
364            (((long)b7 & 0xff) << 48) |
365            (((long)b8 & 0xff) << 56);
366   }
367 
368   /**
369    * Decode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
370    * into values that can be efficiently encoded with varint.  (Otherwise,
371    * negative values must be sign-extended to 64 bits to be varint encoded,
372    * thus always taking 10 bytes on the wire.)
373    *
374    * @param n An unsigned 32-bit integer, stored in a signed int because
375    *          Java has no explicit unsigned support.
376    * @return A signed 32-bit integer.
377    */
decodeZigZag32(final int n)378   public static int decodeZigZag32(final int n) {
379     return (n >>> 1) ^ -(n & 1);
380   }
381 
382   /**
383    * Decode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
384    * into values that can be efficiently encoded with varint.  (Otherwise,
385    * negative values must be sign-extended to 64 bits to be varint encoded,
386    * thus always taking 10 bytes on the wire.)
387    *
388    * @param n An unsigned 64-bit integer, stored in a signed int because
389    *          Java has no explicit unsigned support.
390    * @return A signed 64-bit integer.
391    */
decodeZigZag64(final long n)392   public static long decodeZigZag64(final long n) {
393     return (n >>> 1) ^ -(n & 1);
394   }
395 
396   // -----------------------------------------------------------------
397 
398   private final byte[] buffer;
399   private int bufferStart;
400   private int bufferSize;
401   private int bufferSizeAfterLimit;
402   private int bufferPos;
403   private int lastTag;
404 
405   /** The absolute position of the end of the current message. */
406   private int currentLimit = Integer.MAX_VALUE;
407 
408   /** See setRecursionLimit() */
409   private int recursionDepth;
410   private int recursionLimit = DEFAULT_RECURSION_LIMIT;
411 
412   /** See setSizeLimit() */
413   private int sizeLimit = DEFAULT_SIZE_LIMIT;
414 
415   private static final int DEFAULT_RECURSION_LIMIT = 64;
416   private static final int DEFAULT_SIZE_LIMIT = 64 << 20;  // 64MB
417 
CodedInputByteBufferNano(final byte[] buffer, final int off, final int len)418   private CodedInputByteBufferNano(final byte[] buffer, final int off, final int len) {
419     this.buffer = buffer;
420     bufferStart = off;
421     bufferSize = off + len;
422     bufferPos = off;
423   }
424 
425   /**
426    * Set the maximum message recursion depth.  In order to prevent malicious
427    * messages from causing stack overflows, {@code CodedInputStream} limits
428    * how deeply messages may be nested.  The default limit is 64.
429    *
430    * @return the old limit.
431    */
setRecursionLimit(final int limit)432   public int setRecursionLimit(final int limit) {
433     if (limit < 0) {
434       throw new IllegalArgumentException(
435         "Recursion limit cannot be negative: " + limit);
436     }
437     final int oldLimit = recursionLimit;
438     recursionLimit = limit;
439     return oldLimit;
440   }
441 
442   /**
443    * Set the maximum message size.  In order to prevent malicious
444    * messages from exhausting memory or causing integer overflows,
445    * {@code CodedInputStream} limits how large a message may be.
446    * The default limit is 64MB.  You should set this limit as small
447    * as you can without harming your app's functionality.  Note that
448    * size limits only apply when reading from an {@code InputStream}, not
449    * when constructed around a raw byte array.
450    * <p>
451    * If you want to read several messages from a single CodedInputStream, you
452    * could call {@link #resetSizeCounter()} after each one to avoid hitting the
453    * size limit.
454    *
455    * @return the old limit.
456    */
setSizeLimit(final int limit)457   public int setSizeLimit(final int limit) {
458     if (limit < 0) {
459       throw new IllegalArgumentException(
460         "Size limit cannot be negative: " + limit);
461     }
462     final int oldLimit = sizeLimit;
463     sizeLimit = limit;
464     return oldLimit;
465   }
466 
467   /**
468    * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
469    */
resetSizeCounter()470   public void resetSizeCounter() {
471   }
472 
473   /**
474    * Sets {@code currentLimit} to (current position) + {@code byteLimit}.  This
475    * is called when descending into a length-delimited embedded message.
476    *
477    * @return the old limit.
478    */
pushLimit(int byteLimit)479   public int pushLimit(int byteLimit) throws InvalidProtocolBufferNanoException {
480     if (byteLimit < 0) {
481       throw InvalidProtocolBufferNanoException.negativeSize();
482     }
483     byteLimit += bufferPos;
484     final int oldLimit = currentLimit;
485     if (byteLimit > oldLimit) {
486       throw InvalidProtocolBufferNanoException.truncatedMessage();
487     }
488     currentLimit = byteLimit;
489 
490     recomputeBufferSizeAfterLimit();
491 
492     return oldLimit;
493   }
494 
recomputeBufferSizeAfterLimit()495   private void recomputeBufferSizeAfterLimit() {
496     bufferSize += bufferSizeAfterLimit;
497     final int bufferEnd = bufferSize;
498     if (bufferEnd > currentLimit) {
499       // Limit is in current buffer.
500       bufferSizeAfterLimit = bufferEnd - currentLimit;
501       bufferSize -= bufferSizeAfterLimit;
502     } else {
503       bufferSizeAfterLimit = 0;
504     }
505   }
506 
507   /**
508    * Discards the current limit, returning to the previous limit.
509    *
510    * @param oldLimit The old limit, as returned by {@code pushLimit}.
511    */
popLimit(final int oldLimit)512   public void popLimit(final int oldLimit) {
513     currentLimit = oldLimit;
514     recomputeBufferSizeAfterLimit();
515   }
516 
517   /**
518    * Returns the number of bytes to be read before the current limit.
519    * If no limit is set, returns -1.
520    */
getBytesUntilLimit()521   public int getBytesUntilLimit() {
522     if (currentLimit == Integer.MAX_VALUE) {
523       return -1;
524     }
525 
526     final int currentAbsolutePosition = bufferPos;
527     return currentLimit - currentAbsolutePosition;
528   }
529 
530   /**
531    * Returns true if the stream has reached the end of the input.  This is the
532    * case if either the end of the underlying input source has been reached or
533    * if the stream has reached a limit created using {@link #pushLimit(int)}.
534    */
isAtEnd()535   public boolean isAtEnd() {
536     return bufferPos == bufferSize;
537   }
538 
539   /**
540    * Get current position in buffer relative to beginning offset.
541    */
getPosition()542   public int getPosition() {
543     return bufferPos - bufferStart;
544   }
545 
546   /**
547    * Get current (absolute) position in buffer.
548    */
getAbsolutePosition()549   public int getAbsolutePosition() {
550     return bufferPos;
551   }
552 
553   /**
554    * Return the raw underlying data in the buffer, directly.
555    */
getBuffer()556   public byte[] getBuffer() {
557     return buffer;
558   }
559 
560   /**
561    * Retrieves a subset of data in the buffer. The returned array is not backed by the original
562    * buffer array.
563    *
564    * @param offset the position (relative to the buffer start position) to start at.
565    * @param length the number of bytes to retrieve.
566    */
getData(int offset, int length)567   public byte[] getData(int offset, int length) {
568     if (length == 0) {
569       return WireFormatNano.EMPTY_BYTES;
570     }
571     byte[] copy = new byte[length];
572     int start = bufferStart + offset;
573     System.arraycopy(buffer, start, copy, 0, length);
574     return copy;
575   }
576 
577   /**
578    * Rewind to previous position. Cannot go forward.
579    */
rewindToPosition(int position)580   public void rewindToPosition(int position) {
581     if (position > bufferPos - bufferStart) {
582       throw new IllegalArgumentException(
583               "Position " + position + " is beyond current " + (bufferPos - bufferStart));
584     }
585     if (position < 0) {
586       throw new IllegalArgumentException("Bad position " + position);
587     }
588     bufferPos = bufferStart + position;
589   }
590 
591   /**
592    * Read one byte from the input.
593    *
594    * @throws InvalidProtocolBufferNanoException The end of the stream or the current
595    *                                        limit was reached.
596    */
readRawByte()597   public byte readRawByte() throws IOException {
598     if (bufferPos == bufferSize) {
599       throw InvalidProtocolBufferNanoException.truncatedMessage();
600     }
601     return buffer[bufferPos++];
602   }
603 
604   /**
605    * Read a fixed size of bytes from the input.
606    *
607    * @throws InvalidProtocolBufferNanoException The end of the stream or the current
608    *                                        limit was reached.
609    */
readRawBytes(final int size)610   public byte[] readRawBytes(final int size) throws IOException {
611     if (size < 0) {
612       throw InvalidProtocolBufferNanoException.negativeSize();
613     }
614 
615     if (bufferPos + size > currentLimit) {
616       // Read to the end of the stream anyway.
617       skipRawBytes(currentLimit - bufferPos);
618       // Then fail.
619       throw InvalidProtocolBufferNanoException.truncatedMessage();
620     }
621 
622     if (size <= bufferSize - bufferPos) {
623       // We have all the bytes we need already.
624       final byte[] bytes = new byte[size];
625       System.arraycopy(buffer, bufferPos, bytes, 0, size);
626       bufferPos += size;
627       return bytes;
628     } else {
629       throw InvalidProtocolBufferNanoException.truncatedMessage();
630     }
631   }
632 
633   /**
634    * Reads and discards {@code size} bytes.
635    *
636    * @throws InvalidProtocolBufferNanoException The end of the stream or the current
637    *                                        limit was reached.
638    */
skipRawBytes(final int size)639   public void skipRawBytes(final int size) throws IOException {
640     if (size < 0) {
641       throw InvalidProtocolBufferNanoException.negativeSize();
642     }
643 
644     if (bufferPos + size > currentLimit) {
645       // Read to the end of the stream anyway.
646       skipRawBytes(currentLimit - bufferPos);
647       // Then fail.
648       throw InvalidProtocolBufferNanoException.truncatedMessage();
649     }
650 
651     if (size <= bufferSize - bufferPos) {
652       // We have all the bytes we need already.
653       bufferPos += size;
654     } else {
655       throw InvalidProtocolBufferNanoException.truncatedMessage();
656     }
657   }
658 }
659