001    package org.fusesource.hawtbuf.proto;
002    
003    import java.io.EOFException;
004    import java.io.IOException;
005    import java.io.InputStream;
006    import java.util.Collection;
007    
008    import org.fusesource.hawtbuf.Buffer;
009    import org.fusesource.hawtbuf.BufferOutputStream;
010    
011    
012    final public class MessageBufferSupport {
013    
014        public static final String FORZEN_ERROR_MESSAGE = "Modification not allowed after object has been fozen.  Try modifying a copy of this object.";
015        
016        static public Buffer toUnframedBuffer(MessageBuffer message) {
017            try {
018                int size = message.serializedSizeUnframed();
019                BufferOutputStream baos = new BufferOutputStream(size);
020                CodedOutputStream output = new CodedOutputStream(baos);
021                message.writeUnframed(output);
022                Buffer rc = baos.toBuffer();
023                assert rc.length == size : "Did not write as much data as expected.";
024                return rc;
025            } catch (IOException e) {
026                throw new RuntimeException("Serializing to a byte array threw an IOException " + "(should never happen).", e);
027            }
028        }
029    
030        static public Buffer toFramedBuffer(MessageBuffer message) {
031            try {
032                int size = message.serializedSizeFramed();
033                BufferOutputStream baos = new BufferOutputStream(size);
034                CodedOutputStream output = new CodedOutputStream(baos);
035                message.writeFramed(output);
036                Buffer rc = baos.toBuffer();
037                assert rc.length==size : "Did not write as much data as expected.";
038                return rc;
039            } catch (IOException e) {
040                throw new RuntimeException("Serializing to a byte array threw an IOException " + "(should never happen).", e);
041            }
042        }
043        
044        public static void writeMessage(CodedOutputStream output, int tag, MessageBuffer message) throws IOException {
045            output.writeTag(tag, WireFormat.WIRETYPE_LENGTH_DELIMITED);
046            message.writeFramed(output);
047        }
048    
049        public static int computeMessageSize(int tag, MessageBuffer message) {
050            return CodedOutputStream.computeTagSize(tag) + message.serializedSizeFramed();
051        }
052    
053        public static Buffer readFrame(java.io.InputStream input) throws IOException {
054            int length = 0;
055            try {
056                length = readRawVarint32(input);
057            } catch (InvalidProtocolBufferException e) {
058                if( e.isEOF() ) {
059                    throw new EOFException();
060                } else {
061                    throw e;
062                }
063            }
064    
065            byte[] data = new byte[length];
066            int pos = 0;
067            while (pos < length) {
068                int r = input.read(data, pos, length - pos);
069                if (r < 0) {
070                    throw new InvalidProtocolBufferException("Input stream ended before a full message frame could be read.");
071                }
072                pos += r;
073            }
074            return new Buffer(data);
075        }
076        
077        /**
078         * Read a raw Varint from the stream. If larger than 32 bits, discard the
079         * upper bits.
080         */
081        static public int readRawVarint32(InputStream is) throws IOException {
082            byte tmp = readRawByte(is);
083            if (tmp >= 0) {
084                return tmp;
085            }
086            int result = tmp & 0x7f;
087            if ((tmp = readRawByte(is)) >= 0) {
088                result |= tmp << 7;
089            } else {
090                result |= (tmp & 0x7f) << 7;
091                if ((tmp = readRawByte(is)) >= 0) {
092                    result |= tmp << 14;
093                } else {
094                    result |= (tmp & 0x7f) << 14;
095                    if ((tmp = readRawByte(is)) >= 0) {
096                        result |= tmp << 21;
097                    } else {
098                        result |= (tmp & 0x7f) << 21;
099                        result |= (tmp = readRawByte(is)) << 28;
100                        if (tmp < 0) {
101                            // Discard upper 32 bits.
102                            for (int i = 0; i < 5; i++) {
103                                if (readRawByte(is) >= 0)
104                                    return result;
105                            }
106                            throw new InvalidProtocolBufferException("CodedInputStream encountered a malformed varint.");
107                        }
108                    }
109                }
110            }
111            return result;
112        }
113        
114        static public byte readRawByte(InputStream is) throws IOException {
115            int rc = is.read();
116            if (rc == -1) {
117                throw new InvalidProtocolBufferException("While parsing a protocol message, the input ended unexpectedly " + "in the middle of a field.  This could mean either than the " + "input has been truncated or that an embedded message "
118                        + "misreported its own length.", true);
119            }
120            return (byte) rc;
121        }
122        
123        static public <T> void addAll(Iterable<T> values, Collection<? super T> list) {
124            if (values instanceof Collection) {
125                @SuppressWarnings("unsafe")
126                Collection<T> collection = (Collection<T>) values;
127                list.addAll(collection);
128            } else {
129                for (T value : values) {
130                    list.add(value);
131                }
132            }
133        }
134    
135    
136    }