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    }