ProtoOutputStream.java
package de.schegge.rosinante.io;
import java.io.ByteArrayOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.function.Function;
public class ProtoOutputStream extends FilterOutputStream {
public ProtoOutputStream(OutputStream out) {
super(out);
}
private void writeWireTypeAndFieldNumber(WireType wireType, int fieldNumber) throws IOException {
writeVariableByteInt(fieldNumber << 3 | wireType.ordinal() & 0b00000111);
}
protected void writeVariableByteInt(int number) throws IOException {
int continuationBytes = (31 - Integer.numberOfLeadingZeros(number)) / 7;
for (int i = 0; i < continuationBytes; ++i) {
write(((byte) ((number & 0x7F) | 0x80)));
number >>>= 7;
}
write((byte) number);
}
protected void writeVariableByteLong(long number) throws IOException {
int continuationBytes = (63 - Long.numberOfLeadingZeros(number)) / 7;
for (int i = 0; i < continuationBytes; ++i) {
write(((byte) ((number & 0x7F) | 0x80)));
number >>>= 7;
}
write((byte) number);
}
private <T> void writeRepeatedVarInt(int fieldNumber, List<T> values, Function<T, Integer> convert) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ProtoOutputStream protoOutputStream = new ProtoOutputStream(outputStream);
for (T value : values) {
protoOutputStream.writeVariableByteInt(convert.apply(value));
}
byte[] bytes = outputStream.toByteArray();
writeWireTypeAndFieldNumber(WireType.LEN, fieldNumber);
writeVariableByteInt(bytes.length);
write(bytes);
}
private void writeRepeatedVarLong(int fieldNumber, List<Long> values, Function<Long, Long> convert) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ProtoOutputStream protoOutputStream = new ProtoOutputStream(outputStream);
for (Long value : values) {
protoOutputStream.writeVariableByteLong(convert.apply(value));
}
byte[] bytes = outputStream.toByteArray();
writeWireTypeAndFieldNumber(WireType.LEN, fieldNumber);
writeVariableByteInt(bytes.length);
write(bytes);
}
public void writeBoolean(int fieldNumber, boolean value) throws IOException {
writeWireTypeAndFieldNumber(WireType.VARINT, fieldNumber);
writeVariableByteInt(value ? 1 : 0);
}
public void writeInteger(int fieldNumber, int value) throws IOException {
writeWireTypeAndFieldNumber(WireType.VARINT, fieldNumber);
writeVariableByteInt(value);
}
public void writeZigZagInteger(int fieldNumber, int value) throws IOException {
writeWireTypeAndFieldNumber(WireType.VARINT, fieldNumber);
writeVariableByteInt((value >> 31) ^ (value << 1));
}
public void writeLong(int fieldNumber, long value) throws IOException {
writeWireTypeAndFieldNumber(WireType.VARINT, fieldNumber);
writeVariableByteLong(value);
}
public void writeZigZagLong(int fieldNumber, long value) throws IOException {
writeWireTypeAndFieldNumber(WireType.VARINT, fieldNumber);
writeVariableByteLong((value >> 63) ^ (value << 1));
}
public void writeString(int fieldNumber, String test) throws IOException {
writeBytes(fieldNumber, test.getBytes(StandardCharsets.UTF_8));
}
public void writeBytes(int fieldNumber, byte[] bytes) throws IOException {
writeWireTypeAndFieldNumber(WireType.LEN, fieldNumber);
writeVariableByteInt(bytes.length);
write(bytes);
}
public void writeBoolean(int fieldNumber, List<Boolean> values) throws IOException {
writeRepeatedVarInt(fieldNumber, values, x -> x ? 1 : 0);
}
public void writeInteger(int fieldNumber, List<Integer> values) throws IOException {
writeRepeatedVarInt(fieldNumber, values, x -> x);
}
public void writeZigZagInteger(int fieldNumber, List<Integer> values) throws IOException {
writeRepeatedVarInt(fieldNumber, values, value -> (value >> 31) ^ (value << 1));
}
public void writeZigZagLong(int fieldNumber, List<Long> values) throws IOException {
writeRepeatedVarLong(fieldNumber, values, value -> (value >> 63) ^ (value << 1));
}
public void writeLong(int fieldNumber, List<Long> values) throws IOException {
writeRepeatedVarLong(fieldNumber, values, x -> x);
}
public void writeString(int fieldNumber, List<String> texts) throws IOException {
for (String text : texts) {
writeString(fieldNumber, text);
}
}
public void writeBytes(int fieldNumber, List<byte[]> bytess) throws IOException {
for (byte[] bytes : bytess) {
writeBytes(fieldNumber, bytes);
}
}
}