All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fusesource.hawtbuf.proto.CodedOutputStream Maven / Gradle / Ivy

The newest version!
//Protocol Buffers - Google's data interchange format
//Copyright 2008 Google Inc.
//http://code.google.com/p/protobuf/
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
package org.fusesource.hawtbuf.proto;

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.fusesource.hawtbuf.Buffer;
import org.fusesource.hawtbuf.BufferOutputStream;

/**
 * Encodes and writes protocol message fields.
 * 
 * 

* This class contains two kinds of methods: methods that write specific * protocol message constructs and field types (e.g. {@link #writeTag} and * {@link #writeInt32}) and methods that write low-level values (e.g. * {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are writing * encoded protocol messages, you should use the former methods, but if you are * writing some other format of your own design, use the latter. * *

* This class is totally unsynchronized. * * @author [email protected] Kenton Varda */ public final class CodedOutputStream extends FilterOutputStream { private BufferOutputStream bos; public CodedOutputStream(OutputStream os) { super(os); if( os instanceof BufferOutputStream ) { bos = (BufferOutputStream)os; } } public CodedOutputStream(byte[] data) { super(new BufferOutputStream(data)); } public CodedOutputStream(Buffer data) { super(new BufferOutputStream(data)); } // ----------------------------------------------------------------- /** Write a {@code double} field, including tag, to the stream. */ public void writeDouble(int fieldNumber, double value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); writeRawLittleEndian64(Double.doubleToRawLongBits(value)); } /** Write a {@code float} field, including tag, to the stream. */ public void writeFloat(int fieldNumber, float value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); writeRawLittleEndian32(Float.floatToRawIntBits(value)); } /** Write a {@code uint64} field, including tag, to the stream. */ public void writeUInt64(int fieldNumber, long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeRawVarint64(value); } /** Write an {@code int64} field, including tag, to the stream. */ public void writeInt64(int fieldNumber, long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeRawVarint64(value); } /** Write an {@code int32} field, including tag, to the stream. */ public void writeInt32(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); if (value >= 0) { writeRawVarint32(value); } else { // Must sign-extend. writeRawVarint64(value); } } /** Write a {@code fixed64} field, including tag, to the stream. */ public void writeFixed64(int fieldNumber, long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); writeRawLittleEndian64(value); } /** Write a {@code fixed32} field, including tag, to the stream. */ public void writeFixed32(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); writeRawLittleEndian32(value); } /** Write a {@code bool} field, including tag, to the stream. */ public void writeBool(int fieldNumber, boolean value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeRawByte(value ? 1 : 0); } /** Write a {@code string} field, including tag, to the stream. */ public void writeString(int fieldNumber, String value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); // Unfortunately there does not appear to be any way to tell Java to // encode // UTF-8 directly into our buffer, so we have to let it create its own // byte // array and then copy. byte[] bytes = value.getBytes("UTF-8"); writeRawVarint32(bytes.length); writeRawBytes(bytes); } /** Write a {@code bytes} field, including tag, to the stream. */ public void writeBytes(int fieldNumber, Buffer value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeRawVarint32(value.length); writeRawBytes(value.data, value.offset, value.length); } /** Write a {@code uint32} field, including tag, to the stream. */ public void writeUInt32(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeRawVarint32(value); } /** * Write an enum field, including tag, to the stream. Caller is responsible * for converting the enum value to its numeric value. */ public void writeEnum(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeRawVarint32(value); } /** Write an {@code sfixed32} field, including tag, to the stream. */ public void writeSFixed32(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); writeRawLittleEndian32(value); } /** Write an {@code sfixed64} field, including tag, to the stream. */ public void writeSFixed64(int fieldNumber, long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); writeRawLittleEndian64(value); } /** Write an {@code sint32} field, including tag, to the stream. */ public void writeSInt32(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeRawVarint32(encodeZigZag32(value)); } /** Write an {@code sint64} field, including tag, to the stream. */ public void writeSInt64(int fieldNumber, long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeRawVarint64(encodeZigZag64(value)); } // ================================================================= /** * Compute the number of bytes that would be needed to encode a {@code * double} field, including tag. */ public static int computeDoubleSize(int fieldNumber, double value) { return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE; } /** * Compute the number of bytes that would be needed to encode a {@code * float} field, including tag. */ public static int computeFloatSize(int fieldNumber, float value) { return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE; } /** * Compute the number of bytes that would be needed to encode a {@code * uint64} field, including tag. */ public static int computeUInt64Size(int fieldNumber, long value) { return computeTagSize(fieldNumber) + computeRawVarint64Size(value); } /** * Compute the number of bytes that would be needed to encode an {@code * int64} field, including tag. */ public static int computeInt64Size(int fieldNumber, long value) { return computeTagSize(fieldNumber) + computeRawVarint64Size(value); } /** * Compute the number of bytes that would be needed to encode an {@code * int32} field, including tag. */ public static int computeInt32Size(int fieldNumber, int value) { if (value >= 0) { return computeTagSize(fieldNumber) + computeRawVarint32Size(value); } else { // Must sign-extend. return computeTagSize(fieldNumber) + 10; } } /** * Compute the number of bytes that would be needed to encode a {@code * fixed64} field, including tag. */ public static int computeFixed64Size(int fieldNumber, long value) { return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE; } /** * Compute the number of bytes that would be needed to encode a {@code * fixed32} field, including tag. */ public static int computeFixed32Size(int fieldNumber, int value) { return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE; } /** * Compute the number of bytes that would be needed to encode a {@code bool} * field, including tag. */ public static int computeBoolSize(int fieldNumber, boolean value) { return computeTagSize(fieldNumber) + 1; } /** * Compute the number of bytes that would be needed to encode a {@code * string} field, including tag. */ public static int computeStringSize(int fieldNumber, String value) { try { byte[] bytes = value.getBytes("UTF-8"); return computeTagSize(fieldNumber) + computeRawVarint32Size(bytes.length) + bytes.length; } catch (java.io.UnsupportedEncodingException e) { throw new RuntimeException("UTF-8 not supported.", e); } } /** * Compute the number of bytes that would be needed to encode a {@code * bytes} field, including tag. */ public static int computeBytesSize(int fieldNumber, Buffer value) { return computeTagSize(fieldNumber) + computeRawVarint32Size(value.length) + value.length; } /** * Compute the number of bytes that would be needed to encode a {@code * uint32} field, including tag. */ public static int computeUInt32Size(int fieldNumber, int value) { return computeTagSize(fieldNumber) + computeRawVarint32Size(value); } /** * Compute the number of bytes that would be needed to encode an enum field, * including tag. Caller is responsible for converting the enum value to its * numeric value. */ public static int computeEnumSize(int fieldNumber, int value) { return computeTagSize(fieldNumber) + computeRawVarint32Size(value); } /** * Compute the number of bytes that would be needed to encode an {@code * sfixed32} field, including tag. */ public static int computeSFixed32Size(int fieldNumber, int value) { return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE; } /** * Compute the number of bytes that would be needed to encode an {@code * sfixed64} field, including tag. */ public static int computeSFixed64Size(int fieldNumber, long value) { return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE; } /** * Compute the number of bytes that would be needed to encode an {@code * sint32} field, including tag. */ public static int computeSInt32Size(int fieldNumber, int value) { return computeTagSize(fieldNumber) + computeRawVarint32Size(encodeZigZag32(value)); } /** * Compute the number of bytes that would be needed to encode an {@code * sint64} field, including tag. */ public static int computeSInt64Size(int fieldNumber, long value) { return computeTagSize(fieldNumber) + computeRawVarint64Size(encodeZigZag64(value)); } /** Write a single byte. */ public void writeRawByte(byte value) throws IOException { out.write(value); } /** Write a single byte, represented by an integer value. */ public void writeRawByte(int value) throws IOException { writeRawByte((byte) value); } /** Write an array of bytes. */ public void writeRawBytes(byte[] value) throws IOException { writeRawBytes(value, 0, value.length); } /** Write part of an array of bytes. */ public void writeRawBytes(byte[] value, int offset, int length) throws IOException { out.write(value, offset, length); } public void writeRawBytes(Buffer data) throws IOException { out.write(data.data, data.offset, data.length); } /** Encode and write a tag. */ public void writeTag(int fieldNumber, int wireType) throws IOException { writeRawVarint32(WireFormat.makeTag(fieldNumber, wireType)); } /** Compute the number of bytes that would be needed to encode a tag. */ public static int computeTagSize(int fieldNumber) { return computeRawVarint32Size(WireFormat.makeTag(fieldNumber, 0)); } /** * Encode and write a varint. {@code value} is treated as unsigned, so it * won't be sign-extended if negative. */ public void writeRawVarint32(int value) throws IOException { while (true) { if ((value & ~0x7F) == 0) { writeRawByte(value); return; } else { writeRawByte((value & 0x7F) | 0x80); value >>>= 7; } } } /** * Compute the number of bytes that would be needed to encode a varint. * {@code value} is treated as unsigned, so it won't be sign-extended if * negative. */ public static int computeRawVarint32Size(int value) { if ((value & (0xffffffff << 7)) == 0) return 1; if ((value & (0xffffffff << 14)) == 0) return 2; if ((value & (0xffffffff << 21)) == 0) return 3; if ((value & (0xffffffff << 28)) == 0) return 4; return 5; } /** Encode and write a varint. */ public void writeRawVarint64(long value) throws IOException { while (true) { if ((value & ~0x7FL) == 0) { writeRawByte((int) value); return; } else { writeRawByte(((int) value & 0x7F) | 0x80); value >>>= 7; } } } /** Compute the number of bytes that would be needed to encode a varint. */ public static int computeRawVarint64Size(long value) { if ((value & (0xffffffffffffffffL << 7)) == 0) return 1; if ((value & (0xffffffffffffffffL << 14)) == 0) return 2; if ((value & (0xffffffffffffffffL << 21)) == 0) return 3; if ((value & (0xffffffffffffffffL << 28)) == 0) return 4; if ((value & (0xffffffffffffffffL << 35)) == 0) return 5; if ((value & (0xffffffffffffffffL << 42)) == 0) return 6; if ((value & (0xffffffffffffffffL << 49)) == 0) return 7; if ((value & (0xffffffffffffffffL << 56)) == 0) return 8; if ((value & (0xffffffffffffffffL << 63)) == 0) return 9; return 10; } /** Write a little-endian 32-bit integer. */ public void writeRawLittleEndian32(int value) throws IOException { writeRawByte((value) & 0xFF); writeRawByte((value >> 8) & 0xFF); writeRawByte((value >> 16) & 0xFF); writeRawByte((value >> 24) & 0xFF); } public static final int LITTLE_ENDIAN_32_SIZE = 4; /** Write a little-endian 64-bit integer. */ public void writeRawLittleEndian64(long value) throws IOException { writeRawByte((int) (value) & 0xFF); writeRawByte((int) (value >> 8) & 0xFF); writeRawByte((int) (value >> 16) & 0xFF); writeRawByte((int) (value >> 24) & 0xFF); writeRawByte((int) (value >> 32) & 0xFF); writeRawByte((int) (value >> 40) & 0xFF); writeRawByte((int) (value >> 48) & 0xFF); writeRawByte((int) (value >> 56) & 0xFF); } public static final int LITTLE_ENDIAN_64_SIZE = 8; /** * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers into * values that can be efficiently encoded with varint. (Otherwise, negative * values must be sign-extended to 64 bits to be varint encoded, thus always * taking 10 bytes on the wire.) * * @param n * A signed 32-bit integer. * @return An unsigned 32-bit integer, stored in a signed int because Java * has no explicit unsigned support. */ public static int encodeZigZag32(int n) { // Note: the right-shift must be arithmetic return (n << 1) ^ (n >> 31); } /** * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into * values that can be efficiently encoded with varint. (Otherwise, negative * values must be sign-extended to 64 bits to be varint encoded, thus always * taking 10 bytes on the wire.) * * @param n * A signed 64-bit integer. * @return An unsigned 64-bit integer, stored in a signed int because Java * has no explicit unsigned support. */ public static long encodeZigZag64(long n) { // Note: the right-shift must be arithmetic return (n << 1) ^ (n >> 63); } public void checkNoSpaceLeft() { } public Buffer getNextBuffer(int size) throws IOException { if( bos==null ) { return null; } return bos.getNextBuffer(size); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy