package com.fasterxml.jackson.dataformat.protobuf;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.Charset;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.base.GeneratorBase;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.json.JsonWriteContext;
import com.fasterxml.jackson.core.util.JacksonFeatureSet;
import com.fasterxml.jackson.dataformat.protobuf.schema.FieldType;
import com.fasterxml.jackson.dataformat.protobuf.schema.ProtobufField;
import com.fasterxml.jackson.dataformat.protobuf.schema.ProtobufMessage;
import com.fasterxml.jackson.dataformat.protobuf.schema.ProtobufSchema;
import com.fasterxml.jackson.dataformat.protobuf.schema.WireType;
public class ProtobufGenerator extends GeneratorBase
{
protected final static JsonWriteContext BOGUS_WRITE_CONTEXT = JsonWriteContext.createRootContext(null);
protected final static ProtobufField UNKNOWN_FIELD = ProtobufField.unknownField();
protected final static ProtobufMessage UNKNOWN_MESSAGE = ProtobufMessage.bogusMessage("<unknown>");
final protected IOContext _ioContext;
protected ProtobufSchema _schema;
protected ProtobufWriteContext _rootContext;
protected boolean _inObject;
protected boolean _writeTag;
protected boolean _complete;
protected ProtobufMessage _currMessage;
protected ProtobufField _currField;
final protected OutputStream _output;
protected ByteAccumulator _buffered;
protected ProtobufWriteContext _pbContext;
protected byte[] _currBuffer;
protected byte[] _origCurrBuffer;
protected int _currStart;
protected int _currPtr;
public ProtobufGenerator(IOContext ctxt, int jsonFeatures,
ObjectCodec codec, OutputStream output)
throws IOException
{
super(jsonFeatures, codec, BOGUS_WRITE_CONTEXT);
_ioContext = ctxt;
_output = output;
_pbContext = _rootContext = ProtobufWriteContext.createNullContext();
_currBuffer = _origCurrBuffer = ctxt.allocWriteEncodingBuffer();
}
public void setSchema(ProtobufSchema schema)
{
if (_schema == schema) {
return;
}
_schema = schema;
_pbContext = _rootContext = ProtobufWriteContext.createRootContext(schema.getRootType());
}
@Override
public Object getCurrentValue() {
return _pbContext.getCurrentValue();
}
@Override
public void setCurrentValue(Object v) {
_pbContext.setCurrentValue(v);
}
@Override
public Version version() {
return PackageVersion.VERSION;
}
@Override
public boolean canWriteBinaryNatively() {
return true;
}
@Override
public JacksonFeatureSet<StreamWriteCapability> getWriteCapabilities() {
return DEFAULT_BINARY_WRITE_CAPABILITIES;
}
@Override
public boolean canUseSchema(FormatSchema schema) {
return (schema instanceof ProtobufSchema);
}
@Override
public ProtobufGenerator useDefaultPrettyPrinter() {
return this;
}
@Override
public ProtobufGenerator setPrettyPrinter(PrettyPrinter pp) {
return this;
}
@Override
public Object getOutputTarget() {
return _output;
}
@Override
public int getOutputBuffered() {
return -1;
}
@Override public ProtobufSchema getSchema() {
return _schema;
}
@Override
public void setSchema(FormatSchema schema)
{
if (!(schema instanceof ProtobufSchema)) {
throw new IllegalArgumentException("Can not use FormatSchema of type "
+schema.getClass().getName());
}
setSchema((ProtobufSchema) schema);
}
@Override
public final void writeFieldName(String name) throws IOException {
if (!_inObject) {
_reportError("Can not write field name: current context not Object but "+_pbContext.typeDesc());
}
ProtobufField f = _currField;
if (f != null && _pbContext.notArray()) {
f = f.nextIf(name);
if (f == null) {
f = _currMessage.field(name);
}
} else {
f = _currMessage.firstIf(name);
}
if (f == null) {
if ((_currMessage == UNKNOWN_MESSAGE)
|| isEnabled(JsonGenerator.Feature.IGNORE_UNKNOWN)) {
f = UNKNOWN_FIELD;
} else {
_reportError("Unrecognized field '"+name+"' (in Message of type "+_currMessage.getName()
+"); known fields are: "+_currMessage.fieldsAsString());
}
}
_pbContext.setField(f);
_currField = f;
}
@Override
public final void writeFieldName(SerializableString sstr) throws IOException {
if (!_inObject) {
_reportError("Can not write field name: current context not Object but "+_pbContext.typeDesc());
}
ProtobufField f = _currField;
final String name = sstr.getValue();
if (f != null && _pbContext.notArray()) {
f = f.nextIf(name);
if (f == null) {
f = _currMessage.field(name);
}
} else {
f = _currMessage.firstIf(name);
}
if (f == null) {
if ((_currMessage == UNKNOWN_MESSAGE)
|| isEnabled(JsonGenerator.Feature.IGNORE_UNKNOWN)) {
f = UNKNOWN_FIELD;
} else {
_reportError("Unrecognized field '"+name+"' (in Message of type "+_currMessage.getName()
+"); known fields are: "+_currMessage.fieldsAsString());
}
}
_pbContext.setField(f);
_currField = f;
}
@Override
public final void flush() throws IOException
{
if (_buffered == null) {
int start = _currStart;
int len = _currPtr - start;
if (len > 0) {
_currStart = 0;
_currPtr = 0;
_output.write(_currBuffer, start, len);
}
}
if (isEnabled(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM)) {
_output.flush();
}
}
@Override
public void close() throws IOException
{
super.close();
if (isEnabled(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT)) {
ProtobufWriteContext ctxt;
while ((ctxt = _pbContext) != null) {
if (ctxt.inArray()) {
writeEndArray();
} else if (ctxt.inObject()) {
writeEndObject();
} else {
break;
}
}
}
if (!_complete) {
_complete();
}
if (_output != null) {
if (_ioContext.isResourceManaged() || isEnabled(JsonGenerator.Feature.AUTO_CLOSE_TARGET)) {
_output.close();
} else if (isEnabled(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM)) {
_output.flush();
}
}
_releaseBuffers();
}
@Override
public final void writeStartArray() throws IOException
{
if (!_inObject) {
_reportError("Current context not an OBJECT, can not write arrays");
}
if (_currField == null) {
_reportError("Can not write START_ARRAY without field (message type "+_currMessage.getName()+")");
return;
}
if (!_currField.isArray()) {
_reportError("Can not write START_ARRAY: field '"+_currField.name+"' not declared as 'repeated'");
}
_pbContext = _pbContext.createChildArrayContext();
_writeTag = !_currField.packed;
if (!_writeTag) {
_startBuffering(_currField.typedTag);
}
}
@Override
public final void writeEndArray() throws IOException
{
if (!_pbContext.inArray()) {
_reportError("Current context not Array but "+_pbContext.typeDesc());
}
_pbContext = _pbContext.getParent();
if (_pbContext.inRoot()) {
if (!_complete) {
_complete();
}
_inObject = false;
} else {
_inObject = _pbContext.inObject();
}
_writeTag = true;
if (_currField.packed) {
_finishBuffering();
}
}
@Override
public final void writeStartObject() throws IOException
{
if (_currField == null) {
if (!_pbContext.inRoot()) {
_reportError("Can not write START_OBJECT without field (message type "+_currMessage.getName()+")");
}
_currMessage = _schema.getRootType();
} else {
if (!_currField.isObject) {
_reportError("Can not write START_OBJECT: type of field '"+_currField.name+"' not Message but: "+_currField.type);
}
_currMessage = _currField.getMessageType();
if (_writeTag) {
_startBuffering(_currField.typedTag);
} else {
_startBuffering();
}
}
if (_inObject) {
_pbContext = _pbContext.createChildObjectContext(_currMessage);
_currField = null;
} else {
_pbContext = _pbContext.createChildObjectContext(_currMessage);
_inObject = true;
}
_writeTag = true;
}
@Override
public final void writeEndObject() throws IOException
{
if (!_inObject) {
_reportError("Current context not Object but "+_pbContext.typeDesc());
}
_pbContext = _pbContext.getParent();
if (_pbContext.inRoot()) {
if (!_complete) {
_complete();
}
} else {
_currMessage = _pbContext.getMessageType();
}
_currField = _pbContext.getField();
boolean inObj = _pbContext.inObject();
_inObject = inObj;
_writeTag = inObj || !_pbContext.inArray() || !_currField.packed;
if (_buffered != null) {
_finishBuffering();
}
}
@Override
public void writeArray(int[] array, int offset, int length) throws IOException
{
_verifyArrayWrite(array);
_verifyOffsets(array.length, offset, length);
if (length > 0) {
final int end = offset+length;
if (_currField.packed) {
_writePackedArray(array, offset, end);
} else {
_writeNonPackedArray(array, offset, end);
}
_writeTag = true;
}
}
@Override
public void writeArray(long[] array, int offset, int length) throws IOException
{
_verifyArrayWrite(array);
_verifyOffsets(array.length, offset, length);
if (length > 0) {
final int end = offset+length;
if (_currField.packed) {
_writePackedArray(array, offset, end);
} else {
_writeNonPackedArray(array, offset, end);
}
_writeTag = true;
}
}
@Override
public void writeArray(double[] array, int offset, int length) throws IOException
{
_verifyArrayWrite(array);
_verifyOffsets(array.length, offset, length);
if (length > 0) {
final int end = offset+length;
if (_currField.packed) {
_writePackedArray(array, offset, end);
} else {
_writeNonPackedArray(array, offset, end);
}
_writeTag = true;
}
}
private void _verifyArrayWrite(Object array) throws IOException
{
if (array == null) {
throw new IllegalArgumentException("null array");
}
if (!_inObject) {
_reportError("Current context not an OBJECT, can not write arrays");
}
if (_currField == null) {
_reportError("Can not write START_ARRAY without field (message type "+_currMessage.getName()+")");
return;
}
if (!_currField.isArray()) {
_reportError("Can not write START_ARRAY: field '"+_currField.name+"' not declared as 'repeated'");
}
}
private void _writePackedArray(int[] array, int i, int end) throws IOException
{
_startBuffering(_currField.typedTag);
final int type = _currField.wireType;
if (type == WireType.VINT) {
final boolean zigzag = _currField.usesZigZag;
for (; i < end; ++i) {
int v = array[i];
if (zigzag) {
v = ProtobufUtil.zigzagEncode(v);
}
_writeVIntNoTag(v);
}
} else if (type == WireType.FIXED_32BIT) {
for (; i < end; ++i) {
_writeInt32NoTag(array[i]);
}
} else if (type == WireType.FIXED_64BIT) {
for (; i < end; ++i) {
_writeInt64NoTag(array[i]);
}
} else {
_reportWrongWireType("int");
}
_finishBuffering();
}
private void _writePackedArray(long[] array, int i, int end) throws IOException
{
_startBuffering(_currField.typedTag);
final int type = _currField.wireType;
if (type == WireType.VINT) {
final boolean zigzag = _currField.usesZigZag;
for (; i < end; ++i) {
long v = array[i];
if (zigzag) {
v = ProtobufUtil.zigzagEncode(v);
}
_writeVLongNoTag(v);
}
} else if (type == WireType.FIXED_32BIT) {
for (; i < end; ++i) {
_writeInt32NoTag((int) array[i]);
}
} else if (type == WireType.FIXED_64BIT) {
for (; i < end; ++i) {
_writeInt64NoTag(array[i]);
}
} else {
_reportWrongWireType("int");
}
_finishBuffering();
}
private void _writePackedArray(double[] array, int i, int end) throws IOException
{
_startBuffering(_currField.typedTag);
final int type = _currField.wireType;
if (type == WireType.FIXED_64BIT) {
for (; i < end; ++i) {
_writeInt64NoTag(Double.doubleToLongBits( array[i]));
}
} else if (type == WireType.FIXED_32BIT) {
for (; i < end; ++i) {
float f = (float) array[i];
_writeInt32NoTag(Float.floatToRawIntBits(f));
}
} else {
_reportWrongWireType("double");
}
_finishBuffering();
}
private void _writeNonPackedArray(int[] array, int i, int end) throws IOException
{
final int type = _currField.wireType;
if (type == WireType.VINT) {
final boolean zigzag = _currField.usesZigZag;
for (; i < end; ++i) {
int v = array[i];
if (zigzag) {
v = ProtobufUtil.zigzagEncode(v);
}
_writeVInt(v);
}
} else if (type == WireType.FIXED_32BIT) {
for (; i < end; ++i) {
_writeInt32(array[i]);
}
} else if (type == WireType.FIXED_64BIT) {
for (; i < end; ++i) {
_writeInt64(array[i]);
}
} else {
_reportWrongWireType("int");
}
}
private void _writeNonPackedArray(long[] array, int i, int end) throws IOException
{
final int type = _currField.wireType;
if (type == WireType.VINT) {
final boolean zigzag = _currField.usesZigZag;
for (; i < end; ++i) {
long v = array[i];
if (zigzag) {
v = ProtobufUtil.zigzagEncode(v);
}
_writeVLong(v);
}
} else if (type == WireType.FIXED_32BIT) {
for (; i < end; ++i) {
_writeInt32((int) array[i]);
}
} else if (type == WireType.FIXED_64BIT) {
for (; i < end; ++i) {
_writeInt64(array[i]);
}
} else {
_reportWrongWireType("int");
}
}
private void _writeNonPackedArray(double[] array, int i, int end) throws IOException
{
final int type = _currField.wireType;
if (type == WireType.FIXED_64BIT) {
for (; i < end; ++i) {
_writeInt64(Double.doubleToLongBits( array[i]));
}
} else if (type == WireType.FIXED_32BIT) {
for (; i < end; ++i) {
float f = (float) array[i];
_writeInt32(Float.floatToRawIntBits(f));
}
} else {
_reportWrongWireType("double");
}
}
@Override
public void writeString(String text) throws IOException
{
if (text == null) {
writeNull();
return;
}
if (_currField.wireType != WireType.LENGTH_PREFIXED) {
_writeEnum(text);
return;
}
final int clen = text.length();
if (clen > 99) {
_encodeLongerString(text);
return;
}
if (clen == 0) {
_writeEmptyString();
return;
}
_verifyValueWrite();
_ensureRoom(clen+clen+clen+7);
int ptr = _writeTag(_currPtr) + 1;
final int start = ptr;
final byte[] buf = _currBuffer;
int i = 0;
while (true) {
int c = text.charAt(i);
if (c > 0x7F) {
break;
}
buf[ptr++] = (byte) c;
if (++i >= clen) {
buf[start-1] = (byte) (ptr - start);
_currPtr = ptr;
return;
}
}
while (i < clen) {
int c = text.charAt(i++);
if (c <= 0x7F) {
buf[ptr++] = (byte) c;
continue;
}
if (c < 0x800) {
buf[ptr++] = (byte) (0xc0 | (c >> 6));
buf[ptr++] = (byte) (0x80 | (c & 0x3f));
continue;
}
if (c < SURR1_FIRST || c > SURR2_LAST) {
buf[ptr++] = (byte) (0xe0 | (c >> 12));
buf[ptr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
buf[ptr++] = (byte) (0x80 | (c & 0x3f));
continue;
}
if (c > SURR1_LAST) {
_throwIllegalSurrogate(c);
}
if (i >= clen) {
_throwIllegalSurrogate(c);
}
c = _decodeSurrogate(c, text.charAt(i++));
if (c > 0x10FFFF) {
_throwIllegalSurrogate(c);
}
buf[ptr++] = (byte) (0xf0 | (c >> 18));
buf[ptr++] = (byte) (0x80 | ((c >> 12) & 0x3f));
buf[ptr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
buf[ptr++] = (byte) (0x80 | (c & 0x3f));
}
int blen = ptr-start;
if (blen <= 0x7F) {
buf[start-1] = (byte) blen;
} else {
System.arraycopy(buf, start, buf, start+1, blen);
buf[start-1] = (byte) (0x80 + (blen & 0x7F));
buf[start] = (byte) (blen >> 7);
++ptr;
}
_currPtr = ptr;
}
@Override
public void writeString(char[] text, int offset, int clen) throws IOException
{
if (text == null) {
writeNull();
return;
}
if (_currField.wireType != WireType.LENGTH_PREFIXED) {
_writeEnum(new String(text, offset, clen));
}
if (clen > 99) {
_encodeLongerString(text, offset, clen);
return;
}
if (clen == 0) {
_writeEmptyString();
return;
}
_verifyValueWrite();
_ensureRoom(clen+clen+clen+7);
int ptr = _writeTag(_currPtr) + 1;
final int start = ptr;
final byte[] buf = _currBuffer;
final int end = offset + clen;
while (true) {
int c = text[offset];
if (c > 0x7F) {
break;
}
buf[ptr++] = (byte) c;
if (++offset >= end) {
buf[start-1] = (byte) (ptr - start);
_currPtr = ptr;
return;
}
}
while (offset < end) {
int c = text[offset++];
if (c <= 0x7F) {
buf[ptr++] = (byte) c;
continue;
}
if (c < 0x800) {
buf[ptr++] = (byte) (0xc0 | (c >> 6));
buf[ptr++] = (byte) (0x80 | (c & 0x3f));
continue;
}
if (c < SURR1_FIRST || c > SURR2_LAST) {
buf[ptr++] = (byte) (0xe0 | (c >> 12));
buf[ptr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
buf[ptr++] = (byte) (0x80 | (c & 0x3f));
continue;
}
if (c > SURR1_LAST) {
_throwIllegalSurrogate(c);
}
if (offset >= end) {
_throwIllegalSurrogate(c);
}
c = _decodeSurrogate(c, text[offset++]);
if (c > 0x10FFFF) {
_throwIllegalSurrogate(c);
}
buf[ptr++] = (byte) (0xf0 | (c >> 18));
buf[ptr++] = (byte) (0x80 | ((c >> 12) & 0x3f));
buf[ptr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
buf[ptr++] = (byte) (0x80 | (c & 0x3f));
}
int blen = ptr-start;
if (blen <= 0x7F) {
buf[start-1] = (byte) blen;
} else {
System.arraycopy(buf, start, buf, start+1, blen);
buf[start-1] = (byte) (0x80 + (blen & 0x7F));
buf[start] = (byte) (blen >> 7);
++ptr;
}
_currPtr = ptr;
}
@Override
public final void writeString(SerializableString sstr) throws IOException
{
_verifyValueWrite();
if (_currField.wireType == WireType.LENGTH_PREFIXED) {
byte[] b = sstr.asUnquotedUTF8();
_writeLengthPrefixed(b, 0, b.length);
} else if (_currField.type == FieldType.ENUM) {
int index = _currField.findEnumIndex(sstr);
if (index < 0) {
_reportEnumError(sstr);
}
_writeEnum(index);
} else {
_reportWrongWireType("string");
}
}
@Override
public void writeRawUTF8String(byte[] text, int offset, int len) throws IOException
{
if (_currField.wireType != WireType.LENGTH_PREFIXED) {
_reportWrongWireType("string");
return;
}
_verifyValueWrite();
_writeLengthPrefixed(text, offset, len);
}
@Override
public final void writeUTF8String(byte[] text, int offset, int len) throws IOException
{
if (_currField.wireType != WireType.LENGTH_PREFIXED) {
_reportWrongWireType("string");
return;
}
_verifyValueWrite();
_writeLengthPrefixed(text, offset, len);
}
protected void _writeEmptyString() throws IOException
{
_verifyValueWrite();
_ensureRoom(6);
_currPtr = _writeTag(_currPtr);
_currBuffer[_currPtr++] = 0;
}
protected void _writeEnum(String str) throws IOException
{
if (_currField.type != FieldType.ENUM) {
_reportWrongWireType("string");
}
int index = _currField.findEnumIndex(str);
if (index < 0) {
_reportEnumError(str);
}
final int tag = _currField.typedTag;
int ptr = _currPtr;
if (index > 0x7F || tag > 0x7F || (ptr + 1) >= _currBuffer.length) {
_writeVInt(index);
return;
}
final byte[] buf = _currBuffer;
buf[ptr++] = (byte) tag;
buf[ptr++] = (byte) index;
_currPtr = ptr;
}
protected void _writeEnum(int index) throws IOException
{
final int tag = _currField.typedTag;
int ptr = _currPtr;
if (index > 0x7F || tag > 0x7F || (ptr + 1) >= _currBuffer.length) {
_writeVInt(index);
return;
}
final byte[] buf = _currBuffer;
buf[ptr++] = (byte) tag;
buf[ptr++] = (byte) index;
_currPtr = ptr;
}
protected void _reportEnumError(Object enumValue) throws IOException
{
_reportErrorF("No Enum '%s' found for property '%s'; valid values = %s"
+_currField.getEnumValues(), _currField.name, enumValue);
}
@Override
public void writeRaw(String text) throws IOException {
_reportUnsupportedOperation();
}
@Override
public void writeRaw(String text, int offset, int len) throws IOException {
_reportUnsupportedOperation();
}
@Override
public void writeRaw(char[] text, int offset, int len) throws IOException {
_reportUnsupportedOperation();
}
@Override
public void writeRaw(char c) throws IOException {
_reportUnsupportedOperation();
}
@Override
public void writeRawValue(String text) throws IOException {
_reportUnsupportedOperation();
}
@Override
public void writeRawValue(String text, int offset, int len) throws IOException {
_reportUnsupportedOperation();
}
@Override
public void writeRawValue(char[] text, int offset, int len) throws IOException {
_reportUnsupportedOperation();
}
@Override
public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) throws IOException
{
if (data == null) {
writeNull();
return;
}
_verifyValueWrite();
if (_currField.wireType != WireType.LENGTH_PREFIXED) {
_reportWrongWireType("binary");
return;
}
_ensureRoom(10);
_writeLengthPrefixed(data, offset, len);
}
@Override
public void writeBoolean(boolean state) throws IOException
{
_verifyValueWrite();
final int type = _currField.wireType;
if (type == WireType.VINT) {
int b;
if (_currField.usesZigZag) {
b = state ? 2 : 0;
} else {
b = state ? 1 : 0;
}
_writeVInt(b);
return;
}
if (type == WireType.FIXED_32BIT) {
_writeInt32(state ? 1 : 0);
return;
}
if (type == WireType.FIXED_64BIT) {
_writeInt64(state ? 1L : 0L);
return;
}
_reportWrongWireType("boolean");
}
@Override
public void writeNull() throws IOException
{
_verifyValueWrite();
if (_currField == UNKNOWN_FIELD) {
return;
}
if (_currField.required) {
_reportError("Can not omit writing of `null` value for required field '"+_currField.name+"' (type "+_currField.type+")");
}
}
@Override
public void writeNumber(int v) throws IOException
{
_verifyValueWrite();
final int type = _currField.wireType;
if (type == WireType.VINT) {
if (_currField.usesZigZag) {
v = ProtobufUtil.zigzagEncode(v);
}
_writeVInt(v);
return;
}
if (type == WireType.FIXED_32BIT) {
_writeInt32(v);
return;
}
if (type == WireType.FIXED_64BIT) {
_writeInt64(v);
return;
}
_reportWrongWireType("int");
}
@Override
public void writeNumber(long v) throws IOException
{
_verifyValueWrite();
final int type = _currField.wireType;
if (type == WireType.VINT) {
if (_currField.usesZigZag) {
v = ProtobufUtil.zigzagEncode(v);
}
_writeVLong(v);
return;
}
if (type == WireType.FIXED_32BIT) {
_writeInt32((int) v);
return;
}
if (type == WireType.FIXED_64BIT) {
_writeInt64(v);
return;
}
_reportWrongWireType("long");
}
@Override
public void writeNumber(BigInteger v) throws IOException
{
if (v == null) {
writeNull();
return;
}
if (_currField == UNKNOWN_FIELD) {
return;
}
writeNumber(v.longValue());
}
@Override
public void writeNumber(double d) throws IOException
{
_verifyValueWrite();
final int type = _currField.wireType;
if (type == WireType.FIXED_32BIT) {
float f = (float) d;
_writeInt32(Float.floatToRawIntBits(f));
return;
}
if (type == WireType.FIXED_64BIT) {
_writeInt64(Double.doubleToLongBits(d));
return;
}
if (_currField.type == FieldType.STRING) {
_encodeLongerString(String.valueOf(d));
return;
}
_reportWrongWireType("double");
}
@Override
public void writeNumber(float f) throws IOException
{
_verifyValueWrite();
final int type = _currField.wireType;
if (type == WireType.FIXED_32BIT) {
_writeInt32(Float.floatToRawIntBits(f));
return;
}
if (type == WireType.FIXED_64BIT) {
_writeInt64(Double.doubleToLongBits((double) f));
return;
}
if (_currField.type == FieldType.STRING) {
_encodeLongerString(String.valueOf(f));
return;
}
_reportWrongWireType("float");
}
@Override
public void writeNumber(BigDecimal v) throws IOException
{
if (v == null) {
writeNull();
return;
}
if (_currField == UNKNOWN_FIELD) {
return;
}
writeNumber(v.doubleValue());
}
@Override
public void writeNumber(String encodedValue) throws IOException {
throw new UnsupportedOperationException("Can not write 'untyped' numbers");
}
protected final void _verifyValueWrite() throws IOException {
if (_currField == null) {
_reportError("Can not write value without indicating field first (in message of type "+_currMessage.getName()+")");
}
}
@Override
protected void _verifyValueWrite(String typeMsg) throws IOException {
_throwInternal();
}
@Override
protected void _releaseBuffers() {
byte[] b = _currBuffer;
if (b != null) {
_currBuffer = null;
byte[] b2 = _origCurrBuffer;
byte[] toRelease = ((b == b2) || (b.length > b2.length)) ? b : b2;
_ioContext.releaseWriteEncodingBuffer(toRelease);
}
}
private final static Charset UTF8 = Charset.forName("UTF-8");
protected void _encodeLongerString(char[] text, int offset, int clen) throws IOException
{
_verifyValueWrite();
byte[] b = new String(text, offset, clen).getBytes(UTF8);
_writeLengthPrefixed(b, 0, b.length);
}
protected void _encodeLongerString(String text) throws IOException
{
byte[] b = text.getBytes(UTF8);
_writeLengthPrefixed(b, 0, b.length);
}
protected void _writeLengthPrefixed(byte[] data, int offset, int len) throws IOException
{
_ensureRoom(10);
int ptr = _writeTag(_currPtr);
ptr = ProtobufUtil.appendLengthLength(len, _currBuffer, ptr);
while (len > 0) {
int max = Math.min(len, _currBuffer.length - ptr);
System.arraycopy(data, offset, _currBuffer, ptr, max);
ptr += max;
if ((len -= max) == 0) {
_currPtr = ptr;
break;
}
offset += max;
ByteAccumulator acc = _buffered;
final int start = _currStart;
_currStart = 0;
int toFlush = ptr - start;
ptr = 0;
if (acc == null) {
if (toFlush > 0) {
_output.write(_currBuffer, start, toFlush);
}
ptr = 0;
continue;
}
if (toFlush > 0) {
acc.append(_currBuffer, start, toFlush);
}
_currBuffer = ProtobufUtil.allocSecondary(_currBuffer);
}
}
private final void _writeVInt(int v) throws IOException
{
_ensureRoom(10);
int ptr = _writeTag(_currPtr);
if (v < 0) {
_currPtr = _writeVIntMax(v, ptr);
return;
}
final byte[] buf = _currBuffer;
if (v <= 0x7F) {
buf[ptr++] = (byte) v;
} else {
buf[ptr++] = (byte) (0x80 + (v & 0x7F));
v >>= 7;
if (v <= 0x7F) {
buf[ptr++] = (byte) v;
} else {
buf[ptr++] = (byte) ((v & 0x7F) + 0x80);
v >>= 7;
if (v <= 0x7F) {
buf[ptr++] = (byte) v;
} else {
buf[ptr++] = (byte) ((v & 0x7F) + 0x80);
v >>= 7;
if (v <= 0x7F) {
buf[ptr++] = (byte) v;
} else {
buf[ptr++] = (byte) ((v & 0x7F) + 0x80);
v >>= 7;
buf[ptr++] = (byte) (v & 0x7F);
}
}
}
}
_currPtr = ptr;
}
private final void _writeVIntNoTag(int v) throws IOException
{
_ensureRoom(5);
int ptr = _currPtr;
if (v < 0) {
_currPtr = _writeVIntMax(v, ptr);
return;
}
final byte[] buf = _currBuffer;
if (v <= 0x7F) {
buf[ptr++] = (byte) v;
} else {
buf[ptr++] = (byte) (0x80 + (v & 0x7F));
v >>= 7;
if (v <= 0x7F) {
buf[ptr++] = (byte) v;
} else {
buf[ptr++] = (byte) ((v & 0x7F) + 0x80);
v >>= 7;
if (v <= 0x7F) {
buf[ptr++] = (byte) v;
} else {
buf[ptr++] = (byte) ((v & 0x7F) + 0x80);
v >>= 7;
if (v <= 0x7F) {
buf[ptr++] = (byte) v;
} else {
buf[ptr++] = (byte) ((v & 0x7F) + 0x80);
v >>= 7;
buf[ptr++] = (byte) (v & 0x7F);
}
}
}
}
_currPtr = ptr;
}
private final int _writeVIntMax(int v, int ptr) throws IOException
{
final byte[] buf = _currBuffer;
buf[ptr++] = (byte) ((v & 0x7F) + 0x80);
v >>>= 7;
buf[ptr++] = (byte) ((v & 0x7F) + 0x80);
v >>= 7;
buf[ptr++] = (byte) ((v & 0x7F) + 0x80);
v >>= 7;
buf[ptr++] = (byte) ((v & 0x7F) + 0x80);
v >>= 7;
buf[ptr++] = (byte) v;
return ptr;
}
private final void _writeVLong(long v) throws IOException
{
_ensureRoom(16);
int ptr = _writeTag(_currPtr);
if (v < 0L) {
_currPtr = _writeVLongMax(v, ptr);
return;
}
if (v <= 0x0FFFFFFF) {
int i = (int) v;
final byte[] buf = _currBuffer;
if (v <= 0x7F) {
buf[ptr++] = (byte) v;
} else {
do {
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>= 7;
} while (i > 0x7F);
buf[ptr++] = (byte) i;
}
_currPtr = ptr;
return;
}
int i = (int) v;
final byte[] buf = _currBuffer;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>>= 7;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>= 7;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>= 7;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
v >>>= 28;
if (v <= 0x7F) {
buf[ptr++] = (byte) v;
} else {
buf[ptr++] = (byte) ((v & 0x7F) + 0x80);
i = (int) (v >> 7);
do {
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>= 7;
} while (i > 0x7F);
buf[ptr++] = (byte) i;
}
_currPtr = ptr;
}
private final void _writeVLongNoTag(long v) throws IOException
{
_ensureRoom(10);
int ptr = _currPtr;
if (v < 0L) {
_currPtr = _writeVLongMax(v, ptr);
return;
}
if (v <= 0x0FFFFFFF) {
int i = (int) v;
final byte[] buf = _currBuffer;
if (v <= 0x7F) {
buf[ptr++] = (byte) v;
} else {
do {
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>= 7;
} while (i > 0x7F);
buf[ptr++] = (byte) i;
}
_currPtr = ptr;
return;
}
int i = (int) v;
final byte[] buf = _currBuffer;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>>= 7;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>= 7;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>= 7;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
v >>>= 28;
if (v <= 0x7F) {
buf[ptr++] = (byte) v;
} else {
buf[ptr++] = (byte) ((v & 0x7F) + 0x80);
i = (int) (v >> 7);
do {
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>= 7;
} while (i > 0x7F);
buf[ptr++] = (byte) i;
}
_currPtr = ptr;
}
private final int _writeVLongMax(long v, int ptr) throws IOException
{
final byte[] buf = _currBuffer;
int i = (int) v;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>>= 7;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>= 7;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>= 7;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i = (int) (v >>> 28);
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>>= 7;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>= 7;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>= 7;
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i = (int) (v >>> 56);
buf[ptr++] = (byte) ((i & 0x7F) + 0x80);
i >>= 7;
buf[ptr++] = (byte) i;
return ptr;
}
private final void _writeInt32(int v) throws IOException
{
_ensureRoom(9);
int ptr = _writeTag(_currPtr);
final byte[] buf = _currBuffer;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
_currPtr = ptr;
}
private final void _writeInt32NoTag(int v) throws IOException
{
_ensureRoom(4);
int ptr = _currPtr;
final byte[] buf = _currBuffer;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
_currPtr = ptr;
}
private final void _writeInt64(long v64) throws IOException
{
_ensureRoom(13);
int ptr = _writeTag(_currPtr);
final byte[] buf = _currBuffer;
int v = (int) v64;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v = (int) (v64 >> 32);
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
_currPtr = ptr;
}
private final void _writeInt64NoTag(long v64) throws IOException
{
_ensureRoom(8);
int ptr = _currPtr;
final byte[] buf = _currBuffer;
int v = (int) v64;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v = (int) (v64 >> 32);
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
v >>= 8;
buf[ptr++] = (byte) v;
_currPtr = ptr;
}
private final int _writeTag(int ptr)
{
if (_writeTag) {
final byte[] buf = _currBuffer;
int tag = _currField.typedTag;
if (tag <= 0x7F) {
buf[ptr++] = (byte) tag;
} else {
do {
buf[ptr++] = (byte) ((tag & 0x7F) + 0x80);
tag >>= 7;
} while (tag > 0x7F);
buf[ptr++] = (byte) tag;
}
}
return ptr;
}
private final void _startBuffering(int typedTag) throws IOException
{
_ensureRoom(20);
int ptr = _currPtr;
int start = _currStart;
if (_buffered == null) {
int len = ptr - start;
if (len > 0) {
ptr = start = 0;
_output.write(_currBuffer, start, len);
}
}
_buffered = new ByteAccumulator(_buffered, typedTag, _currBuffer, ptr, _currStart);
ptr += 10;
_currStart = ptr;
_currPtr = ptr;
}
private final void _startBuffering() throws IOException
{
_ensureRoom(16);
int ptr = _currPtr;
_buffered = new ByteAccumulator(_buffered, -1, _currBuffer, ptr, _currStart);
ptr += 5;
_currStart = ptr;
_currPtr = ptr;
}
private final void _finishBuffering() throws IOException
{
final int start = _currStart;
final int newStart = _currPtr;
final int currLen = newStart - start;
ByteAccumulator acc = _buffered;
acc = acc.finish(_output, _currBuffer, start, currLen);
_buffered = acc;
if (acc == null) {
_currStart = 0;
_currPtr = 0;
return;
}
_currStart = newStart;
}
protected final void _ensureRoom(int needed) throws IOException
{
if ((_currPtr + needed) > _currBuffer.length) {
_ensureMore();
}
}
protected final void _ensureMore() throws IOException
{
final int start = _currStart;
final int currLen = _currPtr - start;
_currStart = 0;
_currPtr = 0;
ByteAccumulator acc = _buffered;
if (acc == null) {
if (currLen > 0) {
_output.write(_currBuffer, start, currLen);
}
return;
}
if (currLen > 0) {
acc.append(_currBuffer, start, currLen);
}
_currBuffer = ProtobufUtil.allocSecondary(_currBuffer);
}
protected void _complete() throws IOException
{
_complete = true;
final int start = _currStart;
final int currLen = _currPtr - start;
_currPtr = start;
ByteAccumulator acc = _buffered;
if (acc == null) {
if (currLen > 0) {
_output.write(_currBuffer, start, currLen);
_currStart = 0;
_currPtr = 0;
}
} else {
acc = acc.finish(_output, _currBuffer, start, currLen);
while (acc != null) {
acc = acc.finish(_output, _currBuffer);
}
_buffered = null;
}
}
protected void _reportWrongWireType(String typeStr) throws IOException {
if (_currField == UNKNOWN_FIELD) {
return;
}
_reportErrorF("Can not write `string` value for '%s' (type %s)",
_currField.name, _currField.type);
}
private void _reportErrorF(String format, Object... args) throws JsonGenerationException {
_reportError(String.format(format, args));
}
private void _throwIllegalSurrogate(int code)
{
if (code > 0x10FFFF) {
throw new IllegalArgumentException("Illegal character point (0x"+Integer.toHexString(code)+") to output; max is 0x10FFFF as per RFC 4627");
}
if (code >= SURR1_FIRST) {
if (code <= SURR1_LAST) {
throw new IllegalArgumentException("Unmatched first part of surrogate pair (0x"+Integer.toHexString(code)+")");
}
throw new IllegalArgumentException("Unmatched second part of surrogate pair (0x"+Integer.toHexString(code)+")");
}
throw new IllegalArgumentException("Illegal character point (0x"+Integer.toHexString(code)+") to output");
}
}