001 // Protocol Buffers - Google's data interchange format
002 // Copyright 2008 Google Inc.
003 // http://code.google.com/p/protobuf/
004 //
005 // Licensed under the Apache License, Version 2.0 (the "License");
006 // you may not use this file except in compliance with the License.
007 // You may obtain a copy of the License at
008 //
009 // http://www.apache.org/licenses/LICENSE-2.0
010 //
011 // Unless required by applicable law or agreed to in writing, software
012 // distributed under the License is distributed on an "AS IS" BASIS,
013 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 // See the License for the specific language governing permissions and
015 // limitations under the License.
016
017 package org.fusesource.hawtbuf.proto;
018
019 import java.io.EOFException;
020 import java.io.FilterInputStream;
021 import java.io.IOException;
022 import java.io.InputStream;
023
024 import org.fusesource.hawtbuf.Buffer;
025 import org.fusesource.hawtbuf.BufferInputStream;
026
027 /**
028 * Reads and decodes protocol message fields.
029 *
030 * This class contains two kinds of methods: methods that read specific protocol
031 * message constructs and field types (e.g. {@link #readTag()} and
032 * {@link #readInt32()}) and methods that read low-level values (e.g.
033 * {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading
034 * encoded protocol messages, you should use the former methods, but if you are
035 * reading some other format of your own design, use the latter.
036 *
037 * @author kenton@google.com Kenton Varda
038 */
039 public final class CodedInputStream extends FilterInputStream {
040
041 private int lastTag = 0;
042 private int limit = Integer.MAX_VALUE;
043 private int pos;
044 private BufferInputStream bis;
045
046 public CodedInputStream(InputStream in) {
047 super(in);
048 if( in.getClass() == BufferInputStream.class ) {
049 bis = (BufferInputStream)in;
050 }
051 }
052
053 public CodedInputStream(Buffer data) {
054 this(new BufferInputStream(data));
055 limit = data.length;
056 }
057
058 public CodedInputStream(byte[] data) {
059 this(new BufferInputStream(data));
060 limit = data.length;
061 }
062
063 /**
064 * Attempt to read a field tag, returning zero if we have reached EOF.
065 * Protocol message parsers use this to read tags, since a protocol message
066 * may legally end wherever a tag occurs, and zero is not a valid tag
067 * number.
068 */
069 public int readTag() throws IOException {
070 if( pos >= limit ) {
071 lastTag=0;
072 return 0;
073 }
074 try {
075 lastTag = readRawVarint32();
076 if (lastTag == 0) {
077 // If we actually read zero, that's not a valid tag.
078 throw InvalidProtocolBufferException.invalidTag();
079 }
080 return lastTag;
081 } catch (EOFException e) {
082 lastTag=0;
083 return 0;
084 }
085 }
086
087
088 /**
089 * Verifies that the last call to readTag() returned the given tag value.
090 * This is used to verify that a nested group ended with the correct end
091 * tag.
092 *
093 * @throws InvalidProtocolBufferException
094 * {@code value} does not match the last tag.
095 */
096 public void checkLastTagWas(int value) throws InvalidProtocolBufferException {
097 if (lastTag != value) {
098 throw InvalidProtocolBufferException.invalidEndTag();
099 }
100 }
101
102 /**
103 * Reads and discards a single field, given its tag value.
104 *
105 * @return {@code false} if the tag is an endgroup tag, in which case
106 * nothing is skipped. Otherwise, returns {@code true}.
107 */
108 public boolean skipField(int tag) throws IOException {
109 switch (WireFormat.getTagWireType(tag)) {
110 case WireFormat.WIRETYPE_VARINT:
111 readInt32();
112 return true;
113 case WireFormat.WIRETYPE_FIXED64:
114 readRawLittleEndian64();
115 return true;
116 case WireFormat.WIRETYPE_LENGTH_DELIMITED:
117 skipRawBytes(readRawVarint32());
118 return true;
119 case WireFormat.WIRETYPE_START_GROUP:
120 skipMessage();
121 checkLastTagWas(WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP));
122 return true;
123 case WireFormat.WIRETYPE_END_GROUP:
124 return false;
125 case WireFormat.WIRETYPE_FIXED32:
126 readRawLittleEndian32();
127 return true;
128 default:
129 throw InvalidProtocolBufferException.invalidWireType();
130 }
131 }
132
133 /**
134 * Reads and discards an entire message. This will read either until EOF or
135 * until an endgroup tag, whichever comes first.
136 */
137 public void skipMessage() throws IOException {
138 while (true) {
139 int tag = readTag();
140 if (tag == 0 || !skipField(tag))
141 return;
142 }
143 }
144
145 // -----------------------------------------------------------------
146
147 /** Read a {@code double} field value from the stream. */
148 public double readDouble() throws IOException {
149 return Double.longBitsToDouble(readRawLittleEndian64());
150 }
151
152 /** Read a {@code float} field value from the stream. */
153 public float readFloat() throws IOException {
154 return Float.intBitsToFloat(readRawLittleEndian32());
155 }
156
157 /** Read a {@code uint64} field value from the stream. */
158 public long readUInt64() throws IOException {
159 return readRawVarint64();
160 }
161
162 /** Read an {@code int64} field value from the stream. */
163 public long readInt64() throws IOException {
164 return readRawVarint64();
165 }
166
167 /** Read an {@code int32} field value from the stream. */
168 public int readInt32() throws IOException {
169 return readRawVarint32();
170 }
171
172 /** Read a {@code fixed64} field value from the stream. */
173 public long readFixed64() throws IOException {
174 return readRawLittleEndian64();
175 }
176
177 /** Read a {@code fixed32} field value from the stream. */
178 public int readFixed32() throws IOException {
179 return readRawLittleEndian32();
180 }
181
182 /** Read a {@code bool} field value from the stream. */
183 public boolean readBool() throws IOException {
184 return readRawVarint32() != 0;
185 }
186
187 /** Read a {@code string} field value from the stream. */
188 public String readString() throws IOException {
189 int size = readRawVarint32();
190 Buffer data = readRawBytes(size);
191 return new String(data.data, data.offset, data.length, "UTF-8");
192 }
193
194 /** Read a {@code bytes} field value from the stream. */
195 public Buffer readBytes() throws IOException {
196 int size = readRawVarint32();
197 return readRawBytes(size);
198 }
199
200 /** Read a {@code uint32} field value from the stream. */
201 public int readUInt32() throws IOException {
202 return readRawVarint32();
203 }
204
205 /**
206 * Read an enum field value from the stream. Caller is responsible for
207 * converting the numeric value to an actual enum.
208 */
209 public int readEnum() throws IOException {
210 return readRawVarint32();
211 }
212
213 /** Read an {@code sfixed32} field value from the stream. */
214 public int readSFixed32() throws IOException {
215 return readRawLittleEndian32();
216 }
217
218 /** Read an {@code sfixed64} field value from the stream. */
219 public long readSFixed64() throws IOException {
220 return readRawLittleEndian64();
221 }
222
223 /** Read an {@code sint32} field value from the stream. */
224 public int readSInt32() throws IOException {
225 return decodeZigZag32(readRawVarint32());
226 }
227
228 /** Read an {@code sint64} field value from the stream. */
229 public long readSInt64() throws IOException {
230 return decodeZigZag64(readRawVarint64());
231 }
232
233 // =================================================================
234
235 /**
236 * Read a raw Varint from the stream. If larger than 32 bits, discard the
237 * upper bits.
238 */
239 public int readRawVarint32() throws IOException {
240 byte tmp = readRawByte();
241 if (tmp >= 0) {
242 return tmp;
243 }
244 int result = tmp & 0x7f;
245 if ((tmp = readRawByte()) >= 0) {
246 result |= tmp << 7;
247 } else {
248 result |= (tmp & 0x7f) << 7;
249 if ((tmp = readRawByte()) >= 0) {
250 result |= tmp << 14;
251 } else {
252 result |= (tmp & 0x7f) << 14;
253 if ((tmp = readRawByte()) >= 0) {
254 result |= tmp << 21;
255 } else {
256 result |= (tmp & 0x7f) << 21;
257 result |= (tmp = readRawByte()) << 28;
258 if (tmp < 0) {
259 // Discard upper 32 bits.
260 for (int i = 0; i < 5; i++) {
261 if (readRawByte() >= 0)
262 return result;
263 }
264 throw InvalidProtocolBufferException.malformedVarint();
265 }
266 }
267 }
268 }
269 return result;
270 }
271
272 /** Read a raw Varint from the stream. */
273 public long readRawVarint64() throws IOException {
274 int shift = 0;
275 long result = 0;
276 while (shift < 64) {
277 byte b = readRawByte();
278 result |= (long) (b & 0x7F) << shift;
279 if ((b & 0x80) == 0)
280 return result;
281 shift += 7;
282 }
283 throw InvalidProtocolBufferException.malformedVarint();
284 }
285
286 /** Read a 32-bit little-endian integer from the stream. */
287 public int readRawLittleEndian32() throws IOException {
288 byte b1 = readRawByte();
289 byte b2 = readRawByte();
290 byte b3 = readRawByte();
291 byte b4 = readRawByte();
292 return (((int) b1 & 0xff)) | (((int) b2 & 0xff) << 8) | (((int) b3 & 0xff) << 16) | (((int) b4 & 0xff) << 24);
293 }
294
295 /** Read a 64-bit little-endian integer from the stream. */
296 public long readRawLittleEndian64() throws IOException {
297 byte b1 = readRawByte();
298 byte b2 = readRawByte();
299 byte b3 = readRawByte();
300 byte b4 = readRawByte();
301 byte b5 = readRawByte();
302 byte b6 = readRawByte();
303 byte b7 = readRawByte();
304 byte b8 = readRawByte();
305 return (((long) b1 & 0xff)) | (((long) b2 & 0xff) << 8) | (((long) b3 & 0xff) << 16) | (((long) b4 & 0xff) << 24) | (((long) b5 & 0xff) << 32) | (((long) b6 & 0xff) << 40) | (((long) b7 & 0xff) << 48) | (((long) b8 & 0xff) << 56);
306 }
307
308 /**
309 * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers into
310 * values that can be efficiently encoded with varint. (Otherwise, negative
311 * values must be sign-extended to 64 bits to be varint encoded, thus always
312 * taking 10 bytes on the wire.)
313 *
314 * @param n
315 * An unsigned 32-bit integer, stored in a signed int because
316 * Java has no explicit unsigned support.
317 * @return A signed 32-bit integer.
318 */
319 public static int decodeZigZag32(int n) {
320 return (n >>> 1) ^ -(n & 1);
321 }
322
323 /**
324 * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into
325 * values that can be efficiently encoded with varint. (Otherwise, negative
326 * values must be sign-extended to 64 bits to be varint encoded, thus always
327 * taking 10 bytes on the wire.)
328 *
329 * @param n
330 * An unsigned 64-bit integer, stored in a signed int because
331 * Java has no explicit unsigned support.
332 * @return A signed 64-bit integer.
333 */
334 public static long decodeZigZag64(long n) {
335 return (n >>> 1) ^ -(n & 1);
336 }
337
338 /**
339 * Read one byte from the input.
340 *
341 * @throws InvalidProtocolBufferException
342 * The end of the stream or the current limit was reached.
343 */
344 public byte readRawByte() throws IOException {
345 if( pos >= limit ) {
346 throw new EOFException();
347 }
348 int rc = in.read();
349 if( rc < 0 ) {
350 throw new EOFException();
351 }
352 pos++;
353 return (byte)( rc & 0xFF);
354 }
355
356 /**
357 * Read a fixed size of bytes from the input.
358 *
359 * @throws InvalidProtocolBufferException
360 * The end of the stream or the current limit was reached.
361 */
362 public Buffer readRawBytes(int size) throws IOException {
363 if( size == 0) {
364 return new Buffer(new byte[]{});
365 }
366 if( this.pos+size > limit ) {
367 throw new EOFException();
368 }
369
370 // If the underlying stream is a ByteArrayInputStream
371 // then we can avoid an array copy.
372 if( bis!=null ) {
373 Buffer rc = bis.readBuffer(size);
374 if( rc==null || rc.getLength() < size ) {
375 throw new EOFException();
376 }
377 this.pos += rc.getLength();
378 return rc;
379 }
380
381 // Otherwise we, have to do it the old fasioned way
382 byte[] rc = new byte[size];
383 int c;
384 int pos=0;
385 while( pos < size ) {
386 c = in.read(rc, pos, size-pos);
387 if( c < 0 ) {
388 throw new EOFException();
389 }
390 this.pos += c;
391 pos += c;
392 }
393
394 return new Buffer(rc);
395 }
396
397 /**
398 * Reads and discards {@code size} bytes.
399 *
400 * @throws InvalidProtocolBufferException
401 * The end of the stream or the current limit was reached.
402 */
403 public void skipRawBytes(int size) throws IOException {
404 int pos = 0;
405 while (pos < size) {
406 int n = (int) in.skip(size - pos);
407 pos += n;
408 }
409 }
410
411 public int pushLimit(int limit) {
412 int rc = this.limit;
413 this.limit = pos+limit;
414 return rc;
415 }
416
417 public void popLimit(int limit) {
418 this.limit = limit;
419 }
420
421 }