diff --git a/.gitignore b/.gitignore
old mode 100755
new mode 100644
diff --git a/README.md b/README.md
index 85893db09..2d7689968 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,41 @@
# MessagePack for Java
-An implementation of [MessagePack](http://msgpack.org/) for Java.
+An *alternative* implementation of [MessagePack](http://msgpack.org/) for Java.
+
+It is based on the [original Java implementation](https://github.com/msgpack/msgpack-java)
+
+The primary goals of this alternative implementation are to keep the original tightness of MessagePack, while serving additionally the following use cases:
+
+* Enable long-term persistence of data, under the assumption that the full schema (but not the original code) will still be available in the future.
+* Enable easy on-the-fly data-migration, when reading data using an old schema.
+* Enable partial/incremental de-serialisation.
+* Enable serializing *changes* to an object graph, rather the the whole graph itself.
+* Enable each type to choose a different MessagePack representation (array/map/raw)
+* Enable embedding of other serialisation streams.
+* Enable cycles in the object graph.
+* Enable serialisation of immutable objects (might not work together with "cycles")
+* Enable compatibility with GWT and Hadoop
+* Enamble compatibility with HPPC collections (more third-party APIs compatibility to come)
+
+One limitation of the core MessagePack API that causes some inefficiencies is the fact that MessagePack does not nativelly support true streaming of data. What I mean is that data can put into raw, arrays or maps, but all of them require the API user to know how many bytes or values will be written a priory, which goes against the principle of "streaming". There is currently work to make MessagePack an official Internet standard, and as part of this effort, there is work to make the API extensible. This, I hope, will allow use to create raw/arrays/maps of unknown size.
+
+There are generally a few patterns to serializing objects. They can either be written as a bunch of bytes (raw), where the API cannot recognize the actual content of the bytes, and the code deserializing the data must have the full knowledge. The second possibility is that each object's filed is written as a "value" that the API recognize, and so objects are always written in the same format, independent of the content. The third option is for the object to only write it's "non-default" fields to the stream. The last option requires that at least some field ID precedes each field data, so that the object can be reconstructed when de-serializing.
+
+Most serialisation API require force you to use a single one of those patterns for each and every type you want to persist. This API lets you choose, although MessagePack itself puts limitation on "raw" objects, which currently requires wrapping them in an array first, therefore causing one additional byte of overhead per object.
+
+The general design of the object protocol works like this:
+
+* All objects are written and read using an object-specific template.
+* At the moment, all templates must be creted manually.
+* The (optional) separation of object creation and obect reading allows both for the usage of immutable types and cycles, but both might not work together.
+* The ObjectPacker and ObjectUnpacker are hardly more then wrappers for the templates.
+* If the object is null, the you write nil
+* If the object is a string, the you write a raw
+* If the objects wants to be saved as an array, you open the array at size ("object size" + 1), and store the object's type as an integer ID in the first array position.
+* If the objects wants to be saved as a map, you open the map at size ("object size" + 1), and store the object's type as an integer ID in the first map entry key (first map entry value might optionally be used by the object's template).
+* If the objects wants to be saved as a raw (and is not a string), you create an array at size 2, and store the object's type as an integer ID in the first array position, and the raw at the second position.
+* Under certain circumstances, arrays of objects might be able to skip the individual array and type header overhead.
+* Being compatable with Java's DataOutput/DataInput interfaces bot for the underlying stream and the MessagePack core API should maximize this API's compatibility to existing code.
## Installation
diff --git a/pom.xml b/pom.xml
index 252152c43..dc6b94f49 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,15 +1,13 @@
4.0.0
- org.msgpack
+ com.blockwithmemsgpackMessagePack for JavaMessagePack for Java is a binary-based efficient object
serialization library in Java.
- 0.6.8-SNAPSHOT
+ 1.0.0bundle
- http://msgpack.org/
-
The Apache Software License, Version 2.0
@@ -17,28 +15,21 @@
repo
-
- scm:git:git://github.com/msgpack/msgpack-java.git
- scm:git:git@github.com:msgpack/msgpack-java.git
- scm:git:git://github.com/msgpack/msgpack-java.git
+ scm:git:git://github.com/skunkiferous/msgpack-java.git
+ scm:git:git@github.com:skunkiferous/msgpack-java.git
+ scm:git:git://github.com/skunkiferous/msgpack-java.git
-
GitHub
- https://github.com/msgpack/msgpack-java/issues
+ https://github.com/skunkiferous/msgpack-java/issues
- frsyuki
- Sadayuki Furuhashi
- frsyuki@users.sourceforge.jp
-
-
- muga
- Muga Nishizawa
- muga.nishizawa@gmail.com
+ skunkiferous
+ Sebastien Diot
+ s.diot@eurodata.de
@@ -66,6 +57,16 @@
4.8.2test
+
+ com.blockwithme
+ Common
+ [0.0,1)
+
+
+ com.blockwithme
+ hppc
+ 0.4.1
+
@@ -90,8 +91,8 @@
maven-compiler-plugin2.3.2
- 1.6
- 1.6
+ 1.7
+ 1.7UTF-8
@@ -190,4 +191,11 @@
+
+
+ blockwithme-mvn-repo
+ https://raw.github.com/skunkiferous/Maven/master
+
+
+
diff --git a/src/main/java/com/blockwithme/msgpack/Helper.java b/src/main/java/com/blockwithme/msgpack/Helper.java
new file mode 100644
index 000000000..34d8bf06d
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/Helper.java
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+import com.blockwithme.msgpack.impl.MessagePackPacker;
+import com.blockwithme.msgpack.impl.MessagePackUnpacker;
+import com.blockwithme.msgpack.impl.ObjectPackerImpl;
+import com.blockwithme.msgpack.impl.ObjectUnpackerImpl;
+import com.blockwithme.msgpack.schema.SchemaManager;
+import com.blockwithme.msgpack.templates.PackerContext;
+import com.blockwithme.msgpack.templates.UnpackerContext;
+import com.blockwithme.util.DataInputBuffer;
+
+/**
+ * Helper class for the MessagePack API.
+ *
+ * @author monster
+ */
+public class Helper {
+ /** The format and schema versions. */
+ public static final class Version {
+ /** The format version. */
+ public final int format;
+ /** The schema version. */
+ public final int schema;
+
+ /** Constructor */
+ public Version(final int format, final int schema) {
+ this.format = format;
+ this.schema = schema;
+ }
+
+ /** toString */
+ @Override
+ public String toString() {
+ return "Version(" + format + "," + schema + ")";
+ }
+ }
+
+ /** Creates a new packer. */
+ public static Packer newPacker(final DataOutput out) {
+ return new MessagePackPacker(out);
+ }
+
+ /** Creates a new object packer.
+ * @throws IOException */
+ public static ObjectPacker newObjectPacker(final DataOutput out,
+ final PackerContext context) throws IOException {
+ return new ObjectPackerImpl(newPacker(out), context);
+ }
+
+ /** Creates a new object packer.
+ * @throws IOException */
+ public static ObjectPacker newObjectPacker(final DataOutput out,
+ final SchemaManager schemaManager, final int schema)
+ throws IOException {
+ final PackerContext pc = new PackerContext(schemaManager);
+ pc.schemaID = schema;
+ return newObjectPacker(out, pc);
+ }
+
+ /** Creates a new Unpacker for the bytes. */
+ public static Unpacker newUnpacker(final byte[] bytes) {
+ return new MessagePackUnpacker(new DataInputBuffer(bytes));
+ }
+
+ /** Creates a new ObjectUnpacker for the bytes.
+ * @throws IOException */
+ public static ObjectUnpacker newObjectUnpacker(final byte[] bytes,
+ final UnpackerContext context) throws IOException {
+ return new ObjectUnpackerImpl(new MessagePackUnpacker(
+ new DataInputBuffer(bytes)), context);
+ }
+
+ /** Creates a new ObjectUnpacker for the bytes.
+ * @throws IOException */
+ public static ObjectUnpacker newObjectUnpacker(final byte[] bytes,
+ final SchemaManager schemaManager) throws IOException {
+ return newObjectUnpacker(bytes, new UnpackerContext(schemaManager));
+ }
+
+ /** Returns the format version, and the schema version, for the given byte array.
+ * @throws IOException */
+ public static Version getVersion(final byte[] bytes) throws IOException {
+ final Unpacker u = newUnpacker(bytes);
+ final int format = u.readIndex();
+ final int schema = u.readIndex();
+ return new Version(format, schema);
+ }
+
+ /** Writes a boolean array. */
+ public static void writeBooleanArray(final Packer packer,
+ final boolean[] target) throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(target.length);
+ for (final boolean a : target) {
+ packer.writeBoolean(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Writes a short array. */
+ public static void writeShortArray(final Packer packer, final short[] target)
+ throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(target.length);
+ for (final short a : target) {
+ packer.writeShort(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Writes a char array. */
+ public static void writeCharArray(final Packer packer, final char[] target)
+ throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(target.length);
+ for (final char a : target) {
+ packer.writeChar(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Writes a int array. */
+ public static void writeIntArray(final Packer packer, final int[] target)
+ throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(target.length);
+ for (final int a : target) {
+ packer.writeInt(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Writes a long array. */
+ public static void writeLongArray(final Packer packer, final long[] target)
+ throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(target.length);
+ for (final long a : target) {
+ packer.writeLong(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Writes a float array. */
+ public static void writeFloatArray(final Packer packer, final float[] target)
+ throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(target.length);
+ for (final float a : target) {
+ packer.writeFloat(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Writes a double array. */
+ public static void writeDoubleArray(final Packer packer,
+ final double[] target) throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(target.length);
+ for (final double a : target) {
+ packer.writeDouble(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Writes a boolean array. */
+ public static void writeBooleanArray(final Packer packer,
+ final boolean[] target, final int offset, final int length)
+ throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(length);
+ final int end = (offset + length);
+ for (int i = offset; i < end; i++) {
+ final boolean a = target[i];
+ packer.writeBoolean(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Writes a short array. */
+ public static void writeShortArray(final Packer packer,
+ final short[] target, final int offset, final int length)
+ throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(length);
+ final int end = (offset + length);
+ for (int i = offset; i < end; i++) {
+ final short a = target[i];
+ packer.writeShort(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Writes a char array. */
+ public static void writeCharArray(final Packer packer, final char[] target,
+ final int offset, final int length) throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(length);
+ final int end = (offset + length);
+ for (int i = offset; i < end; i++) {
+ final char a = target[i];
+ packer.writeChar(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Writes a int array. */
+ public static void writeIntArray(final Packer packer, final int[] target,
+ final int offset, final int length) throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(length);
+ final int end = (offset + length);
+ for (int i = offset; i < end; i++) {
+ final int a = target[i];
+ packer.writeInt(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Writes a long array. */
+ public static void writeLongArray(final Packer packer, final long[] target,
+ final int offset, final int length) throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(length);
+ final int end = (offset + length);
+ for (int i = offset; i < end; i++) {
+ final long a = target[i];
+ packer.writeLong(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Writes a float array. */
+ public static void writeFloatArray(final Packer packer,
+ final float[] target, final int offset, final int length)
+ throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(length);
+ final int end = (offset + length);
+ for (int i = offset; i < end; i++) {
+ final float a = target[i];
+ packer.writeFloat(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Writes a double array. */
+ public static void writeDoubleArray(final Packer packer,
+ final double[] target, final int offset, final int length)
+ throws IOException {
+ if (target == null) {
+ packer.writeNil();
+
+ }
+ packer.writeArrayBegin(length);
+ final int end = (offset + length);
+ for (int i = offset; i < end; i++) {
+ final double a = target[i];
+ packer.writeDouble(a);
+ }
+ packer.writeArrayEnd();
+
+ }
+
+ /** Reads a boolean array. */
+ public static boolean[] readBooleanArray(final Unpacker unpacker)
+ throws IOException {
+ if (unpacker.trySkipNil()) {
+ return null;
+ }
+ final int n = unpacker.readArrayBegin();
+ final boolean[] result = new boolean[n];
+ for (int i = 0; i < n; i++) {
+ result[i] = unpacker.readBoolean();
+ }
+ unpacker.readArrayEnd();
+ return result;
+ }
+
+ /** Reads a short array. */
+ public static short[] readShortArray(final Unpacker unpacker)
+ throws IOException {
+ if (unpacker.trySkipNil()) {
+ return null;
+ }
+ final int n = unpacker.readArrayBegin();
+ final short[] result = new short[n];
+ for (int i = 0; i < n; i++) {
+ result[i] = unpacker.readShort();
+ }
+ unpacker.readArrayEnd();
+ return result;
+ }
+
+ /** Reads a char array. */
+ public static char[] readCharArray(final Unpacker unpacker)
+ throws IOException {
+ if (unpacker.trySkipNil()) {
+ return null;
+ }
+ final int n = unpacker.readArrayBegin();
+ final char[] result = new char[n];
+ for (int i = 0; i < n; i++) {
+ result[i] = unpacker.readChar();
+ }
+ unpacker.readArrayEnd();
+ return result;
+ }
+
+ /** Reads a int array. */
+ public static int[] readIntArray(final Unpacker unpacker)
+ throws IOException {
+ if (unpacker.trySkipNil()) {
+ return null;
+ }
+ final int n = unpacker.readArrayBegin();
+ final int[] result = new int[n];
+ for (int i = 0; i < n; i++) {
+ result[i] = unpacker.readInt();
+ }
+ unpacker.readArrayEnd();
+ return result;
+ }
+
+ /** Reads a long array. */
+ public static long[] readLongArray(final Unpacker unpacker)
+ throws IOException {
+ if (unpacker.trySkipNil()) {
+ return null;
+ }
+ final int n = unpacker.readArrayBegin();
+ final long[] result = new long[n];
+ for (int i = 0; i < n; i++) {
+ result[i] = unpacker.readLong();
+ }
+ unpacker.readArrayEnd();
+ return result;
+ }
+
+ /** Reads a float array. */
+ public static float[] readFloatArray(final Unpacker unpacker)
+ throws IOException {
+ if (unpacker.trySkipNil()) {
+ return null;
+ }
+ final int n = unpacker.readArrayBegin();
+ final float[] result = new float[n];
+ for (int i = 0; i < n; i++) {
+ result[i] = unpacker.readFloat();
+ }
+ unpacker.readArrayEnd();
+ return result;
+ }
+
+ /** Reads a double array. */
+ public static double[] readDoubleArray(final Unpacker unpacker)
+ throws IOException {
+ if (unpacker.trySkipNil()) {
+ return null;
+ }
+ final int n = unpacker.readArrayBegin();
+ final double[] result = new double[n];
+ for (int i = 0; i < n; i++) {
+ result[i] = unpacker.readDouble();
+ }
+ unpacker.readArrayEnd();
+ return result;
+ }
+}
diff --git a/src/main/java/org/msgpack/MessageTypeException.java b/src/main/java/com/blockwithme/msgpack/MessageTypeException.java
similarity index 72%
rename from src/main/java/org/msgpack/MessageTypeException.java
rename to src/main/java/com/blockwithme/msgpack/MessageTypeException.java
index 926838f51..36c4bcaad 100644
--- a/src/main/java/org/msgpack/MessageTypeException.java
+++ b/src/main/java/com/blockwithme/msgpack/MessageTypeException.java
@@ -15,23 +15,27 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack;
+package com.blockwithme.msgpack;
+/**
+ * Denotes certain MessagePack Exceptions, generally related to inconsistent
+ * API usage or stream content.
+ */
@SuppressWarnings("serial")
public class MessageTypeException extends RuntimeException {
public MessageTypeException() {
super();
}
- public MessageTypeException(String message) {
+ public MessageTypeException(final String message) {
super(message);
}
- public MessageTypeException(String message, Throwable cause) {
+ public MessageTypeException(final String message, final Throwable cause) {
super(message, cause);
}
- public MessageTypeException(Throwable cause) {
+ public MessageTypeException(final Throwable cause) {
super(cause);
}
}
diff --git a/src/main/java/com/blockwithme/msgpack/ObjectPacker.java b/src/main/java/com/blockwithme/msgpack/ObjectPacker.java
new file mode 100644
index 000000000..1f6a4f572
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/ObjectPacker.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.Date;
+
+import com.blockwithme.msgpack.templates.Template;
+
+/**
+ * ObjectPacker can pack any object with a registered template.
+ *
+ * It does NOT extends Packer by design. To serialize primitive value, go
+ * directly to the underlying Packer, with the packer() method.
+ *
+ * Please realize the difference between the write(int[]) of Packer and our
+ * writeObject(int[]); ours stores additional information to allow for generic object
+ * serialization (the type), therefore the two are not compatible. Also, all
+ * the methods here take into consideration that an object might be serialized
+ * multiple times, and so writing the same int[] with an ObjectPacker will
+ * result in a single copy on the stream, while it would result in multiple
+ * copies if done using Unpacker.
+ *
+ * @author monster
+ */
+public interface ObjectPacker {
+
+ /** Returns the underlying packer. */
+ Packer packer();
+
+ /** Writes a Boolean. */
+ ObjectPacker writeObject(final Boolean o) throws IOException;
+
+ /** Writes a Byte. */
+ ObjectPacker writeObject(final Byte o) throws IOException;
+
+ /** Writes a Short. */
+ ObjectPacker writeObject(final Short o) throws IOException;
+
+ /** Writes a Character. */
+ ObjectPacker writeObject(final Character o) throws IOException;
+
+ /** Writes a Integer. */
+ ObjectPacker writeObject(final Integer o) throws IOException;
+
+ /** Writes a Long. */
+ ObjectPacker writeObject(final Long o) throws IOException;
+
+ /** Writes a Float. */
+ ObjectPacker writeObject(final Float o) throws IOException;
+
+ /** Writes a Double. */
+ ObjectPacker writeObject(final Double o) throws IOException;
+
+ /** Writes a BigInteger. */
+ ObjectPacker writeObject(final BigInteger o) throws IOException;
+
+ /** Writes a BigDecimal. */
+ ObjectPacker writeObject(final BigDecimal o) throws IOException;
+
+ /** Writes a Date out. */
+ ObjectPacker writeObject(final Date o) throws IOException;
+
+ /** Writes a boolean array. */
+ ObjectPacker writeObject(final boolean[] o) throws IOException;
+
+ /** Writes a byte array. */
+ ObjectPacker writeObject(final byte[] o) throws IOException;
+
+ /** Writes a short array. */
+ ObjectPacker writeObject(final short[] o) throws IOException;
+
+ /** Writes a char array. */
+ ObjectPacker writeObject(final char[] o) throws IOException;
+
+ /** Writes a int array. */
+ ObjectPacker writeObject(final int[] o) throws IOException;
+
+ /** Writes a long array. */
+ ObjectPacker writeObject(final long[] o) throws IOException;
+
+ /** Writes a float array. */
+ ObjectPacker writeObject(final float[] o) throws IOException;
+
+ /** Writes a double array. */
+ ObjectPacker writeObject(final double[] o) throws IOException;
+
+ /** Writes a String. */
+ ObjectPacker writeObject(final String o) throws IOException;
+
+ /** Writes a ByteBuffer. */
+ ObjectPacker writeObject(final ByteBuffer o) throws IOException;
+
+ /** Writes a Class out. */
+ ObjectPacker writeObject(final Class> o) throws IOException;
+
+ /** Writes a slice of a byte[]. */
+ ObjectPacker writeObject(final byte[] o, final int off, final int len)
+ throws IOException;
+
+ /**
+ * Writes an Object out. Template is determined based on object type.
+ * Pass along a template for faster results.
+ */
+ ObjectPacker writeObject(final Object o) throws IOException;
+
+ /**
+ * Writes an Object out. Object must be compatible with non-null template.
+ * Note that we cannot link the Object type with the template type, since
+ * we could use the template to also write an *array* of the object type.
+ */
+ ObjectPacker writeObject(final Object o, final Template> template)
+ throws IOException;
+
+ /**
+ * Writes an Object out. Template is determined based on object type.
+ * Pass along a template for faster results.
+ */
+ ObjectPacker writeObject(final Object o,
+ final boolean ifObjectArrayCanContainNullValue) throws IOException;
+
+ /**
+ * Writes an Object out. Object must be compatible with non-null template.
+ * Note that we cannot link the Object type with the template type, since
+ * we could use the template to also write an *array* of the object type.
+ */
+ ObjectPacker writeObject(final Object o, final Template> template,
+ final boolean ifObjectArrayCanContainNullValue) throws IOException;
+}
diff --git a/src/main/java/com/blockwithme/msgpack/ObjectUnpacker.java b/src/main/java/com/blockwithme/msgpack/ObjectUnpacker.java
new file mode 100644
index 000000000..c7a74bc05
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/ObjectUnpacker.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.Date;
+
+import com.blockwithme.msgpack.templates.Template;
+
+/**
+ * ObjectUnpacker can unpack any object with a registered template.
+ * It does NOT extends Unpacker by design. To serialize primitive value, go
+ * directly to the underlying Unpacker, with the unpacker() method.
+ *
+ * Please realize the difference between the int[] readIntArray() of Unpacker
+ * and ours; ours stores additional information to allow for generic object
+ * serialization (the type), therefore the two are not compatible. Also, all
+ * the methods here take into consideration that an object might be serialized
+ * multiple times, and so writing the same int[] with an ObjectPacker will
+ * result in a single copy on the stream, while it would result in multiple
+ * copies if done using Unpacker.
+ *
+ * @author monster
+ */
+public interface ObjectUnpacker extends Closeable {
+
+ /** Returns the underlying unpacker. */
+ Unpacker unpacker();
+
+ /** Reads any Object. */
+ Object readObject() throws IOException;
+
+ /**
+ * Reads any Object. Fails if the template is not null, and the Object type
+ * does not match template type. Since templates are used to read not only
+ * objects, but also array, we cannot assume that for a Template, the
+ * return type will be T; it could also be T[] ...
+ */
+ Object readObject(final Template> template) throws IOException;
+
+ /** Reads any Object. */
+ Object readObject(final boolean ifObjectArrayCanContainNullValue)
+ throws IOException;
+
+ /**
+ * Reads any Object. Fails if the template is not null, and the Object type
+ * does not match template type. Since templates are used to read not only
+ * objects, but also array, we cannot assume that for a Template, the
+ * return type will be T; it could also be T[] ...
+ */
+ Object readObject(final Template> template,
+ final boolean ifObjectArrayCanContainNullValue) throws IOException;
+
+ /** Reads a boolean. */
+ Boolean readBoolean() throws IOException;
+
+ /** Reads a byte. */
+ Byte readByte() throws IOException;
+
+ /** Reads a short. */
+ Short readShort() throws IOException;
+
+ /** Reads a char. */
+ Character readChar() throws IOException;
+
+ /** Reads an int. */
+ Integer readInt() throws IOException;
+
+ /** Reads a long. */
+ Long readLong() throws IOException;
+
+ /** Reads a float. */
+ Float readFloat() throws IOException;
+
+ /** Reads a double. */
+ Double readDouble() throws IOException;
+
+ /** Reads a String. */
+ String readString() throws IOException;
+
+ /** Reads a BigInteger. */
+ BigInteger readBigInteger() throws IOException;
+
+ /** Reads a BigDecimal. */
+ BigDecimal readBigDecimal() throws IOException;
+
+ /** Reads a Date. */
+ Date readDate() throws IOException;
+
+ /** Reads a Class. */
+ Class> readClass() throws IOException;
+
+ /** Reads a boolean array. */
+ boolean[] readBooleanArray() throws IOException;
+
+ /** Reads a byte array. */
+ byte[] readByteArray() throws IOException;
+
+ /** Reads a short array. */
+ short[] readShortArray() throws IOException;
+
+ /** Reads a char array. */
+ char[] readCharArray() throws IOException;
+
+ /** Reads a int array. */
+ int[] readIntArray() throws IOException;
+
+ /** Reads a long array. */
+ long[] readLongArray() throws IOException;
+
+ /** Reads a float array. */
+ float[] readFloatArray() throws IOException;
+
+ /** Reads a double array. */
+ double[] readDoubleArray() throws IOException;
+
+ /** Reads a ByteBuffer. */
+ ByteBuffer readByteBuffer() throws IOException;
+}
diff --git a/src/main/java/com/blockwithme/msgpack/Packer.java b/src/main/java/com/blockwithme/msgpack/Packer.java
new file mode 100644
index 000000000..a4d8ae7dc
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/Packer.java
@@ -0,0 +1,223 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 - 2013 FURUHASHI Sadayuki
+//
+// 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 com.blockwithme.msgpack;
+
+import java.io.Closeable;
+import java.io.DataOutput;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.Date;
+
+/**
+ * Standard serializer in MessagePack for Java. It allows users to serialize
+ * objects like String, byte[], primitive types and so on.
+ * Things List, Map ... must be built on top of it.
+ *
+ * It also implements DataOutput, for easier migration of code, but it is
+ * unlikely that code using DataOutput can be ported without modifications.
+ */
+public interface Packer extends Closeable, Flushable, DataOutput {
+ /** Writes a boolean. */
+ @Override
+ void writeBoolean(final boolean o) throws IOException;
+
+ /** Writes a byte. */
+ void writeByte(final byte o) throws IOException;
+
+ /** Writes a short. */
+ void writeShort(final short o) throws IOException;
+
+ /** Writes a char. */
+ void writeChar(final char o) throws IOException;
+
+ /** Writes a int. */
+ @Override
+ void writeInt(final int o) throws IOException;
+
+ /** Writes a long. */
+ @Override
+ void writeLong(final long o) throws IOException;
+
+ /** Writes a float. */
+ @Override
+ void writeFloat(final float o) throws IOException;
+
+ /** Writes a double. */
+ @Override
+ void writeDouble(final double o) throws IOException;
+
+ /** Writes a byte array. */
+ @Override
+ void write(final byte[] o) throws IOException;
+
+ /** Writes a Boolean. */
+ void writeBoolean(final Boolean o) throws IOException;
+
+ /** Writes a Byte. */
+ void writeByte(final Byte o) throws IOException;
+
+ /** Writes a Short. */
+ void writeShort(final Short o) throws IOException;
+
+ /** Writes a Character. */
+ void writeCharacter(final Character o) throws IOException;
+
+ /** Writes a Integer. */
+ void writeInteger(final Integer o) throws IOException;
+
+ /** Writes a Long. */
+ void writeLong(final Long o) throws IOException;
+
+ /** Writes a Float. */
+ void writeFloat(final Float o) throws IOException;
+
+ /** Writes a Double. */
+ void writeDouble(final Double o) throws IOException;
+
+ /** Writes a BigInteger. */
+ void writeBigInteger(final BigInteger o) throws IOException;
+
+ /** Writes a BigDecimal. */
+ void writeBigDecimal(final BigDecimal o) throws IOException;
+
+ /** Writes a String. */
+ @Override
+ void writeUTF(final String o) throws IOException;
+
+ /** Writes a Date out. */
+ void writeDate(final Date o) throws IOException;
+
+ /** Writes a ByteBuffer. */
+ void writeByteBuffer(final ByteBuffer o) throws IOException;
+
+ /**
+ * Deduce 31 from the index, so it is more likely to be saved as one byte.
+ * This methods should be used for normally non-negative integers.
+ * -1 also stores as one byte.
+ */
+ void writeIndex(final int index) throws IOException;
+
+ /** Writes a slice of a byte[]. */
+ @Override
+ void write(final byte[] o, final int off, final int len) throws IOException;
+
+ /** Writes nil/null. */
+ void writeNil() throws IOException;
+
+ /** Writes an array begin. */
+ void writeArrayBegin(final int size) throws IOException;
+
+ /** Writes an array end. */
+ void writeArrayEnd(final boolean check) throws IOException;
+
+ /** Writes an array end. */
+ void writeArrayEnd() throws IOException;
+
+ /** Writes a map begin. */
+ void writeMapBegin(final int size) throws IOException;
+
+ /** Writes a map end. */
+ void writeMapEnd(final boolean check) throws IOException;
+
+ /** Writes a map end. */
+ void writeMapEnd() throws IOException;
+
+ /** Writes an raw begin. */
+ void writeRawBegin(final int size) throws IOException;
+
+ /** Writes an raw end. */
+ void writeRawEnd() throws IOException;
+
+ /**
+ * Returns the underlying DataOutput: use with extreme care!
+ *
+ * Before using the underlying DataOutput, you must first call
+ * writeRawBegin(size) (which implies you must already know how many bytes
+ * you will write. While writing, or after you are done, you must call
+ * rawWritten(written), so the Packer knows how much you wrote. When you are
+ * done, you must call writeRawEnd(). If the wrong amount of data was
+ * written, according to rawWritten(), writeRawEnd() will fail.
+ * @throws IOException
+ */
+ DataOutput dataOutput() throws IOException;
+
+ /**
+ * Returns the underlying OutputStream: use with extreme care!
+ *
+ * If the underlying DataOutput is an OutputStream, then it will be
+ * returned. If not, the a wrapper OutputStream on top of the DataOutput
+ * will be written instead.
+ *
+ * @see dataOutput() for usage restrictions.
+ *
+ * @throws IOException
+ */
+ OutputStream outputStream() throws IOException;
+
+ /**
+ * Writes a ByteBuffer *content*, between writeRawBegin(size) and
+ * writeRawEnd(). It can be used together with dataOutput(). Note that
+ * writePartial(ByteBuffer) calls rawWritten() directly, while you need to
+ * do this yourself if using dataOutput().
+ *
+ * This method is just an helper, since DataOutput does not directly
+ * support ByteBuffers.
+ */
+ void writePartial(final ByteBuffer o) throws IOException;
+
+ /**
+ * Indicate that 'written' bytes were written to the underlying DataOutput.
+ * You must call this method, when accessing the underlying DataOutput directly.
+ * @throws IOException
+ */
+ void rawWritten(final int written) throws IOException;
+
+ /** Writes a byte. */
+ @Override
+ @Deprecated
+ void writeByte(final int o) throws IOException;
+
+ /** Writes a *byte*. */
+ @Override
+ @Deprecated
+ void write(final int o) throws IOException;
+
+ /** Writes a short. */
+ @Override
+ @Deprecated
+ void writeShort(final int o) throws IOException;
+
+ /** Writes a char. */
+ @Override
+ @Deprecated
+ void writeChar(final int o) throws IOException;
+
+ /** Just delegates to writeUTF(String) */
+ @Override
+ @Deprecated
+ void writeBytes(final String s) throws IOException;
+
+ /** Just delegates to writeUTF(String) */
+ @Override
+ @Deprecated
+ void writeChars(final String s) throws IOException;
+}
diff --git a/src/main/java/com/blockwithme/msgpack/PostDeserListener.java b/src/main/java/com/blockwithme/msgpack/PostDeserListener.java
new file mode 100644
index 000000000..3a1e8dfcd
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/PostDeserListener.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack;
+
+import com.blockwithme.msgpack.templates.UnpackerContext;
+
+/**
+ * We assume that if there is anything to be done right before serializing, or
+ * right after it, the Template can take care of it. Also, the template can
+ * do whatever is needed right after de-serializing. So what is missing it to
+ * be informed that the whole de-serialisation is over.
+ *
+ * @author monster
+ */
+public interface PostDeserListener {
+ /** Called after the graph was de-serialized. */
+ void postDeser(final UnpackerContext context);
+}
diff --git a/src/main/java/com/blockwithme/msgpack/Unpacker.java b/src/main/java/com/blockwithme/msgpack/Unpacker.java
new file mode 100644
index 000000000..c57f2c2d9
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/Unpacker.java
@@ -0,0 +1,212 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 - 2013 FURUHASHI Sadayuki
+//
+// 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 com.blockwithme.msgpack;
+
+import java.io.Closeable;
+import java.io.DataInput;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.Date;
+
+/**
+ * Standard deserializer, implementing the core Message-Pack protocol.
+ *
+ * It also implements DataInput, for easier migration of code, but it is
+ * unlikely that code using DataInput can be ported without modifications.
+ */
+public interface Unpacker extends Closeable, DataInput {
+
+ /** Reads a boolean. */
+ @Override
+ boolean readBoolean() throws IOException;
+
+ /** Reads a byte. */
+ @Override
+ byte readByte() throws IOException;
+
+ /** Reads a short. */
+ @Override
+ short readShort() throws IOException;
+
+ /** Reads a char. */
+ @Override
+ char readChar() throws IOException;
+
+ /** Reads an int. */
+ @Override
+ int readInt() throws IOException;
+
+ /** Reads a long. */
+ @Override
+ long readLong() throws IOException;
+
+ /** Reads a float. */
+ @Override
+ float readFloat() throws IOException;
+
+ /** Reads a double. */
+ @Override
+ double readDouble() throws IOException;
+
+ /** Reads a String. */
+ @Override
+ String readUTF() throws IOException;
+
+ /** Reads a BigInteger. */
+ BigInteger readBigInteger() throws IOException;
+
+ /** Reads a BigDecimal. */
+ BigDecimal readBigDecimal() throws IOException;
+
+ /** Reads a Date. */
+ Date readDate() throws IOException;
+
+ /** Reads a byte array. */
+ byte[] readByteArray() throws IOException;
+
+ /** Reads a ByteBuffer. */
+ ByteBuffer readByteBuffer() throws IOException;
+
+ /** Reads an index written with Packer.writeIndex(int). */
+ int readIndex() throws IOException;
+
+ /** Returns the type of the next value to be read. */
+ ValueType getNextType() throws IOException;
+
+ /** Set the raw size limit. */
+ void setRawSizeLimit(final int size);
+
+ /** Set the array size limit. */
+ void setArraySizeLimit(final int size);
+
+ /** Set the map size limit. */
+ void setMapSizeLimit(final int size);
+
+ /** Skip the next value. */
+ void skip() throws IOException;
+
+ /** Reads an array begin. */
+ int readArrayBegin() throws IOException;
+
+ /** Reads an array end. */
+ void readArrayEnd(final boolean check) throws IOException;
+
+ /** Reads an array end. */
+ void readArrayEnd() throws IOException;
+
+ /** Reads a map begin. */
+ int readMapBegin() throws IOException;
+
+ /** Reads a map end. */
+ void readMapEnd(final boolean check) throws IOException;
+
+ /** Reads a map end. */
+ void readMapEnd() throws IOException;
+
+ /** Reads a nil/null. */
+ void readNil() throws IOException;
+
+ /** Returns true, if a nil/null could be read. */
+ boolean trySkipNil() throws IOException;
+
+ /** Reads a raw begin and return the size. */
+ int readRawBegin() throws IOException;
+
+ /** Reads a raw end. */
+ void readRawEnd() throws IOException;
+
+ /**
+ * Returns the underlying DataInput: use with extreme care!
+ *
+ * Before using the underlying DataInput, you must first call readRawBegin()
+ * which will tell you how many bytes you must read. While reading, or after
+ * you are done, you must call rawRead(read), so the Unpacker knows how much
+ * you read. When you are done, you must call readRawEnd(). If the wrong
+ * amount of data was read, according to rawRead(), readRawEnd() will fail.
+ * @throws IOException
+ */
+ DataInput dataInput() throws IOException;
+
+ /**
+ * Returns the underlying InputStream: use with extreme care!
+ *
+ * If the underlying DataInput is an InputStream, then it will be
+ * returned. If not, the a wrapper InputStream on top of the DataInput
+ * will be written instead.
+ *
+ * @see dataInput() for usage restrictions.
+ *
+ * @throws IOException
+ */
+ InputStream inputStream() throws IOException;
+
+ /**
+ * Reads a ByteBuffer *content*, between readRawBegin() and
+ * readRawEnd(). It can be used together with dataInput(). Note that
+ * readPartialByteBuffer() calls rawRead() directly, while you need to
+ * do this yourself if using dataInput().
+ *
+ * This method is just an helper, since DataInput does not directly support
+ * ByteBuffers.
+ */
+ ByteBuffer readPartialByteBuffer(final int bytes) throws IOException;
+
+ /**
+ * Indicate that 'read' bytes were read to the underlying DataInput.
+ * You must call this method, when accessing the underlying DataInput directly.
+ * @throws IOException
+ */
+ void rawRead(final int read) throws IOException;
+
+ // For DataInput compatibility; not recommended for new code.
+
+ /** readByte() & 0xFF */
+ @Override
+ @Deprecated
+ int readUnsignedByte() throws IOException;
+
+ /** readShort() & 0xFFFF */
+ @Override
+ @Deprecated
+ int readUnsignedShort() throws IOException;
+
+ /** Just delegates to readUTF() */
+ @Override
+ @Deprecated
+ String readLine() throws IOException;
+
+ /** Just delegates to readFully(byte[], 0, byte[].length) */
+ @Override
+ @Deprecated
+ void readFully(final byte b[]) throws IOException;
+
+ /** Reads a raw into b. The raw must be exactly of length len. */
+ @Override
+ @Deprecated
+ void readFully(final byte b[], final int off, final int length)
+ throws IOException;
+
+ /** Skips a raw. n is ignored. The raw size is returned. */
+ @Override
+ @Deprecated
+ int skipBytes(final int n) throws IOException;
+
+}
diff --git a/src/main/java/org/msgpack/type/ValueType.java b/src/main/java/com/blockwithme/msgpack/ValueType.java
similarity index 87%
rename from src/main/java/org/msgpack/type/ValueType.java
rename to src/main/java/com/blockwithme/msgpack/ValueType.java
index 2651567e2..ad111c3a7 100644
--- a/src/main/java/org/msgpack/type/ValueType.java
+++ b/src/main/java/com/blockwithme/msgpack/ValueType.java
@@ -15,8 +15,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.type;
+package com.blockwithme.msgpack;
+/** All the supported data-type of the core Message-Pack protocol. */
public enum ValueType {
NIL, BOOLEAN, INTEGER, FLOAT, ARRAY, MAP, RAW;
}
diff --git a/src/main/java/com/blockwithme/msgpack/impl/AbstractPacker.java b/src/main/java/com/blockwithme/msgpack/impl/AbstractPacker.java
new file mode 100644
index 000000000..ef30d66cb
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/impl/AbstractPacker.java
@@ -0,0 +1,282 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 - 2013 FURUHASHI Sadayuki
+//
+// 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 com.blockwithme.msgpack.impl;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.Date;
+
+import com.blockwithme.msgpack.Packer;
+
+/**
+ * The Abstract Packer reuses the code form the original Java implementation
+ * of the Abstract Packer.
+ *
+ * It is limited to the core protocol implementation, without support for Java
+ * objects.
+ *
+ * @author monster
+ */
+public abstract class AbstractPacker implements Packer {
+
+ /** Deduce from index to optimize storage. */
+ public static final int INDEX_OFFSET = 31;
+
+ @Override
+ public void writeBoolean(final Boolean o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeBoolean(o);
+ }
+
+ }
+
+ @Override
+ public void writeByte(final Byte o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeByte(o);
+ }
+
+ }
+
+ @Override
+ public void writeShort(final Short o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeShort(o);
+ }
+
+ }
+
+ @Override
+ public void writeCharacter(final Character o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeChar(o);
+ }
+
+ }
+
+ @Override
+ public void writeInteger(final Integer o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeInt(o);
+ }
+
+ }
+
+ @Override
+ public void writeLong(final Long o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeLong(o);
+ }
+
+ }
+
+ @Override
+ public void writeBigInteger(final BigInteger o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeBigInteger(o, true);
+ }
+
+ }
+
+ @Override
+ public void writeBigDecimal(final BigDecimal o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeBigInteger(o.unscaledValue(), false);
+ writeInt(o.scale());
+ }
+
+ }
+
+ @Override
+ public void writeFloat(final Float o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeFloat(o);
+ }
+
+ }
+
+ @Override
+ public void writeDouble(final Double o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeDouble(o);
+ }
+
+ }
+
+ /** Writes a Date out. */
+ @Override
+ public void writeDate(final Date o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeLong(o.getTime());
+ }
+
+ }
+
+ @Override
+ public void write(final byte[] o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeByteArray(o);
+ }
+
+ }
+
+ @Override
+ public void write(final byte[] o, final int off, final int len)
+ throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeByteArray(o, off, len);
+ }
+
+ }
+
+ @Override
+ public void writeByteBuffer(final ByteBuffer o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeByteBuffer2(o);
+ }
+
+ }
+
+ @Override
+ public void writeUTF(final String o) throws IOException {
+ if (o == null) {
+ writeNil();
+ } else {
+ writeString(o);
+ }
+
+ }
+
+ @Override
+ public void writeArrayEnd() throws IOException {
+ writeArrayEnd(true);
+
+ }
+
+ @Override
+ public void writeMapEnd() throws IOException {
+ writeMapEnd(true);
+
+ }
+
+ /**
+ * Deduce 31 from the index, so it is more likely to be saved as one byte.
+ * This methods should be used for normally non-negative integers.
+ * -1 also stores as one byte.
+ */
+ @Override
+ public void writeIndex(final int index) throws IOException {
+ writeInt(index - INDEX_OFFSET);
+
+ }
+
+ /** Writes a byte. */
+ @Override
+ @Deprecated
+ public void writeByte(final int o) throws IOException {
+ writeByte((byte) o);
+ }
+
+ /** Writes a short. */
+ @Override
+ @Deprecated
+ public void writeShort(final int o) throws IOException {
+ writeShort((short) o);
+ }
+
+ /** Writes a char. */
+ @Override
+ @Deprecated
+ public void writeChar(final int o) throws IOException {
+ writeChar((char) o);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Packer#writeBytes(java.lang.String)
+ */
+ @Override
+ @Deprecated
+ public void writeBytes(final String s) throws IOException {
+ writeUTF(s);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Packer#writeChars(java.lang.String)
+ */
+ @Override
+ @Deprecated
+ public void writeChars(final String s) throws IOException {
+ writeUTF(s);
+ }
+
+ /** Writes a *byte*. */
+ @Override
+ @Deprecated
+ public void write(final int o) throws IOException {
+ writeByte((byte) o);
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+
+ abstract protected void writeBigInteger(final BigInteger v,
+ final boolean countAaValue) throws IOException;
+
+ protected void writeByteArray(final byte[] b) throws IOException {
+ writeByteArray(b, 0, b.length);
+ }
+
+ abstract protected void writeByteArray(final byte[] b, final int off,
+ final int len) throws IOException;
+
+ abstract protected void writeByteBuffer2(final ByteBuffer bb)
+ throws IOException;
+
+ abstract protected void writeString(final String s) throws IOException;
+}
diff --git a/src/main/java/com/blockwithme/msgpack/impl/AbstractUnpacker.java b/src/main/java/com/blockwithme/msgpack/impl/AbstractUnpacker.java
new file mode 100644
index 000000000..5b396da6c
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/impl/AbstractUnpacker.java
@@ -0,0 +1,178 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 - 2013 FURUHASHI Sadayuki
+//
+// 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 com.blockwithme.msgpack.impl;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.Date;
+
+import com.blockwithme.msgpack.Unpacker;
+
+/**
+ * The Abstract Unpacker reuses the code form the original Java implementation
+ * of the Abstract Unpacker.
+ *
+ * It is limited to the core protocol implementation, without support for Java
+ * objects.
+ *
+ * @author monster
+ */
+public abstract class AbstractUnpacker implements Unpacker {
+ protected int rawSizeLimit = 134217728;
+
+ protected int arraySizeLimit = 4194304;
+
+ protected int mapSizeLimit = 2097152;
+
+ /** Reads a Date. */
+ @Override
+ public Date readDate() throws IOException {
+ if (trySkipNil()) {
+ return null;
+ }
+ return new Date(readLong());
+ }
+
+ @Override
+ public ByteBuffer readByteBuffer() throws IOException {
+ return ByteBuffer.wrap(readByteArray());
+ }
+
+ @Override
+ public void readArrayEnd() throws IOException {
+ readArrayEnd(false);
+ }
+
+ @Override
+ public void readMapEnd() throws IOException {
+ readMapEnd(false);
+ }
+
+ @Override
+ public void setRawSizeLimit(final int size) {
+ if (size < 32) {
+ rawSizeLimit = 32;
+ } else {
+ rawSizeLimit = size;
+ }
+ }
+
+ @Override
+ public void setArraySizeLimit(final int size) {
+ if (size < 16) {
+ arraySizeLimit = 16;
+ } else {
+ arraySizeLimit = size;
+ }
+ }
+
+ @Override
+ public void setMapSizeLimit(final int size) {
+ if (size < 16) {
+ mapSizeLimit = 16;
+ } else {
+ mapSizeLimit = size;
+ }
+ }
+
+ @Override
+ public BigDecimal readBigDecimal() throws IOException {
+ final BigInteger unscaledVal = readBigInteger(false);
+ if (unscaledVal == null) {
+ return null;
+ }
+ final int scale = readInt();
+ return new BigDecimal(unscaledVal, scale);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readUnsignedByte()
+ */
+ @Override
+ @Deprecated
+ public int readUnsignedByte() throws IOException {
+ return readByte() & 0xFF;
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readUnsignedShort()
+ */
+ @Override
+ @Deprecated
+ public int readUnsignedShort() throws IOException {
+ return readShort() & 0xFFFF;
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readLine()
+ */
+ @Override
+ @Deprecated
+ public String readLine() throws IOException {
+ return readUTF();
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#skipBytes(int)
+ */
+ @Override
+ @Deprecated
+ public int skipBytes(final int n) throws IOException {
+ final byte[] raw = readByteArray();
+ return (raw == null) ? -1 : raw.length;
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readFully(byte[])
+ */
+ @Override
+ @Deprecated
+ public void readFully(final byte[] b) throws IOException {
+ readFully(b, 0, b.length);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readFully(byte[], int, int)
+ */
+ @Override
+ @Deprecated
+ public void readFully(final byte[] b, final int off, final int length)
+ throws IOException {
+ final byte[] raw = readByteArray();
+ if ((raw == null) || (raw.length != length)) {
+ throw new IOException("Could not read " + length + " bytes raw");
+ }
+ System.arraycopy(raw, 0, b, off, length);
+ }
+
+ /** Reads an index written with Packer.writeIndex(int). */
+ @Override
+ public int readIndex() throws IOException {
+ return readInt() + AbstractPacker.INDEX_OFFSET;
+ }
+
+ /** Checks if we are within a raw read, and fails if not. */
+ protected abstract void checkInRawRead() throws IOException;
+
+ protected abstract BigInteger readBigInteger(final boolean countAaValue)
+ throws IOException;
+
+ protected abstract boolean tryReadNil() throws IOException;
+}
diff --git a/src/main/java/com/blockwithme/msgpack/impl/ByteArraySlice.java b/src/main/java/com/blockwithme/msgpack/impl/ByteArraySlice.java
new file mode 100644
index 000000000..3b06e2f31
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/impl/ByteArraySlice.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack.impl;
+
+/**
+ * Small wrapper object, needed to pass a byte[] slice to a Template as a
+ * single object.
+ *
+ * @author monster
+ */
+public class ByteArraySlice {
+
+ public final byte[] o;
+ public final int off;
+ public final int len;
+
+ /** Creates a byte[] slice */
+ public ByteArraySlice(final byte[] o, final int off, final int len) {
+ this.o = o;
+ this.off = off;
+ this.len = len;
+ }
+}
diff --git a/src/main/java/com/blockwithme/msgpack/impl/DataInputStreamWrapper.java b/src/main/java/com/blockwithme/msgpack/impl/DataInputStreamWrapper.java
new file mode 100644
index 000000000..cb0fb8982
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/impl/DataInputStreamWrapper.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack.impl;
+
+import java.io.Closeable;
+import java.io.DataInput;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Objects;
+
+/**
+ * Wraps an DataInput into an InputStream.
+ *
+ * @author monster
+ */
+public class DataInputStreamWrapper extends InputStream {
+ /** The DataInput */
+ private final DataInput dataInput;
+
+ /** Wraps a DataInput */
+ public DataInputStreamWrapper(final DataInput dataInput) {
+ this.dataInput = Objects.requireNonNull(dataInput);
+ }
+
+ @Override
+ public int read() throws IOException {
+ return dataInput.readByte();
+ }
+
+ @Override
+ public int read(final byte b[]) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ @Override
+ public int read(final byte b[], final int off, final int len)
+ throws IOException {
+ dataInput.readFully(b, off, len);
+ return len;
+ }
+
+ @Override
+ public long skip(final long n) throws IOException {
+ if (n > Integer.MAX_VALUE) {
+ return dataInput.skipBytes(Integer.MAX_VALUE);
+ }
+ return dataInput.skipBytes((int) n);
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (dataInput instanceof Closeable) {
+ ((Closeable) dataInput).close();
+ }
+ }
+}
diff --git a/src/main/java/com/blockwithme/msgpack/impl/DataOutputWrapperStream.java b/src/main/java/com/blockwithme/msgpack/impl/DataOutputWrapperStream.java
new file mode 100644
index 000000000..14444806f
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/impl/DataOutputWrapperStream.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack.impl;
+
+import java.io.Closeable;
+import java.io.DataOutput;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Objects;
+
+/**
+ * DataOutputWrapperStream is an OutputStream that wraps a DataOutput.
+ *
+ * @author monster
+ */
+public class DataOutputWrapperStream extends OutputStream {
+
+ /** The DataOutput */
+ private final DataOutput dataOutput;
+
+ /** Wraps a DataOutput. */
+ public DataOutputWrapperStream(final DataOutput dataOutput) {
+ this.dataOutput = Objects.requireNonNull(dataOutput);
+ }
+
+ @Override
+ public void write(final int b) throws IOException {
+ dataOutput.write(b);
+ }
+
+ @Override
+ public void write(final byte b[]) throws IOException {
+ dataOutput.write(b);
+ }
+
+ @Override
+ public void write(final byte b[], final int off, final int len)
+ throws IOException {
+ dataOutput.write(b, off, len);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (dataOutput instanceof Flushable) {
+ ((Flushable) dataOutput).flush();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (dataOutput instanceof Closeable) {
+ ((Closeable) dataOutput).close();
+ }
+ }
+}
diff --git a/src/main/java/com/blockwithme/msgpack/impl/MessagePackPacker.java b/src/main/java/com/blockwithme/msgpack/impl/MessagePackPacker.java
new file mode 100644
index 000000000..fe4ee7184
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/impl/MessagePackPacker.java
@@ -0,0 +1,519 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 - 2013 FURUHASHI Sadayuki
+//
+// 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 com.blockwithme.msgpack.impl;
+
+import java.io.Closeable;
+import java.io.DataOutput;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+/**
+ * The MessagePack Packer reuses the code form the original Java implementation
+ * of the MessagePack Packer.
+ *
+ * It is limited to the core protocol implementation, without support for Java
+ * objects.
+ *
+ * @author monster
+ */
+public class MessagePackPacker extends AbstractPacker {
+ protected final DataOutput out;
+ protected final OutputStream outputStream;
+
+ /** Amounts of raw bytes still to be written. */
+ private int rawToWrite;
+
+ /** True if we are in a raw write. */
+ private boolean inRawWrite;
+
+ private final PackerStack stack = new PackerStack();
+
+ public MessagePackPacker(final DataOutput out) {
+ this.out = Objects.requireNonNull(out);
+ if (out instanceof OutputStream) {
+ outputStream = (OutputStream) out;
+ } else {
+ outputStream = new DataOutputWrapperStream(out);
+ }
+ }
+
+ @Override
+ public void writeByte(final byte d) throws IOException {
+ if (d < -(1 << 5)) {
+ out.writeByte((byte) 0xd0);
+ out.writeByte(d);
+ } else {
+ out.writeByte(d);
+ }
+ stack.reduceCount();
+ }
+
+ @Override
+ public void writeShort(final short d) throws IOException {
+ if (d < -(1 << 5)) {
+ if (d < -(1 << 7)) {
+ // signed 16
+ out.writeByte((byte) 0xd1);
+ out.writeShort(d);
+ } else {
+ // signed 8
+ out.writeByte((byte) 0xd0);
+ out.writeByte((byte) d);
+ }
+ } else if (d < (1 << 7)) {
+ // fixnum
+ out.writeByte((byte) d);
+ } else {
+ if (d < (1 << 8)) {
+ // unsigned 8
+ out.writeByte((byte) 0xcc);
+ out.writeByte((byte) d);
+ } else {
+ // unsigned 16
+ out.writeByte((byte) 0xcd);
+ out.writeShort(d);
+ }
+ }
+ stack.reduceCount();
+ }
+
+ @Override
+ public void writeChar(final char d) throws IOException {
+ if (d < -(1 << 5)) {
+ if (d < -(1 << 7)) {
+ // signed 16
+ out.writeByte((byte) 0xd1);
+ out.writeShort((short) d);
+ } else {
+ // signed 8
+ out.writeByte((byte) 0xd0);
+ out.writeByte((byte) d);
+ }
+ } else if (d < (1 << 7)) {
+ // fixnum
+ out.writeByte((byte) d);
+ } else {
+ if (d < (1 << 8)) {
+ // unsigned 8
+ out.writeByte((byte) 0xcc);
+ out.writeByte((byte) d);
+ } else {
+ // unsigned 16
+ out.writeByte((byte) 0xcd);
+ out.writeShort((short) d);
+ }
+ }
+ stack.reduceCount();
+ }
+
+ @Override
+ public void writeInt(final int d) throws IOException {
+ if (d < -(1 << 5)) {
+ if (d < -(1 << 15)) {
+ // signed 32
+ out.writeByte((byte) 0xd2);
+ out.writeInt(d);
+ } else if (d < -(1 << 7)) {
+ // signed 16
+ out.writeByte((byte) 0xd1);
+ out.writeShort((short) d);
+ } else {
+ // signed 8
+ out.writeByte((byte) 0xd0);
+ out.writeByte((byte) d);
+ }
+ } else if (d < (1 << 7)) {
+ // fixnum
+ out.writeByte((byte) d);
+ } else {
+ if (d < (1 << 8)) {
+ // unsigned 8
+ out.writeByte((byte) 0xcc);
+ out.writeByte((byte) d);
+ } else if (d < (1 << 16)) {
+ // unsigned 16
+ out.writeByte((byte) 0xcd);
+ out.writeShort((short) d);
+ } else {
+ // unsigned 32
+ out.writeByte((byte) 0xce);
+ out.writeInt(d);
+ }
+ }
+ stack.reduceCount();
+ }
+
+ @Override
+ public void writeLong(final long d) throws IOException {
+ if (d < -(1L << 5)) {
+ if (d < -(1L << 15)) {
+ if (d < -(1L << 31)) {
+ // signed 64
+ out.writeByte((byte) 0xd3);
+ out.writeLong(d);
+ } else {
+ // signed 32
+ out.writeByte((byte) 0xd2);
+ out.writeInt((int) d);
+ }
+ } else {
+ if (d < -(1 << 7)) {
+ // signed 16
+ out.writeByte((byte) 0xd1);
+ out.writeShort((short) d);
+ } else {
+ // signed 8
+ out.writeByte((byte) 0xd0);
+ out.writeByte((byte) d);
+ }
+ }
+ } else if (d < (1 << 7)) {
+ // fixnum
+ out.writeByte((byte) d);
+ } else {
+ if (d < (1L << 16)) {
+ if (d < (1 << 8)) {
+ // unsigned 8
+ out.writeByte((byte) 0xcc);
+ out.writeByte((byte) d);
+ } else {
+ // unsigned 16
+ out.writeByte((byte) 0xcd);
+ out.writeShort((short) d);
+ }
+ } else {
+ if (d < (1L << 32)) {
+ // unsigned 32
+ out.writeByte((byte) 0xce);
+ out.writeInt((int) d);
+ } else {
+ // unsigned 64
+ out.writeByte((byte) 0xcf);
+ out.writeLong(d);
+ }
+ }
+ }
+ stack.reduceCount();
+ }
+
+ @Override
+ protected void writeBigInteger(final BigInteger d,
+ final boolean countAaValue) throws IOException {
+ if (d.bitLength() <= 63) {
+ writeLong(d.longValue());
+ if (countAaValue) {
+ stack.reduceCount();
+ }
+ } else if (d.bitLength() == 64 && d.signum() == 1) {
+ // unsigned 64
+ out.writeByte((byte) 0xcf);
+ out.writeLong(d.longValue());
+ if (countAaValue) {
+ stack.reduceCount();
+ }
+ } else {
+ throw new IOException(
+ "MessagePack can't serialize BigInteger larger than (2^64)-1");
+ }
+ }
+
+ @Override
+ public void writeFloat(final float d) throws IOException {
+ out.writeByte((byte) 0xca);
+ out.writeFloat(d);
+ stack.reduceCount();
+ }
+
+ @Override
+ public void writeDouble(final double d) throws IOException {
+ out.writeByte((byte) 0xcb);
+ out.writeDouble(d);
+ stack.reduceCount();
+ }
+
+ @Override
+ public void writeBoolean(final boolean d) throws IOException {
+ if (d) {
+ // true
+ out.writeByte((byte) 0xc3);
+ } else {
+ // false
+ out.writeByte((byte) 0xc2);
+ }
+ stack.reduceCount();
+ }
+
+ @Override
+ protected void writeByteArray(final byte[] b, final int off, final int len)
+ throws IOException {
+ writeRawBegin(len);
+ out.write(b, off, len);
+ rawWritten(len);
+ writeRawEnd();
+ }
+
+ /**
+ * Writes a ByteBuffer *content*, between writeRawBegin(size) and
+ * writeRawEnd(). It can be used together with dataOutput(). Note that
+ * writePartial(ByteBuffer) calls rawWritten() directly, while you need to
+ * do this yourself if using dataOutput().
+ */
+ @Override
+ public void writePartial(final ByteBuffer bb) throws IOException {
+ checkInRawWrite();
+ final int len = bb.remaining();
+ final int pos = bb.position();
+ try {
+ if (bb.hasArray()) {
+ final byte[] array = bb.array();
+ final int offset = bb.arrayOffset();
+ out.write(array, offset, len);
+ } else {
+ final byte[] buf = new byte[len];
+ bb.get(buf);
+ out.write(buf);
+ }
+ rawWritten(len);
+ } finally {
+ bb.position(pos);
+ }
+
+ }
+
+ @Override
+ protected void writeByteBuffer2(final ByteBuffer bb) throws IOException {
+ final int len = bb.remaining();
+ writeRawBegin(len);
+ writePartial(bb);
+ writeRawEnd();
+ }
+
+ @Override
+ protected void writeString(final String s) throws IOException {
+ byte[] b;
+ try {
+ // TODO encoding error?
+ b = s.getBytes("UTF-8");
+ } catch (final UnsupportedEncodingException ex) {
+ throw new IOException(ex);
+ }
+ writeByteArray(b, 0, b.length);
+ }
+
+ @Override
+ public void writeNil() throws IOException {
+ out.writeByte((byte) 0xc0);
+ stack.reduceCount();
+
+ }
+
+ @Override
+ public void writeArrayBegin(final int size) throws IOException {
+ // TODO check size < 0?
+ if (size < 16) {
+ // FixArray
+ out.writeByte((byte) (0x90 | size));
+ } else if (size < 65536) {
+ out.writeByte((byte) 0xdc);
+ out.writeShort((short) size);
+ } else {
+ out.writeByte((byte) 0xdd);
+ out.writeInt(size);
+ }
+ stack.reduceCount();
+ stack.pushArray(size);
+
+ }
+
+ @Override
+ public void writeArrayEnd(final boolean check) throws IOException {
+ if (!stack.topIsArray()) {
+ throw new IOException(
+ "writeArrayEnd() is called but writeArrayBegin() is not called");
+ }
+
+ final int remain = stack.getTopCount();
+ if (remain > 0) {
+ if (check) {
+ throw new IOException(
+ "writeArrayEnd(check=true) is called but the array is not end: "
+ + remain);
+ }
+ for (int i = 0; i < remain; i++) {
+ writeNil();
+ }
+ }
+ stack.pop();
+
+ }
+
+ @Override
+ public void writeMapBegin(final int size) throws IOException {
+ // TODO check size < 0?
+ if (size < 16) {
+ // FixMap
+ out.writeByte((byte) (0x80 | size));
+ } else if (size < 65536) {
+ out.writeByte((byte) 0xde);
+ out.writeShort((short) size);
+ } else {
+ out.writeByte((byte) 0xdf);
+ out.writeInt(size);
+ }
+ stack.reduceCount();
+ stack.pushMap(size);
+
+ }
+
+ @Override
+ public void writeMapEnd(final boolean check) throws IOException {
+ if (!stack.topIsMap()) {
+ throw new IOException(
+ "writeMapEnd() is called but writeMapBegin() is not called");
+ }
+
+ final int remain = stack.getTopCount();
+ if (remain > 0) {
+ if (check) {
+ throw new IOException(
+ "writeMapEnd(check=true) is called but the map is not end: "
+ + remain);
+ }
+ for (int i = 0; i < remain; i++) {
+ writeNil();
+ }
+ }
+ stack.pop();
+
+ }
+
+ /**
+ * Returns the underlying DataOutput: use with extreme care!
+ *
+ * Before using the underlying DataOutput, you must first call
+ * writeRawBegin(size) (which implies you must already know how many bytes
+ * you will write. While writing, or after you are done, you must call
+ * rawWritten(written), so the Packer knows how much you wrote. When you are
+ * done, you must call writeRawEnd(). If the wrong amount of data was
+ * written, according to rawWritten(), writeRawEnd() will fail.
+ * @throws IOException
+ */
+ @Override
+ public DataOutput dataOutput() throws IOException {
+ checkInRawWrite();
+ return out;
+ }
+
+ /**
+ * Returns the underlying OutputStream: use with extreme care!
+ *
+ * If the underlying DataOutput is an OutputStream, then it will be
+ * returned. If not, the a wrapper OutputStream on top of the DataOutput
+ * will be written instead.
+ *
+ * @throws IOException
+ */
+ @Override
+ public OutputStream outputStream() throws IOException {
+ checkInRawWrite();
+ return outputStream;
+ }
+
+ /**
+ * Indicate that 'written' bytes were written to the underlying DataOutput.
+ * You must call this method, when accessing the underlying DataOutput directly.
+ * @throws IOException
+ */
+ @Override
+ public void rawWritten(final int written) throws IOException {
+ checkInRawWrite();
+ rawToWrite -= written;
+ }
+
+ /** Writes an raw begin. */
+ @Override
+ public void writeRawBegin(final int len) throws IOException {
+ if (inRawWrite) {
+ throw new IOException("Last raw write not terminated!");
+ }
+ if (len < 32) {
+ out.writeByte((byte) (0xa0 | len));
+ } else if (len < 65536) {
+ out.writeByte((byte) 0xda);
+ out.writeShort((short) len);
+ } else {
+ out.writeByte((byte) 0xdb);
+ out.writeInt(len);
+ }
+ rawToWrite = len;
+ stack.reduceCount();
+ stack.pushRaw();
+ inRawWrite = true;
+ }
+
+ /** Writes an raw end. */
+ @Override
+ public void writeRawEnd() throws IOException {
+ checkInRawWrite();
+ // We moved the single raw reduceCOunt() here.
+ stack.reduceCount();
+ if (!stack.topIsRaw()) {
+ throw new IOException(
+ "writeRawEnd() is called but writeRawBegin() is not called");
+ }
+
+ if (rawToWrite > 0) {
+ throw new IOException("Last raw write not terminated!");
+ }
+ if (rawToWrite < 0) {
+ throw new IOException("Last raw write too big!");
+ }
+ stack.pop();
+ inRawWrite = false;
+ }
+
+ public void reset() {
+ stack.clear();
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (out instanceof Flushable) {
+ ((Flushable) out).flush();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (out instanceof Closeable) {
+ ((Closeable) out).close();
+ }
+ }
+
+ /** Checks if we are within a raw write, and fails if not. */
+ protected void checkInRawWrite() throws IOException {
+ if (!inRawWrite) {
+ throw new IOException("Not in raw write");
+ }
+ }
+}
diff --git a/src/main/java/org/msgpack/unpacker/MessagePackUnpacker.java b/src/main/java/com/blockwithme/msgpack/impl/MessagePackUnpacker.java
similarity index 58%
rename from src/main/java/org/msgpack/unpacker/MessagePackUnpacker.java
rename to src/main/java/com/blockwithme/msgpack/impl/MessagePackUnpacker.java
index f704f1717..93ce14475 100644
--- a/src/main/java/org/msgpack/unpacker/MessagePackUnpacker.java
+++ b/src/main/java/com/blockwithme/msgpack/impl/MessagePackUnpacker.java
@@ -15,24 +15,43 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.unpacker;
+package com.blockwithme.msgpack.impl;
+import java.io.Closeable;
+import java.io.DataInput;
import java.io.IOException;
-import java.io.EOFException;
import java.io.InputStream;
import java.math.BigInteger;
-import org.msgpack.io.Input;
-import org.msgpack.io.StreamInput;
-import org.msgpack.io.BufferReferer;
-import org.msgpack.MessagePack;
-import org.msgpack.MessageTypeException;
-import org.msgpack.packer.Unconverter;
-import org.msgpack.type.ValueType;
-
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+import com.blockwithme.msgpack.ValueType;
+import com.blockwithme.msgpack.impl.accept.Accept;
+import com.blockwithme.msgpack.impl.accept.ArrayAccept;
+import com.blockwithme.msgpack.impl.accept.BigIntegerAccept;
+import com.blockwithme.msgpack.impl.accept.ByteArrayAccept;
+import com.blockwithme.msgpack.impl.accept.DoubleAccept;
+import com.blockwithme.msgpack.impl.accept.IntAccept;
+import com.blockwithme.msgpack.impl.accept.LongAccept;
+import com.blockwithme.msgpack.impl.accept.MapAccept;
+import com.blockwithme.msgpack.impl.accept.SkipAccept;
+import com.blockwithme.msgpack.impl.accept.StringAccept;
+import com.blockwithme.util.DataInputBuffer;
+
+/**
+ * The MessagePack Unpacker reuses the code form the original Java implementation
+ * of the MessagePack Unpacker.
+ *
+ * It is limited to the core protocol implementation, without support for Java
+ * objects.
+ *
+ * @author monster
+ */
public class MessagePackUnpacker extends AbstractUnpacker {
private static final byte REQUIRE_TO_READ_HEAD = (byte) 0xc6;
- protected final Input in;
+ private final DataInput in;
+ private final InputStream inputStream;
private final UnpackerStack stack = new UnpackerStack();
private byte headByte = REQUIRE_TO_READ_HEAD;
@@ -48,16 +67,27 @@ public class MessagePackUnpacker extends AbstractUnpacker {
private final StringAccept stringAccept = new StringAccept();
private final ArrayAccept arrayAccept = new ArrayAccept();
private final MapAccept mapAccept = new MapAccept();
- private final ValueAccept valueAccept = new ValueAccept();
private final SkipAccept skipAccept = new SkipAccept();
- public MessagePackUnpacker(MessagePack msgpack, InputStream stream) {
- this(msgpack, new StreamInput(stream));
- }
+ /** Are we in read raw? */
+ private boolean inReadRaw;
+
+ /** Bytes to read in read raw. */
+ private int readRawToRead;
+
+ /** Temporary DataInput, used only during raw read. */
+ private DataInput tempRawReadDataInput;
+
+ /** Temporary InputStream, used only during raw read. */
+ private InputStream tempInputStream;
- protected MessagePackUnpacker(MessagePack msgpack, Input in) {
- super(msgpack);
- this.in = in;
+ public MessagePackUnpacker(final DataInput in) {
+ this.in = Objects.requireNonNull(in);
+ if (in instanceof InputStream) {
+ inputStream = (InputStream) in;
+ } else {
+ inputStream = new DataInputStreamWrapper(in);
+ }
}
private byte getHeadByte() throws IOException {
@@ -68,14 +98,14 @@ private byte getHeadByte() throws IOException {
return b;
}
- final void readOne(Accept a) throws IOException {
+ final void readOne(final Accept a) throws IOException {
stack.checkCount();
if (readOneWithoutStack(a)) {
stack.reduceCount();
}
}
- final boolean readOneWithoutStack(Accept a) throws IOException {
+ final boolean readOneWithoutStack(final Accept a) throws IOException {
if (raw != null) {
readRawBodyCont();
a.acceptRaw(raw);
@@ -84,7 +114,7 @@ final boolean readOneWithoutStack(Accept a) throws IOException {
return true;
}
- final int b = (int) getHeadByte();
+ final int b = getHeadByte();
if ((b & 0x80) == 0) { // Positive Fixnum
// System.out.println("positive fixnum "+b);
@@ -101,23 +131,21 @@ final boolean readOneWithoutStack(Accept a) throws IOException {
}
if ((b & 0xe0) == 0xa0) { // FixRaw
- int count = b & 0x1f;
+ final int count = b & 0x1f;
if (count == 0) {
a.acceptEmptyRaw();
headByte = REQUIRE_TO_READ_HEAD;
return true;
}
- if (!tryReferRawBody(a, count)) {
- readRawBody(count);
- a.acceptRaw(raw);
- raw = null;
- }
+ readRawBody(count);
+ a.acceptRaw(raw);
+ raw = null;
headByte = REQUIRE_TO_READ_HEAD;
return true;
}
if ((b & 0xf0) == 0x90) { // FixArray
- int count = b & 0x0f;
+ final int count = b & 0x0f;
// System.out.println("fixarray count:"+count);
a.acceptArray(count);
stack.reduceCount();
@@ -127,7 +155,7 @@ final boolean readOneWithoutStack(Accept a) throws IOException {
}
if ((b & 0xf0) == 0x80) { // FixMap
- int count = b & 0x0f;
+ final int count = b & 0x0f;
// System.out.println("fixmap count:"+count/2);
a.acceptMap(count);
stack.reduceCount();
@@ -139,7 +167,7 @@ final boolean readOneWithoutStack(Accept a) throws IOException {
return readOneWithoutStackLarge(a, b);
}
- private boolean readOneWithoutStackLarge(Accept a, final int b)
+ private boolean readOneWithoutStackLarge(final Accept a, final int b)
throws IOException {
switch (b & 0xff) {
case 0xc0: // nil
@@ -155,164 +183,142 @@ private boolean readOneWithoutStackLarge(Accept a, final int b)
headByte = REQUIRE_TO_READ_HEAD;
return true;
case 0xca: // float
- a.acceptFloat(in.getFloat());
- in.advance();
+ a.acceptFloat(in.readFloat());
headByte = REQUIRE_TO_READ_HEAD;
return true;
case 0xcb: // double
- a.acceptDouble(in.getDouble());
- in.advance();
+ a.acceptDouble(in.readDouble());
headByte = REQUIRE_TO_READ_HEAD;
return true;
case 0xcc: // unsigned int 8
- a.acceptUnsignedInteger(in.getByte());
- in.advance();
+ a.acceptUnsignedInteger(in.readByte());
headByte = REQUIRE_TO_READ_HEAD;
return true;
case 0xcd: // unsigned int 16
- a.acceptUnsignedInteger(in.getShort());
- in.advance();
+ a.acceptUnsignedInteger(in.readShort());
headByte = REQUIRE_TO_READ_HEAD;
return true;
case 0xce: // unsigned int 32
- a.acceptUnsignedInteger(in.getInt());
- in.advance();
+ a.acceptUnsignedInteger(in.readInt());
headByte = REQUIRE_TO_READ_HEAD;
return true;
case 0xcf: // unsigned int 64
- a.acceptUnsignedInteger(in.getLong());
- in.advance();
+ a.acceptUnsignedInteger(in.readLong());
headByte = REQUIRE_TO_READ_HEAD;
return true;
case 0xd0: // signed int 8
- a.acceptInteger(in.getByte());
- in.advance();
+ a.acceptInteger(in.readByte());
headByte = REQUIRE_TO_READ_HEAD;
return true;
case 0xd1: // signed int 16
- a.acceptInteger(in.getShort());
- in.advance();
+ a.acceptInteger(in.readShort());
headByte = REQUIRE_TO_READ_HEAD;
return true;
case 0xd2: // signed int 32
- a.acceptInteger(in.getInt());
- in.advance();
+ a.acceptInteger(in.readInt());
headByte = REQUIRE_TO_READ_HEAD;
return true;
case 0xd3: // signed int 64
- a.acceptInteger(in.getLong());
- in.advance();
+ a.acceptInteger(in.readLong());
headByte = REQUIRE_TO_READ_HEAD;
return true;
case 0xda: // raw 16
{
- int count = in.getShort() & 0xffff;
+ final int count = in.readShort() & 0xffff;
if (count == 0) {
a.acceptEmptyRaw();
- in.advance();
headByte = REQUIRE_TO_READ_HEAD;
return true;
}
if (count >= rawSizeLimit) {
- String reason = String.format(
- "Size of raw (%d) over limit at %d",
- new Object[] { count, rawSizeLimit });
- throw new SizeLimitException(reason);
- }
- in.advance();
- if (!tryReferRawBody(a, count)) {
- readRawBody(count);
- a.acceptRaw(raw);
- raw = null;
+ final String reason = String.format(
+ "Size of raw (%d) over limit at %d", new Object[] {
+ count, rawSizeLimit });
+ throw new IOException(reason);
}
+ readRawBody(count);
+ a.acceptRaw(raw);
+ raw = null;
headByte = REQUIRE_TO_READ_HEAD;
return true;
}
case 0xdb: // raw 32
{
- int count = in.getInt();
+ final int count = in.readInt();
if (count == 0) {
a.acceptEmptyRaw();
- in.advance();
headByte = REQUIRE_TO_READ_HEAD;
return true;
}
if (count < 0 || count >= rawSizeLimit) {
- String reason = String.format(
- "Size of raw (%d) over limit at %d",
- new Object[] { count, rawSizeLimit });
- throw new SizeLimitException(reason);
- }
- in.advance();
- if (!tryReferRawBody(a, count)) {
- readRawBody(count);
- a.acceptRaw(raw);
- raw = null;
+ final String reason = String.format(
+ "Size of raw (%d) over limit at %d", new Object[] {
+ count, rawSizeLimit });
+ throw new IOException(reason);
}
+ readRawBody(count);
+ a.acceptRaw(raw);
+ raw = null;
headByte = REQUIRE_TO_READ_HEAD;
return true;
}
case 0xdc: // array 16
{
- int count = in.getShort() & 0xffff;
+ final int count = in.readShort() & 0xffff;
if (count >= arraySizeLimit) {
- String reason = String.format(
- "Size of array (%d) over limit at %d",
- new Object[] { count, arraySizeLimit });
- throw new SizeLimitException(reason);
+ final String reason = String.format(
+ "Size of array (%d) over limit at %d", new Object[] {
+ count, arraySizeLimit });
+ throw new IOException(reason);
}
a.acceptArray(count);
stack.reduceCount();
stack.pushArray(count);
- in.advance();
headByte = REQUIRE_TO_READ_HEAD;
return false;
}
case 0xdd: // array 32
{
- int count = in.getInt();
+ final int count = in.readInt();
if (count < 0 || count >= arraySizeLimit) {
- String reason = String.format(
- "Size of array (%d) over limit at %d",
- new Object[] { count, arraySizeLimit });
- throw new SizeLimitException(reason);
+ final String reason = String.format(
+ "Size of array (%d) over limit at %d", new Object[] {
+ count, arraySizeLimit });
+ throw new IOException(reason);
}
a.acceptArray(count);
stack.reduceCount();
stack.pushArray(count);
- in.advance();
headByte = REQUIRE_TO_READ_HEAD;
return false;
}
case 0xde: // map 16
{
- int count = in.getShort() & 0xffff;
+ final int count = in.readShort() & 0xffff;
if (count >= mapSizeLimit) {
- String reason = String.format(
- "Size of map (%d) over limit at %d",
- new Object[] { count, mapSizeLimit });
- throw new SizeLimitException(reason);
+ final String reason = String.format(
+ "Size of map (%d) over limit at %d", new Object[] {
+ count, mapSizeLimit });
+ throw new IOException(reason);
}
a.acceptMap(count);
stack.reduceCount();
stack.pushMap(count);
- in.advance();
headByte = REQUIRE_TO_READ_HEAD;
return false;
}
case 0xdf: // map 32
{
- int count = in.getInt();
+ final int count = in.readInt();
if (count < 0 || count >= mapSizeLimit) {
- String reason = String.format(
- "Size of map (%d) over limit at %d",
- new Object[] { count, mapSizeLimit });
- throw new SizeLimitException(reason);
+ final String reason = String.format(
+ "Size of map (%d) over limit at %d", new Object[] {
+ count, mapSizeLimit });
+ throw new IOException(reason);
}
a.acceptMap(count);
stack.reduceCount();
stack.pushMap(count);
- in.advance();
headByte = REQUIRE_TO_READ_HEAD;
return false;
}
@@ -324,28 +330,22 @@ private boolean readOneWithoutStackLarge(Accept a, final int b)
}
}
- private boolean tryReferRawBody(BufferReferer referer, int size) throws IOException {
- return in.tryRefer(referer, size);
- }
-
- private void readRawBody(int size) throws IOException {
+ private void readRawBody(final int size) throws IOException {
raw = new byte[size];
rawFilled = 0;
readRawBodyCont();
}
private void readRawBodyCont() throws IOException {
- int len = in.read(raw, rawFilled, raw.length - rawFilled);
+ final int len = raw.length - rawFilled;
+ in.readFully(raw, rawFilled, len);
rawFilled += len;
- if (rawFilled < raw.length) {
- throw new EOFException();
- }
}
@Override
protected boolean tryReadNil() throws IOException {
stack.checkCount();
- int b = getHeadByte() & 0xff;
+ final int b = getHeadByte() & 0xff;
if (b == 0xc0) {
// nil is read
stack.reduceCount();
@@ -363,7 +363,7 @@ public boolean trySkipNil() throws IOException {
return true;
}
- int b = getHeadByte() & 0xff;
+ final int b = getHeadByte() & 0xff;
if (b == 0xc0) {
// nil is skipped
stack.reduceCount();
@@ -378,20 +378,20 @@ public boolean trySkipNil() throws IOException {
public void readNil() throws IOException {
// optimized not to allocate nilAccept
stack.checkCount();
- int b = getHeadByte() & 0xff;
+ final int b = getHeadByte() & 0xff;
if (b == 0xc0) {
stack.reduceCount();
headByte = REQUIRE_TO_READ_HEAD;
return;
}
- throw new MessageTypeException("Expected nil but got not nil value");
+ throw new IOException("Expected nil but got not nil value");
}
@Override
public boolean readBoolean() throws IOException {
// optimized not to allocate booleanAccept
stack.checkCount();
- int b = getHeadByte() & 0xff;
+ final int b = getHeadByte() & 0xff;
if (b == 0xc2) {
stack.reduceCount();
headByte = REQUIRE_TO_READ_HEAD;
@@ -401,8 +401,7 @@ public boolean readBoolean() throws IOException {
headByte = REQUIRE_TO_READ_HEAD;
return true;
}
- throw new MessageTypeException(
- "Expected Boolean but got not boolean value");
+ throw new IOException("Expected Boolean but got not boolean value");
}
@Override
@@ -410,9 +409,9 @@ public byte readByte() throws IOException {
// optimized not to allocate byteAccept
stack.checkCount();
readOneWithoutStack(intAccept);
- int value = intAccept.value;
- if (value < (int) Byte.MIN_VALUE || value > (int) Byte.MAX_VALUE) {
- throw new MessageTypeException(); // TODO message
+ final int value = intAccept.value;
+ if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
+ throw new IOException(); // TODO message
}
stack.reduceCount();
return (byte) value;
@@ -423,14 +422,27 @@ public short readShort() throws IOException {
// optimized not to allocate shortAccept
stack.checkCount();
readOneWithoutStack(intAccept);
- int value = intAccept.value;
- if (value < (int) Short.MIN_VALUE || value > (int) Short.MAX_VALUE) {
- throw new MessageTypeException(); // TODO message
+ final int value = intAccept.value;
+ if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
+ throw new IOException(); // TODO message
}
stack.reduceCount();
return (short) value;
}
+ @Override
+ public char readChar() throws IOException {
+ // optimized not to allocate shortAccept
+ stack.checkCount();
+ readOneWithoutStack(intAccept);
+ final int value = intAccept.value;
+ if (value < Character.MIN_VALUE || value > Character.MAX_VALUE) {
+ throw new IOException(); // TODO message
+ }
+ stack.reduceCount();
+ return (char) value;
+ }
+
@Override
public int readInt() throws IOException {
readOne(intAccept);
@@ -449,6 +461,17 @@ public BigInteger readBigInteger() throws IOException {
return bigIntegerAccept.value;
}
+ @Override
+ protected BigInteger readBigInteger(final boolean countAsValue)
+ throws IOException {
+ readOne(bigIntegerAccept);
+ final BigInteger result = bigIntegerAccept.value;
+ if ((result != null) && !countAsValue) {
+ stack.raiseCount();
+ }
+ return result;
+ }
+
@Override
public float readFloat() throws IOException {
readOne(doubleAccept);
@@ -468,7 +491,7 @@ public byte[] readByteArray() throws IOException {
}
@Override
- public String readString() throws IOException {
+ public String readUTF() throws IOException {
readOne(stringAccept);
return stringAccept.value;
}
@@ -480,16 +503,16 @@ public int readArrayBegin() throws IOException {
}
@Override
- public void readArrayEnd(boolean check) throws IOException {
+ public void readArrayEnd(final boolean check) throws IOException {
if (!stack.topIsArray()) {
- throw new MessageTypeException(
+ throw new IOException(
"readArrayEnd() is called but readArrayBegin() is not called");
}
- int remain = stack.getTopCount();
+ final int remain = stack.getTopCount();
if (remain > 0) {
if (check) {
- throw new MessageTypeException(
+ throw new IOException(
"readArrayEnd(check=true) is called but the array is not end");
}
for (int i = 0; i < remain; i++) {
@@ -506,16 +529,16 @@ public int readMapBegin() throws IOException {
}
@Override
- public void readMapEnd(boolean check) throws IOException {
+ public void readMapEnd(final boolean check) throws IOException {
if (!stack.topIsMap()) {
- throw new MessageTypeException(
+ throw new IOException(
"readMapEnd() is called but readMapBegin() is not called");
}
- int remain = stack.getTopCount();
+ final int remain = stack.getTopCount();
if (remain > 0) {
if (check) {
- throw new MessageTypeException(
+ throw new IOException(
"readMapEnd(check=true) is called but the map is not end");
}
for (int i = 0; i < remain; i++) {
@@ -525,41 +548,6 @@ public void readMapEnd(boolean check) throws IOException {
stack.pop();
}
- @Override
- protected void readValue(Unconverter uc) throws IOException {
- if (uc.getResult() != null) {
- uc.resetResult();
- }
- valueAccept.setUnconverter(uc);
-
- stack.checkCount();
- if (readOneWithoutStack(valueAccept)) {
- stack.reduceCount();
- if (uc.getResult() != null) {
- return;
- }
- }
- while (true) {
- while (stack.getTopCount() == 0) {
- if (stack.topIsArray()) {
- uc.writeArrayEnd(true);
- stack.pop();
- // stack.reduceCount();
- } else if (stack.topIsMap()) {
- uc.writeMapEnd(true);
- stack.pop();
- // stack.reduceCount();
- } else {
- throw new RuntimeException("invalid stack"); // FIXME error?
- }
- if (uc.getResult() != null) {
- return;
- }
- }
- readOne(valueAccept);
- }
- }
-
@Override
public void skip() throws IOException {
stack.checkCount();
@@ -567,7 +555,7 @@ public void skip() throws IOException {
stack.reduceCount();
return;
}
- int targetDepth = stack.getDepth() - 1;
+ final int targetDepth = stack.getDepth() - 1;
while (true) {
while (stack.getTopCount() == 0) {
stack.pop();
@@ -579,8 +567,9 @@ public void skip() throws IOException {
}
}
+ @Override
public ValueType getNextType() throws IOException {
- final int b = (int) getHeadByte();
+ final int b = getHeadByte();
if ((b & 0x80) == 0) { // Positive Fixnum
return ValueType.INTEGER;
}
@@ -633,17 +622,111 @@ public void reset() {
stack.clear();
}
+ @Override
public void close() throws IOException {
- in.close();
+ if (in instanceof Closeable) {
+ ((Closeable) in).close();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#dataInput()
+ */
+ @Override
+ public DataInput dataInput() throws IOException {
+ checkInRawRead();
+ if (inReadRaw) {
+ if (tempRawReadDataInput == null) {
+ tempRawReadDataInput = new DataInputBuffer(
+ byteArrayAccept.value);
+ }
+ return tempRawReadDataInput;
+ }
+ return in;
+ }
+
+ /**
+ * Returns the underlying InputStream: use with extreme care!
+ *
+ * If the underlying DataInput is an InputStream, then it will be
+ * returned. If not, the a wrapper InputStream on top of the DataInput
+ * will be written instead.
+ *
+ * @see dataInput() for usage restrictions.
+ *
+ * @throws IOException
+ */
+ @Override
+ public InputStream inputStream() throws IOException {
+ if (inReadRaw) {
+ if (tempInputStream == null) {
+ tempInputStream = new DataInputStreamWrapper(dataInput());
+ }
+ return tempInputStream;
+ }
+ checkInRawRead();
+ return inputStream;
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readRawBegin()
+ */
+ @Override
+ public int readRawBegin() throws IOException {
+ if (inReadRaw) {
+ throw new IOException("Already in read raw!");
+ }
+ readOne(byteArrayAccept);
+ inReadRaw = true;
+ return (readRawToRead = byteArrayAccept.value.length);
}
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readRawEnd()
+ */
@Override
- public int getReadByteCount() {
- return in.getReadByteCount();
+ public void readRawEnd() throws IOException {
+ checkInRawRead();
+ if (readRawToRead != 0) {
+ throw new IOException("Wrong number of bytes read");
+ }
+ inReadRaw = false;
+ tempRawReadDataInput = null;
+ tempInputStream = null;
}
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#rawRead(int)
+ */
@Override
- public void resetReadByteCount() {
- in.resetReadByteCount();
+ public void rawRead(final int read) throws IOException {
+ checkInRawRead();
+ readRawToRead -= read;
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readPartialByteBuffer(int)
+ */
+ @Override
+ public ByteBuffer readPartialByteBuffer(final int bytes) throws IOException {
+ checkInRawRead();
+ if ((readRawToRead == bytes)
+ && (readRawToRead == byteArrayAccept.value.length)) {
+ readRawToRead = 0;
+ return ByteBuffer.wrap(byteArrayAccept.value);
+ }
+ rawRead(bytes);
+ final int offset = byteArrayAccept.value.length - readRawToRead;
+ return ByteBuffer.wrap(byteArrayAccept.value, offset, bytes);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.impl.AbstractUnpacker#checkInRawRead()
+ */
+ @Override
+ protected void checkInRawRead() throws IOException {
+ if (!inReadRaw) {
+ throw new IOException("Not in read raw");
+ }
}
}
diff --git a/src/main/java/com/blockwithme/msgpack/impl/ObjectPackerImpl.java b/src/main/java/com/blockwithme/msgpack/impl/ObjectPackerImpl.java
new file mode 100644
index 000000000..abbf5711c
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/impl/ObjectPackerImpl.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack.impl;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.Date;
+import java.util.Objects;
+
+import com.blockwithme.msgpack.ObjectPacker;
+import com.blockwithme.msgpack.Packer;
+import com.blockwithme.msgpack.schema.Schema;
+import com.blockwithme.msgpack.templates.AbstractTemplate;
+import com.blockwithme.msgpack.templates.BasicTemplates;
+import com.blockwithme.msgpack.templates.PackerContext;
+import com.blockwithme.msgpack.templates.Template;
+
+/**
+ * ObjectPacker implementation. All the hard work is done in:
+ *
+ * AbstractTemplate.writeObject(PackerContext, Object, Template);
+ *
+ * @author monster
+ */
+public class ObjectPackerImpl implements ObjectPacker {
+
+ /** The real Packer. */
+ protected final Packer packer;
+
+ /** The context */
+ protected final PackerContext context;
+
+ /** The BasicTemplates */
+ protected final BasicTemplates basicTemplates;
+
+ /**
+ * Creates an ObjectPackerImpl
+ *
+ * @param packer
+ * @throws IOException
+ */
+ public ObjectPackerImpl(final Packer packer, final PackerContext context)
+ throws IOException {
+ this.packer = Objects.requireNonNull(packer);
+ this.context = Objects.requireNonNull(context);
+ context.packer = packer;
+ context.objectPacker = this;
+ final Schema schema = context.getSchema();
+ basicTemplates = schema.basicTemplates;
+ packer.writeIndex(schema.format);
+ packer.writeIndex(schema.schema);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#packer()
+ */
+ @Override
+ public Packer packer() {
+ return packer;
+ }
+
+ /** Writes an Object out. Object must be compatible with template. */
+ @Override
+ public ObjectPacker writeObject(final Object o,
+ @SuppressWarnings("rawtypes") final Template template,
+ final boolean ifObjectArrayCanContainNullValue) throws IOException {
+ AbstractTemplate.writeObject(context, o, template,
+ ifObjectArrayCanContainNullValue);
+ return this;
+ }
+
+ /**
+ * Writes an Object out. Template is determined based on object type.
+ * Pass along a template for faster results.
+ */
+ @Override
+ public ObjectPacker writeObject(final Object o,
+ final boolean ifObjectArrayCanContainNullValue) throws IOException {
+ return writeObject(o, null, ifObjectArrayCanContainNullValue);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.OwriteObject(acker#writeObject(java.lang.Class)
+ */
+ @Override
+ public ObjectPacker writeObject(final Class> o) throws IOException {
+ return writeObject(o, basicTemplates.CLASS);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.lang.Boolean)
+ */
+ @Override
+ public ObjectPacker writeObject(final Boolean o) throws IOException {
+ return writeObject(o, basicTemplates.BOOLEAN);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.lang.Byte)
+ */
+ @Override
+ public ObjectPacker writeObject(final Byte o) throws IOException {
+ return writeObject(o, basicTemplates.BYTE);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.lang.Short)
+ */
+ @Override
+ public ObjectPacker writeObject(final Short o) throws IOException {
+ return writeObject(o, basicTemplates.SHORT);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.lang.Character)
+ */
+ @Override
+ public ObjectPacker writeObject(final Character o) throws IOException {
+ return writeObject(o, basicTemplates.CHARACTER);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.lang.Integer)
+ */
+ @Override
+ public ObjectPacker writeObject(final Integer o) throws IOException {
+ return writeObject(o, basicTemplates.INTEGER);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.lang.Long)
+ */
+ @Override
+ public ObjectPacker writeObject(final Long o) throws IOException {
+ return writeObject(o, basicTemplates.LONG);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.lang.Float)
+ */
+ @Override
+ public ObjectPacker writeObject(final Float o) throws IOException {
+ return writeObject(o, basicTemplates.FLOAT);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.lang.Double)
+ */
+ @Override
+ public ObjectPacker writeObject(final Double o) throws IOException {
+ return writeObject(o, basicTemplates.DOUBLE);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.math.BigInteger)
+ */
+ @Override
+ public ObjectPacker writeObject(final BigInteger o) throws IOException {
+ return writeObject(o, basicTemplates.BIG_INTEGER);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.math.BigDecimal)
+ */
+ @Override
+ public ObjectPacker writeObject(final BigDecimal o) throws IOException {
+ return writeObject(o, basicTemplates.BIG_DECIMAL);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.lang.String)
+ */
+ @Override
+ public ObjectPacker writeObject(final String o) throws IOException {
+ return writeObject(o, basicTemplates.STRING);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(boolean[])
+ */
+ @Override
+ public ObjectPacker writeObject(final boolean[] o) throws IOException {
+ return writeObject(o, basicTemplates.BOOLEAN_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(byte[])
+ */
+ @Override
+ public ObjectPacker writeObject(final byte[] o) throws IOException {
+ return writeObject(o, basicTemplates.BYTE_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(short[])
+ */
+ @Override
+ public ObjectPacker writeObject(final short[] o) throws IOException {
+ return writeObject(o, basicTemplates.SHORT_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(char[])
+ */
+ @Override
+ public ObjectPacker writeObject(final char[] o) throws IOException {
+ return writeObject(o, basicTemplates.CHAR_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(int[])
+ */
+ @Override
+ public ObjectPacker writeObject(final int[] o) throws IOException {
+ return writeObject(o, basicTemplates.INT_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(long[])
+ */
+ @Override
+ public ObjectPacker writeObject(final long[] o) throws IOException {
+ return writeObject(o, basicTemplates.LONG_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(float[])
+ */
+ @Override
+ public ObjectPacker writeObject(final float[] o) throws IOException {
+ return writeObject(o, basicTemplates.FLOAT_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(double[])
+ */
+ @Override
+ public ObjectPacker writeObject(final double[] o) throws IOException {
+ return writeObject(o, basicTemplates.DOUBLE_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.util.Date)
+ */
+ @Override
+ public ObjectPacker writeObject(final Date o) throws IOException {
+ return writeObject(o, basicTemplates.DATE);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.nio.ByteBuffer)
+ */
+ @Override
+ public ObjectPacker writeObject(final ByteBuffer o) throws IOException {
+ return writeObject(o, basicTemplates.BYTE_BUFFER);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(byte[], int, int)
+ */
+ @Override
+ public ObjectPacker writeObject(final byte[] o, final int off, final int len)
+ throws IOException {
+ return writeObject(new ByteArraySlice(o, off, len),
+ basicTemplates.BYTE_ARRAY_SLICE);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.lang.Object)
+ */
+ @Override
+ public ObjectPacker writeObject(final Object o) throws IOException {
+ return writeObject(o, true);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectPacker#writeObject(java.lang.Object, com.blockwithme.msgpack.templates.Template)
+ */
+ @Override
+ public ObjectPacker writeObject(final Object o, final Template> template)
+ throws IOException {
+ return writeObject(o, template, true);
+ }
+}
diff --git a/src/main/java/com/blockwithme/msgpack/impl/ObjectUnpackerImpl.java b/src/main/java/com/blockwithme/msgpack/impl/ObjectUnpackerImpl.java
new file mode 100644
index 000000000..788b9c02a
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/impl/ObjectUnpackerImpl.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack.impl;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.Date;
+import java.util.Objects;
+
+import com.blockwithme.msgpack.ObjectUnpacker;
+import com.blockwithme.msgpack.PostDeserListener;
+import com.blockwithme.msgpack.Unpacker;
+import com.blockwithme.msgpack.schema.Schema;
+import com.blockwithme.msgpack.templates.AbstractTemplate;
+import com.blockwithme.msgpack.templates.BasicTemplates;
+import com.blockwithme.msgpack.templates.Template;
+import com.blockwithme.msgpack.templates.UnpackerContext;
+
+/**
+ * The ObjectUnpacker implementation. All the hard work happens in:
+ *
+ * AbstractTemplate.readObject(UnpackerContext, Template);
+ *
+ * @author monster
+ */
+public class ObjectUnpackerImpl implements ObjectUnpacker {
+
+ /** The real Unpacker */
+ protected final Unpacker unpacker;
+
+ /** The context */
+ protected final UnpackerContext context;
+
+ /** The BasicTemplates */
+ protected final BasicTemplates basicTemplates;
+
+ /**
+ * Creates a new ObjectUnpackerImpl.
+ * @param unpacker
+ * @throws IOException
+ */
+ public ObjectUnpackerImpl(final Unpacker unpacker,
+ final UnpackerContext context) throws IOException {
+ this.unpacker = Objects.requireNonNull(unpacker);
+ this.context = Objects.requireNonNull(context);
+ context.unpacker = unpacker;
+ context.objectUnpacker = this;
+ context.format = unpacker.readIndex();
+ context.schemaID = unpacker.readIndex();
+ final Schema schema = context.getSchema();
+ basicTemplates = schema.basicTemplates;
+ }
+
+ /** Returns the underlying unpacker, if any, otherwise self. */
+ @Override
+ public Unpacker unpacker() {
+ return unpacker;
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readBoolean()
+ */
+ @Override
+ public Boolean readBoolean() throws IOException {
+ return (Boolean) readObject(basicTemplates.BOOLEAN);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readByte()
+ */
+ @Override
+ public Byte readByte() throws IOException {
+ return (Byte) readObject(basicTemplates.BYTE);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readShort()
+ */
+ @Override
+ public Short readShort() throws IOException {
+ return (Short) readObject(basicTemplates.SHORT);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readChar()
+ */
+ @Override
+ public Character readChar() throws IOException {
+ return (Character) readObject(basicTemplates.CHARACTER);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readInt()
+ */
+ @Override
+ public Integer readInt() throws IOException {
+ return (Integer) readObject(basicTemplates.INTEGER);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readLong()
+ */
+ @Override
+ public Long readLong() throws IOException {
+ return (Long) readObject(basicTemplates.LONG);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readFloat()
+ */
+ @Override
+ public Float readFloat() throws IOException {
+ return (Float) readObject(basicTemplates.FLOAT);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readDouble()
+ */
+ @Override
+ public Double readDouble() throws IOException {
+ return (Double) readObject(basicTemplates.DOUBLE);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readBigInteger()
+ */
+ @Override
+ public BigInteger readBigInteger() throws IOException {
+ return (BigInteger) readObject(basicTemplates.BIG_INTEGER);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readBigDecimal()
+ */
+ @Override
+ public BigDecimal readBigDecimal() throws IOException {
+ return (BigDecimal) readObject(basicTemplates.BIG_DECIMAL);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readBooleanArray()
+ */
+ @Override
+ public boolean[] readBooleanArray() throws IOException {
+ return (boolean[]) readObject(basicTemplates.BOOLEAN_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readByteArray()
+ */
+ @Override
+ public byte[] readByteArray() throws IOException {
+ return (byte[]) readObject(basicTemplates.BYTE_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readShortArray()
+ */
+ @Override
+ public short[] readShortArray() throws IOException {
+ return (short[]) readObject(basicTemplates.SHORT_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readCharArray()
+ */
+ @Override
+ public char[] readCharArray() throws IOException {
+ return (char[]) readObject(basicTemplates.CHAR_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readIntArray()
+ */
+ @Override
+ public int[] readIntArray() throws IOException {
+ return (int[]) readObject(basicTemplates.INT_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readLongArray()
+ */
+ @Override
+ public long[] readLongArray() throws IOException {
+ return (long[]) readObject(basicTemplates.LONG_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readFloatArray()
+ */
+ @Override
+ public float[] readFloatArray() throws IOException {
+ return (float[]) readObject(basicTemplates.FLOAT_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readDoubleArray()
+ */
+ @Override
+ public double[] readDoubleArray() throws IOException {
+ return (double[]) readObject(basicTemplates.DOUBLE_ARRAY);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readString()
+ */
+ @Override
+ public String readString() throws IOException {
+ return (String) readObject(basicTemplates.STRING);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.Unpacker#readByteBuffer()
+ */
+ @Override
+ public ByteBuffer readByteBuffer() throws IOException {
+ return (ByteBuffer) readObject(basicTemplates.BYTE_BUFFER);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.ObjectUnpacker#readDate()
+ */
+ @Override
+ public Date readDate() throws IOException {
+ return (Date) readObject(basicTemplates.DATE);
+ }
+
+ @Override
+ public Class> readClass() throws IOException {
+ return (Class>) readObject(basicTemplates.CLASS);
+ }
+
+ /** Reads any Object. */
+ @Override
+ public Object readObject() throws IOException {
+ return AbstractTemplate.readObject(context, null, true);
+ }
+
+ /** Reads any Object. Fails if Object type does not match template type. */
+ @Override
+ public Object readObject(final Template> template) throws IOException {
+ return AbstractTemplate.readObject(context, template, true);
+ }
+
+ /** Reads any Object. */
+ @Override
+ public Object readObject(final boolean ifObjectArrayCanContainNullValue)
+ throws IOException {
+ return AbstractTemplate.readObject(context, null,
+ ifObjectArrayCanContainNullValue);
+ }
+
+ /** Reads any Object. Fails if Object type does not match template type. */
+ @Override
+ public Object readObject(final Template> template,
+ final boolean ifObjectArrayCanContainNullValue) throws IOException {
+ return AbstractTemplate.readObject(context, template,
+ ifObjectArrayCanContainNullValue);
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.Closeable#close()
+ */
+ @Override
+ public void close() throws IOException {
+ for (final Object o : context.previous) {
+ if (o instanceof PostDeserListener) {
+ final PostDeserListener pd = (PostDeserListener) o;
+ pd.postDeser(context);
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/msgpack/packer/PackerStack.java b/src/main/java/com/blockwithme/msgpack/impl/PackerStack.java
similarity index 73%
rename from src/main/java/org/msgpack/packer/PackerStack.java
rename to src/main/java/com/blockwithme/msgpack/impl/PackerStack.java
index 9114ebac2..b3c435140 100644
--- a/src/main/java/org/msgpack/packer/PackerStack.java
+++ b/src/main/java/com/blockwithme/msgpack/impl/PackerStack.java
@@ -15,20 +15,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.packer;
+package com.blockwithme.msgpack.impl;
-import org.msgpack.MessageTypeException;
+import com.blockwithme.msgpack.MessageTypeException;
+/**
+ * The Packer stack keeps track of what is currently being packed, to help
+ * detect inconsistencies.
+ */
public final class PackerStack {
private int top;
- private byte[] types;
- private int[] counts;
+ private final byte[] types;
+ private final int[] counts;
- public static final int MAX_STACK_SIZE = 128;
+ public static final int MAX_STACK_SIZE = 256;
private static final byte TYPE_INVALID = 0;
private static final byte TYPE_ARRAY = 1;
private static final byte TYPE_MAP = 2;
+ private static final byte TYPE_RAW = 3;
public PackerStack() {
this.top = 0;
@@ -37,18 +42,24 @@ public PackerStack() {
this.types[0] = TYPE_INVALID;
}
- public void pushArray(int size) {
+ public void pushArray(final int size) {
top++;
types[top] = TYPE_ARRAY;
counts[top] = size;
}
- public void pushMap(int size) {
+ public void pushMap(final int size) {
top++;
types[top] = TYPE_MAP;
counts[top] = size * 2;
}
+ public void pushRaw() {
+ top++;
+ types[top] = TYPE_RAW;
+ counts[top] = 1;
+ }
+
public void checkCount() {
if (counts[top] > 0) {
return;
@@ -62,6 +73,10 @@ public void checkCount() {
throw new MessageTypeException(
"Map is end but writeMapEnd() is not called");
+ } else if (types[top] == TYPE_RAW) {
+ throw new MessageTypeException(
+ "Raw is end but writeRawEnd() is not called");
+
} else {
// empty
return;
@@ -92,6 +107,10 @@ public boolean topIsMap() {
return types[top] == TYPE_MAP;
}
+ public boolean topIsRaw() {
+ return types[top] == TYPE_RAW;
+ }
+
public void clear() {
top = 0;
}
diff --git a/src/main/java/org/msgpack/unpacker/UnpackerStack.java b/src/main/java/com/blockwithme/msgpack/impl/UnpackerStack.java
similarity index 82%
rename from src/main/java/org/msgpack/unpacker/UnpackerStack.java
rename to src/main/java/com/blockwithme/msgpack/impl/UnpackerStack.java
index 9ed67afff..8b5a57e7f 100644
--- a/src/main/java/org/msgpack/unpacker/UnpackerStack.java
+++ b/src/main/java/com/blockwithme/msgpack/impl/UnpackerStack.java
@@ -15,16 +15,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.unpacker;
+package com.blockwithme.msgpack.impl;
-import org.msgpack.MessageTypeException;
+import com.blockwithme.msgpack.MessageTypeException;
+/**
+ * The Unpacker stack keeps track of what is currently being unpacked, to help
+ * detect inconsistencies.
+ */
public final class UnpackerStack {
private int top;
- private byte[] types;
- private int[] counts;
+ private final byte[] types;
+ private final int[] counts;
- public static final int MAX_STACK_SIZE = 128;
+ public static final int MAX_STACK_SIZE = 256;
private static final byte TYPE_INVALID = 0;
private static final byte TYPE_ARRAY = 1;
@@ -37,13 +41,13 @@ public UnpackerStack() {
this.types[0] = TYPE_INVALID;
}
- public void pushArray(int size) {
+ public void pushArray(final int size) {
top++;
types[top] = TYPE_ARRAY;
counts[top] = size;
}
- public void pushMap(int size) {
+ public void pushMap(final int size) {
top++;
types[top] = TYPE_MAP;
counts[top] = size * 2;
@@ -72,6 +76,10 @@ public void reduceCount() {
counts[top]--;
}
+ public void raiseCount() {
+ counts[top]++;
+ }
+
public void pop() {
top--;
}
diff --git a/src/main/java/org/msgpack/unpacker/Accept.java b/src/main/java/com/blockwithme/msgpack/impl/accept/Accept.java
similarity index 63%
rename from src/main/java/org/msgpack/unpacker/Accept.java
rename to src/main/java/com/blockwithme/msgpack/impl/accept/Accept.java
index 9d2f4ba34..09ecd3e04 100644
--- a/src/main/java/org/msgpack/unpacker/Accept.java
+++ b/src/main/java/com/blockwithme/msgpack/impl/accept/Accept.java
@@ -15,47 +15,52 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.unpacker;
+package com.blockwithme.msgpack.impl.accept;
import java.io.IOException;
import java.nio.ByteBuffer;
-import org.msgpack.io.BufferReferer;
-import org.msgpack.MessageTypeException;
-abstract class Accept implements BufferReferer {
- void acceptBoolean(boolean v) throws IOException {
+import com.blockwithme.msgpack.MessageTypeException;
+
+/**
+ * Part of the original low-level Message-Pack Java implementation.
+ *
+ * @author monster
+ */
+public abstract class Accept {
+ public void acceptBoolean(final boolean v) throws IOException {
throw new MessageTypeException("Unexpected boolean value");
}
- void acceptInteger(byte v) throws IOException {
+ public void acceptInteger(final byte v) throws IOException {
throw new MessageTypeException("Unexpected integer value");
}
- void acceptInteger(short v) throws IOException {
+ public void acceptInteger(final short v) throws IOException {
throw new MessageTypeException("Unexpected integer value");
}
- void acceptInteger(int v) throws IOException {
+ public void acceptInteger(final int v) throws IOException {
throw new MessageTypeException("Unexpected integer value");
}
- void acceptInteger(long v) throws IOException {
+ public void acceptInteger(final long v) throws IOException {
throw new MessageTypeException("Unexpected integer value");
}
- void acceptUnsignedInteger(byte v) throws IOException {
+ public void acceptUnsignedInteger(final byte v) throws IOException {
throw new MessageTypeException("Unexpected integer value");
}
- void acceptUnsignedInteger(short v) throws IOException {
+ public void acceptUnsignedInteger(final short v) throws IOException {
throw new MessageTypeException("Unexpected integer value");
}
- void acceptUnsignedInteger(int v) throws IOException {
+ public void acceptUnsignedInteger(final int v) throws IOException {
throw new MessageTypeException("Unexpected integer value");
}
- void acceptUnsignedInteger(long v) throws IOException {
+ public void acceptUnsignedInteger(final long v) throws IOException {
throw new MessageTypeException("Unexpected integer value");
}
@@ -63,11 +68,11 @@ void acceptUnsignedInteger(long v) throws IOException {
// throw new MessageTypeException("Unexpected raw value");
// }
- void acceptRaw(byte[] raw) throws IOException {
+ public void acceptRaw(final byte[] raw) throws IOException {
throw new MessageTypeException("Unexpected raw value");
}
- void acceptEmptyRaw() throws IOException {
+ public void acceptEmptyRaw() throws IOException {
throw new MessageTypeException("Unexpected raw value");
}
@@ -75,7 +80,7 @@ void acceptEmptyRaw() throws IOException {
// throw new MessageTypeException("Unexpected array value");
// }
- void acceptArray(int size) throws IOException {
+ public void acceptArray(final int size) throws IOException {
throw new MessageTypeException("Unexpected array value");
}
@@ -83,23 +88,24 @@ void acceptArray(int size) throws IOException {
// throw new MessageTypeException("Unexpected map value");
// }
- void acceptMap(int size) throws IOException {
+ public void acceptMap(final int size) throws IOException {
throw new MessageTypeException("Unexpected map value");
}
- void acceptNil() throws IOException {
+ public void acceptNil() throws IOException {
throw new MessageTypeException("Unexpected nil value");
}
- void acceptFloat(float v) throws IOException {
+ public void acceptFloat(final float v) throws IOException {
throw new MessageTypeException("Unexpected float value");
}
- void acceptDouble(double v) throws IOException {
+ public void acceptDouble(final double v) throws IOException {
throw new MessageTypeException("Unexpected float value");
}
- public void refer(ByteBuffer bb, boolean gift) throws IOException {
+ public void refer(final ByteBuffer bb, final boolean gift)
+ throws IOException {
throw new MessageTypeException("Unexpected raw value");
}
}
diff --git a/src/main/java/org/msgpack/unpacker/ArrayAccept.java b/src/main/java/com/blockwithme/msgpack/impl/accept/ArrayAccept.java
similarity index 73%
rename from src/main/java/org/msgpack/unpacker/ArrayAccept.java
rename to src/main/java/com/blockwithme/msgpack/impl/accept/ArrayAccept.java
index db2285d85..4bc5710f1 100644
--- a/src/main/java/org/msgpack/unpacker/ArrayAccept.java
+++ b/src/main/java/com/blockwithme/msgpack/impl/accept/ArrayAccept.java
@@ -15,13 +15,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.unpacker;
+package com.blockwithme.msgpack.impl.accept;
-final class ArrayAccept extends Accept {
- int size;
+/**
+ * Part of the original low-level Message-Pack Java implementation.
+ *
+ * @author monster
+ */
+public final class ArrayAccept extends Accept {
+ public int size;
@Override
- void acceptArray(int size) {
+ public void acceptArray(final int size) {
this.size = size;
}
}
diff --git a/src/main/java/org/msgpack/unpacker/BigIntegerAccept.java b/src/main/java/com/blockwithme/msgpack/impl/accept/BigIntegerAccept.java
similarity index 53%
rename from src/main/java/org/msgpack/unpacker/BigIntegerAccept.java
rename to src/main/java/com/blockwithme/msgpack/impl/accept/BigIntegerAccept.java
index accc8367e..8f40bb94f 100644
--- a/src/main/java/org/msgpack/unpacker/BigIntegerAccept.java
+++ b/src/main/java/com/blockwithme/msgpack/impl/accept/BigIntegerAccept.java
@@ -15,54 +15,59 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.unpacker;
+package com.blockwithme.msgpack.impl.accept;
import java.math.BigInteger;
-final class BigIntegerAccept extends Accept {
- BigInteger value;
+/**
+ * Part of the original low-level Message-Pack Java implementation.
+ *
+ * @author monster
+ */
+public final class BigIntegerAccept extends Accept {
+ public BigInteger value;
@Override
- void acceptInteger(byte v) {
- this.value = BigInteger.valueOf((long) v);
+ public void acceptInteger(final byte v) {
+ this.value = BigInteger.valueOf(v);
}
@Override
- void acceptInteger(short v) {
- this.value = BigInteger.valueOf((long) v);
+ public void acceptInteger(final short v) {
+ this.value = BigInteger.valueOf(v);
}
@Override
- void acceptInteger(int v) {
- this.value = BigInteger.valueOf((long) v);
+ public void acceptInteger(final int v) {
+ this.value = BigInteger.valueOf(v);
}
@Override
- void acceptInteger(long v) {
+ public void acceptInteger(final long v) {
this.value = BigInteger.valueOf(v);
}
@Override
- void acceptUnsignedInteger(byte v) {
- BigInteger.valueOf((long) (v & 0xff));
+ public void acceptUnsignedInteger(final byte v) {
+ this.value = BigInteger.valueOf(v & 0xff);
}
@Override
- void acceptUnsignedInteger(short v) {
- BigInteger.valueOf((long) (v & 0xffff));
+ public void acceptUnsignedInteger(final short v) {
+ this.value = BigInteger.valueOf(v & 0xffff);
}
@Override
- void acceptUnsignedInteger(int v) {
+ public void acceptUnsignedInteger(final int v) {
if (v < 0) {
- this.value = BigInteger.valueOf((long) (v & 0x7fffffff) + 0x80000000L);
+ this.value = BigInteger.valueOf((v & 0x7fffffff) + 0x80000000L);
} else {
- this.value = BigInteger.valueOf((long) v);
+ this.value = BigInteger.valueOf(v);
}
}
@Override
- void acceptUnsignedInteger(long v) {
+ public void acceptUnsignedInteger(final long v) {
if (v < 0L) {
this.value = BigInteger.valueOf(v + Long.MAX_VALUE + 1L).setBit(63);
} else {
diff --git a/src/main/java/org/msgpack/unpacker/ByteArrayAccept.java b/src/main/java/com/blockwithme/msgpack/impl/accept/ByteArrayAccept.java
similarity index 70%
rename from src/main/java/org/msgpack/unpacker/ByteArrayAccept.java
rename to src/main/java/com/blockwithme/msgpack/impl/accept/ByteArrayAccept.java
index 18d34d84f..ee07f8ee5 100644
--- a/src/main/java/org/msgpack/unpacker/ByteArrayAccept.java
+++ b/src/main/java/com/blockwithme/msgpack/impl/accept/ByteArrayAccept.java
@@ -15,26 +15,32 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.unpacker;
+package com.blockwithme.msgpack.impl.accept;
import java.io.IOException;
import java.nio.ByteBuffer;
-final class ByteArrayAccept extends Accept {
- byte[] value;
+/**
+ * Part of the original low-level Message-Pack Java implementation.
+ *
+ * @author monster
+ */
+public final class ByteArrayAccept extends Accept {
+ public byte[] value;
@Override
- void acceptRaw(byte[] raw) {
+ public void acceptRaw(final byte[] raw) {
this.value = raw;
}
@Override
- void acceptEmptyRaw() {
+ public void acceptEmptyRaw() {
this.value = new byte[0];
}
@Override
- public void refer(ByteBuffer bb, boolean gift) throws IOException {
+ public void refer(final ByteBuffer bb, final boolean gift)
+ throws IOException {
// TODO gift
this.value = new byte[bb.remaining()];
bb.get(value);
diff --git a/src/main/java/org/msgpack/unpacker/DoubleAccept.java b/src/main/java/com/blockwithme/msgpack/impl/accept/DoubleAccept.java
similarity index 66%
rename from src/main/java/org/msgpack/unpacker/DoubleAccept.java
rename to src/main/java/com/blockwithme/msgpack/impl/accept/DoubleAccept.java
index a0324654f..6e642bdf6 100644
--- a/src/main/java/org/msgpack/unpacker/DoubleAccept.java
+++ b/src/main/java/com/blockwithme/msgpack/impl/accept/DoubleAccept.java
@@ -15,16 +15,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.unpacker;
+package com.blockwithme.msgpack.impl.accept;
-final class DoubleAccept extends Accept {
- double value;
+/**
+ * Part of the original low-level Message-Pack Java implementation.
+ *
+ * @author monster
+ */
+public final class DoubleAccept extends Accept {
+ public double value;
- void acceptFloat(float v) {
- this.value = (double) v;
+ @Override
+ public void acceptFloat(final float v) {
+ this.value = v;
}
- void acceptDouble(double v) {
+ @Override
+ public void acceptDouble(final double v) {
this.value = v;
}
}
diff --git a/src/main/java/org/msgpack/unpacker/IntAccept.java b/src/main/java/com/blockwithme/msgpack/impl/accept/IntAccept.java
similarity index 59%
rename from src/main/java/org/msgpack/unpacker/IntAccept.java
rename to src/main/java/com/blockwithme/msgpack/impl/accept/IntAccept.java
index 71bc6839b..c11435fae 100644
--- a/src/main/java/org/msgpack/unpacker/IntAccept.java
+++ b/src/main/java/com/blockwithme/msgpack/impl/accept/IntAccept.java
@@ -15,48 +15,54 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.unpacker;
+package com.blockwithme.msgpack.impl.accept;
-import org.msgpack.MessageTypeException;
+import com.blockwithme.msgpack.MessageTypeException;
-final class IntAccept extends Accept {
- int value;
+/**
+ * Part of the original low-level Message-Pack Java implementation.
+ *
+ * @author monster
+ */
+public final class IntAccept extends Accept {
+ public int value;
@Override
- void acceptInteger(byte v) {
- this.value = (int) v;
+ public void acceptInteger(final byte v) {
+ this.value = v;
}
@Override
- void acceptInteger(short v) {
- this.value = (int) v;
+ public void acceptInteger(final short v) {
+ this.value = v;
}
@Override
- void acceptInteger(int v) {
+ public void acceptInteger(final int v) {
this.value = v;
}
@Override
- void acceptInteger(long v) {
- if (value < (long) Integer.MIN_VALUE || value > (long) Integer.MAX_VALUE) {
+ public void acceptInteger(final long v) {
+ if (value < (long) Integer.MIN_VALUE
+ || value > (long) Integer.MAX_VALUE) {
throw new MessageTypeException(); // TODO message
}
this.value = (int) v;
}
@Override
- void acceptUnsignedInteger(byte v) {
+ public void acceptUnsignedInteger(final byte v) {
this.value = v & 0xff;
}
@Override
- void acceptUnsignedInteger(short v) {
+ public void acceptUnsignedInteger(final short v) {
this.value = v & 0xffff;
}
@Override
- void acceptUnsignedInteger(int v) {
+ public void acceptUnsignedInteger(final int v) {
if (v < 0) {
throw new MessageTypeException(); // TODO message
}
@@ -64,8 +70,8 @@ void acceptUnsignedInteger(int v) {
}
@Override
- void acceptUnsignedInteger(long v) {
- if (v < 0 || v > (long) Integer.MAX_VALUE) {
+ public void acceptUnsignedInteger(final long v) {
+ if (v < 0 || v > Integer.MAX_VALUE) {
throw new MessageTypeException(); // TODO message
}
this.value = (int) v;
diff --git a/src/main/java/org/msgpack/unpacker/LongAccept.java b/src/main/java/com/blockwithme/msgpack/impl/accept/LongAccept.java
similarity index 53%
rename from src/main/java/org/msgpack/unpacker/LongAccept.java
rename to src/main/java/com/blockwithme/msgpack/impl/accept/LongAccept.java
index 215dc67c1..d26cecf2f 100644
--- a/src/main/java/org/msgpack/unpacker/LongAccept.java
+++ b/src/main/java/com/blockwithme/msgpack/impl/accept/LongAccept.java
@@ -15,54 +15,59 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.unpacker;
+package com.blockwithme.msgpack.impl.accept;
-import org.msgpack.MessageTypeException;
+import com.blockwithme.msgpack.MessageTypeException;
-final class LongAccept extends Accept {
- long value;
+/**
+ * Part of the original low-level Message-Pack Java implementation.
+ *
+ * @author monster
+ */
+public final class LongAccept extends Accept {
+ public long value;
@Override
- void acceptInteger(byte v) {
- this.value = (long) v;
+ public void acceptInteger(final byte v) {
+ this.value = v;
}
@Override
- void acceptInteger(short v) {
- this.value = (long) v;
+ public void acceptInteger(final short v) {
+ this.value = v;
}
@Override
- void acceptInteger(int v) {
- this.value = (long) v;
+ public void acceptInteger(final int v) {
+ this.value = v;
}
@Override
- void acceptInteger(long v) {
+ public void acceptInteger(final long v) {
this.value = v;
}
@Override
- void acceptUnsignedInteger(byte v) {
- this.value = (long) (v & 0xff);
+ public void acceptUnsignedInteger(final byte v) {
+ this.value = v & 0xff;
}
@Override
- void acceptUnsignedInteger(short v) {
- this.value = (long) (v & 0xffff);
+ public void acceptUnsignedInteger(final short v) {
+ this.value = v & 0xffff;
}
@Override
- void acceptUnsignedInteger(int v) {
+ public void acceptUnsignedInteger(final int v) {
if (v < 0) {
- this.value = (long) (v & 0x7fffffff) + 0x80000000L;
+ this.value = (v & 0x7fffffff) + 0x80000000L;
} else {
- this.value = (long) v;
+ this.value = v;
}
}
@Override
- void acceptUnsignedInteger(long v) {
+ public void acceptUnsignedInteger(final long v) {
if (v < 0L) {
throw new MessageTypeException(); // TODO message
}
diff --git a/src/main/java/org/msgpack/unpacker/MapAccept.java b/src/main/java/com/blockwithme/msgpack/impl/accept/MapAccept.java
similarity index 73%
rename from src/main/java/org/msgpack/unpacker/MapAccept.java
rename to src/main/java/com/blockwithme/msgpack/impl/accept/MapAccept.java
index a687b9678..16343b306 100644
--- a/src/main/java/org/msgpack/unpacker/MapAccept.java
+++ b/src/main/java/com/blockwithme/msgpack/impl/accept/MapAccept.java
@@ -15,13 +15,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.unpacker;
+package com.blockwithme.msgpack.impl.accept;
-final class MapAccept extends Accept {
- int size;
+/**
+ * Part of the original low-level Message-Pack Java implementation.
+ *
+ * @author monster
+ */
+public final class MapAccept extends Accept {
+ public int size;
@Override
- void acceptMap(int size) {
+ public void acceptMap(final int size) {
this.size = size;
}
}
diff --git a/src/main/java/org/msgpack/unpacker/SkipAccept.java b/src/main/java/com/blockwithme/msgpack/impl/accept/SkipAccept.java
similarity index 51%
rename from src/main/java/org/msgpack/unpacker/SkipAccept.java
rename to src/main/java/com/blockwithme/msgpack/impl/accept/SkipAccept.java
index 7e3a98c54..07ba2b0e3 100644
--- a/src/main/java/org/msgpack/unpacker/SkipAccept.java
+++ b/src/main/java/com/blockwithme/msgpack/impl/accept/SkipAccept.java
@@ -15,77 +15,83 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.unpacker;
+package com.blockwithme.msgpack.impl.accept;
import java.io.IOException;
import java.nio.ByteBuffer;
-final class SkipAccept extends Accept {
+/**
+ * Part of the original low-level Message-Pack Java implementation.
+ *
+ * @author monster
+ */
+public final class SkipAccept extends Accept {
@Override
- void acceptBoolean(boolean v) {
+ public void acceptBoolean(final boolean v) {
}
@Override
- void acceptInteger(byte v) {
+ public void acceptInteger(final byte v) {
}
@Override
- void acceptInteger(short v) {
+ public void acceptInteger(final short v) {
}
@Override
- void acceptInteger(int v) {
+ public void acceptInteger(final int v) {
}
@Override
- void acceptInteger(long v) {
+ public void acceptInteger(final long v) {
}
@Override
- void acceptUnsignedInteger(byte v) {
+ public void acceptUnsignedInteger(final byte v) {
}
@Override
- void acceptUnsignedInteger(short v) {
+ public void acceptUnsignedInteger(final short v) {
}
@Override
- void acceptUnsignedInteger(int v) {
+ public void acceptUnsignedInteger(final int v) {
}
@Override
- void acceptUnsignedInteger(long v) {
+ public void acceptUnsignedInteger(final long v) {
}
@Override
- void acceptRaw(byte[] raw) {
+ public void acceptRaw(final byte[] raw) {
}
@Override
- void acceptEmptyRaw() {
+ public void acceptEmptyRaw() {
}
@Override
- public void refer(ByteBuffer bb, boolean gift) throws IOException {
+ public void refer(final ByteBuffer bb, final boolean gift)
+ throws IOException {
}
@Override
- void acceptArray(int size) {
+ public void acceptArray(final int size) {
}
@Override
- void acceptMap(int size) {
+ public void acceptMap(final int size) {
}
@Override
- void acceptNil() {
+ public void acceptNil() {
}
@Override
- void acceptFloat(float v) {
+ public void acceptFloat(final float v) {
}
@Override
- void acceptDouble(double v) {
+ public void acceptDouble(final double v) {
}
}
diff --git a/src/main/java/org/msgpack/unpacker/StringAccept.java b/src/main/java/com/blockwithme/msgpack/impl/accept/StringAccept.java
similarity index 71%
rename from src/main/java/org/msgpack/unpacker/StringAccept.java
rename to src/main/java/com/blockwithme/msgpack/impl/accept/StringAccept.java
index a50053ceb..e36fc1d99 100644
--- a/src/main/java/org/msgpack/unpacker/StringAccept.java
+++ b/src/main/java/com/blockwithme/msgpack/impl/accept/StringAccept.java
@@ -15,19 +15,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.unpacker;
+package com.blockwithme.msgpack.impl.accept;
import java.io.IOException;
import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
-import org.msgpack.MessageTypeException;
-final class StringAccept extends Accept {
- String value;
- private CharsetDecoder decoder;
+import com.blockwithme.msgpack.MessageTypeException;
+
+/**
+ * Part of the original low-level Message-Pack Java implementation.
+ *
+ * @author monster
+ */
+public final class StringAccept extends Accept {
+ public String value;
+ private final CharsetDecoder decoder;
public StringAccept() {
this.decoder = Charset.forName("UTF-8").newDecoder()
@@ -36,24 +42,25 @@ public StringAccept() {
}
@Override
- void acceptRaw(byte[] raw) {
+ public void acceptRaw(final byte[] raw) {
try {
this.value = decoder.decode(ByteBuffer.wrap(raw)).toString();
- } catch (CharacterCodingException ex) {
+ } catch (final CharacterCodingException ex) {
throw new MessageTypeException(ex);
}
}
@Override
- void acceptEmptyRaw() {
+ public void acceptEmptyRaw() {
this.value = "";
}
@Override
- public void refer(ByteBuffer bb, boolean gift) throws IOException {
+ public void refer(final ByteBuffer bb, final boolean gift)
+ throws IOException {
try {
this.value = decoder.decode(bb).toString();
- } catch (CharacterCodingException ex) {
+ } catch (final CharacterCodingException ex) {
throw new MessageTypeException(ex);
}
}
diff --git a/src/main/java/com/blockwithme/msgpack/schema/BasicSchemaManager.java b/src/main/java/com/blockwithme/msgpack/schema/BasicSchemaManager.java
new file mode 100644
index 000000000..db558d028
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/schema/BasicSchemaManager.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack.schema;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import com.blockwithme.msgpack.templates.Template;
+
+/**
+ * BasicSchemaManager assumes templates never get change ID.
+ *
+ * @author monster
+ */
+public abstract class BasicSchemaManager extends SchemaManagerBase {
+
+ /** The user templates */
+ private final Template>[] userTemplates;
+
+ /** Creates a BasicSchemaManager */
+ protected BasicSchemaManager(final Template>[] theUserTemplates) {
+ userTemplates = Objects.requireNonNull(theUserTemplates);
+ }
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.schema.SchemaManagerBase#createSchema(int, int)
+ */
+ @Override
+ protected Schema createSchema(final int format, final int schemaID) {
+ final List> list = new ArrayList>(
+ userTemplates.length);
+ int lastNotNull = 0;
+ for (int i = 0; i < userTemplates.length; i++) {
+ if (userTemplates[i].isSchemaSupported(schemaID)) {
+ list.add(userTemplates[i]);
+ lastNotNull = i;
+ } else {
+ list.add(null);
+ }
+ }
+ while (list.size() > lastNotNull + 1) {
+ list.remove(list.size() - 1);
+ }
+ return createSchema(format, schemaID,
+ list.toArray(new Template>[list.size()]),
+ getBasicTemplateCount(schemaID));
+ }
+
+ /** Returns the basicTemplates count, for the given schema. */
+ protected abstract int getBasicTemplateCount(final int schemaID);
+}
diff --git a/src/main/java/com/blockwithme/msgpack/schema/Schema.java b/src/main/java/com/blockwithme/msgpack/schema/Schema.java
new file mode 100644
index 000000000..1e16a3814
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/schema/Schema.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack.schema;
+
+import java.util.Map;
+
+import com.blockwithme.msgpack.templates.BasicTemplates;
+import com.blockwithme.msgpack.templates.Template;
+
+/**
+ * Represents a serialisation schema.
+ *
+ * TODO toString ...
+ *
+ * @author monster
+ */
+public class Schema {
+
+ /** The current format version. */
+ public static final int FORMAT = 0;
+
+ /** The format version for the current (de)serialisation. */
+ public final int format;
+
+ /** The schema version for the current (de)serialisation. */
+ public final int schema;
+
+ /** The basic templates. */
+ public final BasicTemplates basicTemplates;
+
+ /** Maps IDs to Class templates */
+ public final Template>[] idToTemplate;
+
+ /** Maps Class to Template. */
+ public final Map, Template>> classToTemplate;
+
+ /** The "fallback" (catch-all) templates */
+ public final Template>[] fallbackTemplates;
+
+ /** Constructor */
+ public Schema(final int theFormat, final int theSchema,
+ final BasicTemplates theBasicTemplates,
+ final Template>[] theIdToTemplate,
+ final Map, Template>> theClassToTemplate,
+ final Template>[] theFallbackTemplates) {
+ format = theFormat;
+ schema = theSchema;
+ basicTemplates = theBasicTemplates;
+ idToTemplate = theIdToTemplate;
+ classToTemplate = theClassToTemplate;
+ fallbackTemplates = theFallbackTemplates;
+ }
+
+}
diff --git a/src/main/java/com/blockwithme/msgpack/schema/SchemaManager.java b/src/main/java/com/blockwithme/msgpack/schema/SchemaManager.java
new file mode 100644
index 000000000..b0ba04ef9
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/schema/SchemaManager.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack.schema;
+
+/**
+ * SchemaManager creates and cache schemas.
+ *
+ * @author monster
+ */
+public interface SchemaManager {
+ /** Returns a schema for the given schema in. */
+ Schema getSchema(final int format, final int schema);
+}
diff --git a/src/main/java/com/blockwithme/msgpack/schema/SchemaManagerBase.java b/src/main/java/com/blockwithme/msgpack/schema/SchemaManagerBase.java
new file mode 100644
index 000000000..7bc46bc75
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/schema/SchemaManagerBase.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack.schema;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import com.blockwithme.msgpack.templates.BasicTemplates;
+import com.blockwithme.msgpack.templates.Template;
+import com.blockwithme.msgpack.templates._Template;
+
+/**
+ * Base implementation of SchemaManager.
+ *
+ * @author monster
+ */
+public abstract class SchemaManagerBase implements SchemaManager {
+
+ /** Map ID to schema. */
+ private final Map schemas = new HashMap();
+
+ /* (non-Javadoc)
+ * @see com.blockwithme.msgpack.schema.SchemaManager#getSchema(int)
+ */
+ @Override
+ public final Schema getSchema(final int format, final int schemaID) {
+ if (format < 0) {
+ throw new IllegalArgumentException("format: " + format);
+ }
+ if (schemaID < 1) {
+ throw new IllegalArgumentException("schemaID: " + schemaID);
+ }
+ final Integer key = schemaID;
+ Schema result;
+ synchronized (schemas) {
+ result = schemas.get(key);
+ if (result == null) {
+ result = createSchema(format, schemaID);
+ schemas.put(key, result);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates and returns a new schema, given the user templates, and the
+ * number of basic templates.
+ *
+ * @param schemaID
+ * @return
+ */
+ protected final Schema createSchema(final int format, final int schemaID,
+ final Template>[] userTemplates, final int basicTemplateCount) {
+ final BasicTemplates basicTemplates = new BasicTemplates();
+ final Map, Template>> classToTemplate = new HashMap, Template>>();
+ final Template>[] bt = basicTemplates
+ .getBasicTemplates(basicTemplateCount);
+ final Template>[] idToTemplate = new Template>[bt.length
+ + userTemplates.length];
+ System.arraycopy(bt, 0, idToTemplate, 0, bt.length);
+ System.arraycopy(userTemplates, 0, idToTemplate, bt.length,
+ userTemplates.length);
+ for (int i = 0; i < idToTemplate.length; i++) {
+ final Template> template = idToTemplate[i];
+ if (template != null) {
+ Objects.requireNonNull(template.getType(), "idToTemplate[" + i
+ + "].getType()");
+ ((_Template) template).setID(i);
+ if (template.isMainTemplate()
+ && classToTemplate.put(template.getType(), template) != null) {
+ throw new IllegalArgumentException(
+ "Multiple main templates for " + template.getType());
+ }
+ }
+ }
+ final List> fallBack = new ArrayList>();
+ for (int i = 0; i < idToTemplate.length; i++) {
+ if (idToTemplate[i].isFallBackTemplate()) {
+ fallBack.add(idToTemplate[i]);
+ }
+ }
+ final Template>[] fallbackTemplates = fallBack
+ .toArray(new Template>[fallBack.size()]);
+ final Schema result = new Schema(format, schemaID, basicTemplates,
+ idToTemplate, classToTemplate, fallbackTemplates);
+ for (int i = 0; i < idToTemplate.length; i++) {
+ ((_Template) idToTemplate[i]).resolve(result);
+ }
+ return result;
+ }
+
+ /**
+ * Creates and returns a new schema.
+ *
+ * @param format
+ * @param schemaID
+ * @return
+ */
+ protected abstract Schema createSchema(final int format, final int schemaID);
+
+}
diff --git a/src/main/java/com/blockwithme/msgpack/templates/AbstractTemplate.java b/src/main/java/com/blockwithme/msgpack/templates/AbstractTemplate.java
new file mode 100644
index 000000000..390f3ffd8
--- /dev/null
+++ b/src/main/java/com/blockwithme/msgpack/templates/AbstractTemplate.java
@@ -0,0 +1,806 @@
+/*
+ * Copyright (C) 2013 Sebastien Diot.
+ *
+ * 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 com.blockwithme.msgpack.templates;
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Objects;
+
+import com.blockwithme.msgpack.ObjectPacker;
+import com.blockwithme.msgpack.Packer;
+import com.blockwithme.msgpack.Unpacker;
+import com.blockwithme.msgpack.ValueType;
+import com.blockwithme.msgpack.schema.Schema;
+
+/**
+ * Object template, for anything beyond primitive types.
+ *
+ * All the code related to serializing Java Objects, as opposed to just data,
+ * is located here. This part is not based on the original MessagePack
+ * implementation. It makes a strong assumption, that the complete schema is
+ * known at de-serialization.
+ *
+ * @author monster
+ */
+public abstract class AbstractTemplate implements Template, _Template,
+ Cloneable {
+
+ /** The ClassNameConverter */
+ private static volatile ClassNameConverter CLASS_NAME_CONVERTER = new DefaultClassNameConverter();
+
+ /** The template ID (should not be negative). */
+ protected int id = -1;
+
+ /** The type that is supported. */
+ protected final Class type;
+
+ /** The template name. The Main template has the name of the type. */
+ protected final String name;
+
+ /** First schema introduction. */
+ protected final int firstSchemaIntroduction;
+
+ /** The 1D array type that is supported. */
+ protected final Class type1D;
+
+ /** The 2D array type that is supported. */
+ protected final Class type2D;
+
+ /** Is this the "main" template for this type, or an "alternate" template? */
+ protected final boolean mainTemplate;
+
+ /** Is this the "fallback" (catch-all) template for this type? */
+ protected final boolean isFallBackTemplate;
+
+ /** True if the type is final, or a primitive array. */
+ protected final boolean isFinalOrPrimitiveArray;
+
+ /**
+ * Most objects must be stored in "containers" (list or map). What is the
+ * format that should be used for this type? List is the default/usual.
+ */
+ protected final ObjectType objectType;
+
+ /** Returns the TrackingType of instances of this type. */
+ protected final TrackingType trackingType;
+
+ /** A non-negative value, if this type has a "fixed size" */
+ protected final int fixedSize;
+
+ /** Sets the ClassNameConverter; required for multi-version support in OSGi. */
+ public static void setClassNameConverter(final ClassNameConverter cnc) {
+ CLASS_NAME_CONVERTER = Objects.requireNonNull(cnc);
+ }
+
+ /** Returns the ClassNameConverter. */
+ public static ClassNameConverter getClassNameConverter() {
+ return CLASS_NAME_CONVERTER;
+ }
+
+ /** Reads any Object. We assume the template is valid. */
+ private static T readNewNonNullObject(final UnpackerContext context,
+ final Template template, final int size) throws IOException {
+ final ArrayList