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 }