org.tarantool.MsgPackLite Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of connector Show documentation
Show all versions of connector Show documentation
Tarantool client for java
package org.tarantool;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* forked from https://bitbucket.org/sirbrialliance/msgpack-java-lite
*/
public class MsgPackLite {
public static final MsgPackLite INSTANCE = new MsgPackLite();
protected final int MAX_4BIT = 0xf;
protected final int MAX_5BIT = 0x1f;
protected final int MAX_7BIT = 0x7f;
protected final int MAX_8BIT = 0xff;
protected final int MAX_15BIT = 0x7fff;
protected final int MAX_16BIT = 0xffff;
protected final int MAX_31BIT = 0x7fffffff;
protected final long MAX_32BIT = 0xffffffffL;
protected final BigInteger BI_MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE);
protected final BigInteger BI_MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE);
protected final BigInteger BI_MAX_64BIT = BigInteger.valueOf(2).pow(64).subtract(BigInteger.ONE);
//these values are from http://wiki.msgpack.org/display/MSGPACK/Format+specification
protected final byte MP_NULL = (byte) 0xc0;
protected final byte MP_FALSE = (byte) 0xc2;
protected final byte MP_TRUE = (byte) 0xc3;
protected final byte MP_BIN8 = (byte) 0xc4;
protected final byte MP_BIN16 = (byte) 0xc5;
protected final byte MP_BIN32 = (byte) 0xc6;
protected final byte MP_FLOAT = (byte) 0xca;
protected final byte MP_DOUBLE = (byte) 0xcb;
protected final byte MP_FIXNUM = (byte) 0x00;//last 7 bits is value
protected final byte MP_UINT8 = (byte) 0xcc;
protected final byte MP_UINT16 = (byte) 0xcd;
protected final byte MP_UINT32 = (byte) 0xce;
protected final byte MP_UINT64 = (byte) 0xcf;
protected final byte MP_NEGATIVE_FIXNUM = (byte) 0xe0;//last 5 bits is value
protected final int MP_NEGATIVE_FIXNUM_INT = 0xe0;// /me wishes for signed numbers.
protected final byte MP_INT8 = (byte) 0xd0;
protected final byte MP_INT16 = (byte) 0xd1;
protected final byte MP_INT32 = (byte) 0xd2;
protected final byte MP_INT64 = (byte) 0xd3;
protected final byte MP_FIXARRAY = (byte) 0x90;//last 4 bits is size
protected final int MP_FIXARRAY_INT = 0x90;
protected final byte MP_ARRAY16 = (byte) 0xdc;
protected final byte MP_ARRAY32 = (byte) 0xdd;
protected final byte MP_FIXMAP = (byte) 0x80;//last 4 bits is size
protected final int MP_FIXMAP_INT = 0x80;
protected final byte MP_MAP16 = (byte) 0xde;
protected final byte MP_MAP32 = (byte) 0xdf;
protected final byte MP_FIXSTR = (byte) 0xa0;//last 5 bits is size
protected final int MP_FIXSTR_INT = 0xa0;
protected final byte MP_STR8 = (byte) 0xd9;
protected final byte MP_STR16 = (byte) 0xda;
protected final byte MP_STR32 = (byte) 0xdb;
public void pack(Object item, OutputStream os) throws IOException {
DataOutputStream out = new DataOutputStream(os);
if (item instanceof Callable) {
try {
item = ((Callable) item).call();
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
if (item == null) {
out.write(MP_NULL);
} else if (item instanceof Boolean) {
out.write(((Boolean) item).booleanValue() ? MP_TRUE : MP_FALSE);
} else if (item instanceof Number || item instanceof Code) {
if (item instanceof Float) {
out.write(MP_FLOAT);
out.writeFloat((Float) item);
} else if (item instanceof Double) {
out.write(MP_DOUBLE);
out.writeDouble((Double) item);
} else {
if (item instanceof BigInteger) {
BigInteger value = (BigInteger) item;
boolean isPositive = value.signum() >= 0;
if (isPositive && value.compareTo(BI_MAX_64BIT) > 0 ||
value.compareTo(BI_MIN_LONG) < 0)
throw new IllegalArgumentException(
"Cannot encode BigInteger as MsgPack: out of -2^63..2^64-1 range");
if (isPositive && value.compareTo(BI_MAX_LONG) > 0) {
byte[] data = value.toByteArray();
// data can contain leading zero bytes
for (int i = 0; i < data.length - 8; ++i)
assert data[i] == 0;
out.write(MP_UINT64);
out.write(data, data.length - 8, 8);
return;
}
}
long value = item instanceof Code ? ((Code) item).getId() : ((Number) item).longValue();
if (value >= 0) {
if (value <= MAX_7BIT) {
out.write((int) value | MP_FIXNUM);
} else if (value <= MAX_8BIT) {
out.write(MP_UINT8);
out.write((int) value);
} else if (value <= MAX_16BIT) {
out.write(MP_UINT16);
out.writeShort((int) value);
} else if (value <= MAX_32BIT) {
out.write(MP_UINT32);
out.writeInt((int) value);
} else {
out.write(MP_UINT64);
out.writeLong(value);
}
} else {
if (value >= -(MAX_5BIT + 1)) {
out.write((int) (value & 0xff));
} else if (value >= -(MAX_7BIT + 1)) {
out.write(MP_INT8);
out.write((int) value);
} else if (value >= -(MAX_15BIT + 1)) {
out.write(MP_INT16);
out.writeShort((int) value);
} else if (value >= -(MAX_31BIT + 1)) {
out.write(MP_INT32);
out.writeInt((int) value);
} else {
out.write(MP_INT64);
out.writeLong(value);
}
}
}
} else if (item instanceof String) {
byte[] data = ((String) item).getBytes("UTF-8");
if (data.length <= MAX_5BIT) {
out.write(data.length | MP_FIXSTR);
} else if (data.length <= MAX_8BIT) {
out.write(MP_STR8);
out.writeByte(data.length);
} else if (data.length <= MAX_16BIT) {
out.write(MP_STR16);
out.writeShort(data.length);
} else {
out.write(MP_STR32);
out.writeInt(data.length);
}
out.write(data);
} else if (item instanceof byte[] || item instanceof ByteBuffer) {
byte[] data;
if (item instanceof byte[]) {
data = (byte[]) item;
} else {
ByteBuffer bb = ((ByteBuffer) item);
if (bb.hasArray()) {
data = bb.array();
} else {
data = new byte[bb.capacity()];
bb.position();
bb.limit(bb.capacity());
bb.get(data);
}
}
if (data.length <= MAX_8BIT) {
out.write(MP_BIN8);
out.writeByte(data.length);
} else if (data.length <= MAX_16BIT) {
out.write(MP_BIN16);
out.writeShort(data.length);
} else {
out.write(MP_BIN32);
out.writeInt(data.length);
}
out.write(data);
} else if (item instanceof List || item.getClass().isArray()) {
int length = item instanceof List ? ((List) item).size() : Array.getLength(item);
if (length <= MAX_4BIT) {
out.write(length | MP_FIXARRAY);
} else if (length <= MAX_16BIT) {
out.write(MP_ARRAY16);
out.writeShort(length);
} else {
out.write(MP_ARRAY32);
out.writeInt(length);
}
if (item instanceof List) {
List list = ((List) item);
for (Object element : list) {
pack(element, out);
}
} else {
for (int i = 0; i < length; i++) {
pack(Array.get(item, i), out);
}
}
} else if (item instanceof Map) {
Map