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 }